Why custom views in stack view are overlapping?
Asked Answered
G

2

7

I'm trying to create a stack view with custom views inside. Each custom view in this example has the same information. For some reason instead of going each after each the subviews are overlapping and I can't figure out why. I don't have any constraints (in the layout). The stack view is inside scroll view because there may be many subviews.

The code of custom view:

import UIKit

class AddressComponentView: UIView {

    @IBOutlet weak var labelStreet: UILabel!
@IBOutlet weak var labelCity: UILabel!
@IBOutlet weak var labelOfficialRegionType: UILabel!
@IBOutlet weak var labelOfficialRegionTitle: UILabel!
@IBOutlet weak var labelCountry: UILabel!
@IBOutlet weak var labelZip: UILabel!

var view: UIView!

func loadData(address: AddressData){
    self.labelStreet.text = address.street
    self.labelCity.text = address.city
    self.labelOfficialRegionType.text = address.region?.officialRegionType
    self.labelOfficialRegionTitle.text = address.region?.officialRegionTitle
    self.labelZip.text = address.zip
    self.labelStreet.sizeToFit()
}

override init(frame: CGRect) {
    super.init(frame: frame)
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

}

Here is how I dynamically add subviews (viewContent is stack view):

viewScroll.contentSize = CGSize(width: 320, height: 1000)

            let viewsDictionary = ["stackView":viewContent]
            let stackView_H = NSLayoutConstraint.constraints(
                withVisualFormat: "H:|-20-[stackView]-20-|",  //horizontal constraint 20 points from left and right side
                options: NSLayoutFormatOptions(rawValue: 0),
                metrics: nil,
                views: viewsDictionary)
            let stackView_V = NSLayoutConstraint.constraints(
                withVisualFormat: "V:|-30-[stackView]-30-|", //vertical constraint 30 points from top and bottom
                options: NSLayoutFormatOptions(rawValue:0),
                metrics: nil,
                views: viewsDictionary)
            view.addConstraints(stackView_H)
            view.addConstraints(stackView_V)


let addressView = UINib(nibName: "AddressComponent", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! AddressComponentView

addressView.loadData(address: (item?.addressData)!)
viewContent.addArrangedSubview(addressView)

let addressView1 = UINib(nibName: "AddressComponent", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! AddressComponentView

addressView1.loadData(address: (item?.addressData)!) viewContent.addArrangedSubview(addressView1)

And here is awful result:

crap

That's what happened if I add 30 subviews:

enter image description here

That's what happened if I add 30 subviews:

Another thing that is very strange is the fact that I make the background custom view blue, and set it opaque and these properties are being ignored for some reason. That is how the component looks in the design time: Now I'm trying to add these subviews into Prototype cell of UITableView:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    if indexPath.row == 3 || indexPath.row == 7 {
        var text = "Run the app again, and it will look nothing has really changed. You are now using your bioLabel, but it’s just showing one line of text in each cell. Even though the number of lines is set to 0 and your constraints are properly configured so your bioLabel takes up"

        let customView1 = UINib(nibName: "CustomView1", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! CustomView1
        customView1.frame = CGRect(x:0, y:0, width: 200, height: 60)
        customView1.loadData(text: text)
        cell.container.addSubview(customView1)
    } else {
        let customView2 = UINib(nibName: "CustomView2", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! CustomView2

        customView2.loadData(text: "aaaaa adfsd")
        cell.container.addSubview(customView2)

    }

    // Configure the cell...

    return cell
}

This code is very stupid, I just experimented with different views (I created 2 custom views). Both of them have approx same code:

class CustomView1: UIView {

@IBOutlet weak var label1: UILabel!

func loadData(text: String){
    label1.text = text
}
override init(frame: CGRect) {
    super.init(frame: frame)
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

}

NB cell.container is the view that I put into Prototype cell.

Glare answered 10/12, 2016 at 5:54 Comment(2)
Can you post how result would be if you put 3-4 AddressComponent, maybe it it is going over stack view bounds, maybe you have to have constraint for AddressComponent height so that stack view could now how big it row should be.Preciosa
@Markicevic, thanks for your response. I added more pictures into my post. Sorry for mess with comments there, I couldn't figure out how to put them properly but you now should be able to get the idea. I added 30 views.Glare
P
4

Problem is that UIStackView row does not know height of UIStackView, try to set height of that view or maybe change distribution property of UIStackView. Why are you now user UITableView for this, this looks like perfect example to use UITableView, than you would no need UIScrollView?

Preciosa answered 10/12, 2016 at 22:19 Comment(9)
if I set up the height of the stackview it doesn't show anything. I don't know maybe my choice of this container was wrong. From my understanding I needed some container that allows adding items one by one, but I didn't take into account that stackview probably always tries to distribute content evenly. The subviews I'm going to add are not equal by height at all and I don't know in advance which views will be added (it's based on the object's properties). Does UITableView allow adding non-equal items?Glare
Do some google-ing about uitableview and uicollectionview, i think you will find what you need in this tutorial.Preciosa
it looks like this dynamic table is exactly what I need. Thanks a lot (to be honest I googled much but probably I used the wrong keyword because I could not find anything). Thanks! NB I will check your answer as solution as soon as I'm done with this example, so pretty soon.Glare
Glad i could help 🙂Preciosa
Unfortunately it didn't work for so I created a new post where I explain my task completely #41108747Glare
It has to work, just follow steps in tutorial. Why can't you add data dinamicly to table view? Put your view controller class with table view here so i can look at it.Preciosa
Thanks for your help! What I'm trying to do is to created some custom views programmatically from xib and put them onto the parent view. When I tried with UITableView, I created a prototype cell and put the component called View there. Then in the code I load subviews from xib (see the update post).Glare
Please take a look at some tableview tutorial, what you do is on viewDidLoad register class(xib) for table view and that in cellForRowAt you do not create view from xib you reuse one from table view, that is a point of table view, to reuse cells and just to have different data, you can register more than one class(xib) for table view and then when reusing you pick witch one you want to reuse for that row. This is how you should do this, you just have to do some research on table view. :)Preciosa
Yahoo! Finally I made it work! What did wrong were: 1) I created a separate view instead of creating empty nib file and put cell right there 2) I loaded nib for separated cell instead of registering them in viewDidLoad and reuse after. The article that helped me is #25542286 (I used the approach, suggested by internet-nico)Glare
J
2

Try to override intrinsicContentSize of your custom view. The stack view will know then the height of arranged subview.

Jadwiga answered 6/10, 2020 at 18:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.