Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding labels programmatically, aligned with labels from Storyboard

Desired View:

enter image description here

In Storyboard I have two labels with the blue background that I am creating in Autolayout. Their position will never change. Next, I would like to add anywhere from 1 to 10 labels in code in cellForRowAtIndexPath below the blue background labels.

I am struggling to align the the labels added in code (brown background) with the ones created in Autolayout (blue background).

Below is my failed attempt:

enter image description here

Two approaches that failed:

  1. In cellForRowAtIndexPath get the frame of "B AutoLayout Static Label" and use the X position for Dynamic Labels. Did not work.

  2. Adding constraints also did not work -- perhaps I am not adding the constraints correctly.

Here is the code:

class TableViewController: UITableViewController {

    var cellHeight = [Int: CGFloat]()

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.estimatedRowHeight = 85.0
        self.tableView.rowHeight = UITableViewAutomaticDimension
    }

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 4
    }


    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {


        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomCell
        let xLocation = cell.labelBStatic.frame.origin.x
        var yLocation = cell.labelBStatic.frame.origin.y
        let height = cell.labelBStatic.frame.size.height

        var startYLocation = yLocation + height + 20
        var i = 0
        if indexPath.row % 2 == 0 {
            i = 5
        } else {
            i = 7
        }

        while i < 10 {
            let aLabel = UILabel()
            aLabel.backgroundColor = UIColor.orangeColor()
            aLabel.text = "Label # \(i)"
            cell.contentView.addSubview(aLabel)
            addConstraints(aLabel, verticalSpacing: startYLocation)
            startYLocation += 20
            i++
        }

        print(startYLocation)
        cellHeight[indexPath.row] = startYLocation
        return cell
    }

    func addConstraints(labelView: UILabel, verticalSpacing: CGFloat) {
        // set Autoresizing Mask to false
        labelView.translatesAutoresizingMaskIntoConstraints = false

        //make dictionary for views
        let viewsDictionary = ["view1": labelView]

        //sizing constraints
        let view1_constraint_H:Array = NSLayoutConstraint.constraintsWithVisualFormat("H:[view1(>=50)]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDictionary)

        labelView.addConstraints(view1_constraint_H)

        //position constraints
        let view_constraint_H:NSArray = NSLayoutConstraint.constraintsWithVisualFormat("H:|-15-[view1]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: viewsDictionary)
        let view_constraint_V:NSArray = NSLayoutConstraint.constraintsWithVisualFormat("V:|-\(verticalSpacing)-[view1]", options: NSLayoutFormatOptions.AlignAllLeading, metrics: nil, views: viewsDictionary)

        view.addConstraints(view_constraint_H as! [NSLayoutConstraint])
        view.addConstraints(view_constraint_V as! [NSLayoutConstraint])

    }

        override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {

        if let height = cellHeight[indexPath.row] {
            return height
        }
        return 0
    }

Below is the Storyboard setup (Both labels are centered horizontally):

enter image description here

Question: How can I get my dynamic labels that I am creating in cellForRowAtIndexPath left align with my static labels that were created in Storyboard to match my desired view on top?

like image 332
user1107173 Avatar asked Sep 25 '22 03:09

user1107173


1 Answers

Just for demonstration purpose i have added one label programatically, you can add as much as labels you want, just add the constraints properly, also you need to add bottomSpace constraint to the last label inside cell so that your cell will auto resize as per the label height.

Follow the steps i have done to achieve what you want:

  1. Access the B AutoLayout Static Label in cellForRowAtIndexPath: using tag or outlet if you have subclassed UITableViewCell and have created outlet.

    let labelBAutolayoutStaticLabel = cell?.viewWithTag(20)
    
  2. Create the label programatically as below and set translatesAutoresizingMaskIntoConstraints to false,

    let labelDynamicLabel = UILabel()
    labelDynamicLabel.backgroundColor = UIColor.orangeColor()
    labelDynamicLabel.text = "A Dynamic Label"
    labelDynamicLabel.translatesAutoresizingMaskIntoConstraints = false
    cell?.contentView.addSubview(labelDynamicLabel)
    
  3. You need to create two constraint, one is for TopSpace and second is LeadingSpace as below,

    let leadingSpaceConstraint: NSLayoutConstraint = NSLayoutConstraint(item: labelDynamicLabel, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: labelBAutolayoutStaticLabel, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0);
    
    let topSpaceConstraint: NSLayoutConstraint = NSLayoutConstraint(item: labelDynamicLabel, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: labelBAutolayoutStaticLabel, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 10); //Constant is the spacing between
    
  4. Add constraint to your cell's contentView as below,

    cell?.contentView.addConstraint(leadingSpaceConstraint)
    cell?.contentView.addConstraint(topSpaceConstraint)
    

That's it.

And here is the result,

enter image description here

Here is the full code for cellForRowAtIndexPath:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
    let cell = tableView.dequeueReusableCellWithIdentifier("cell")

    let labelBAutolayoutStaticLabel = cell?.viewWithTag(20)


    let labelDynamicLabel = UILabel()
    labelDynamicLabel.backgroundColor = UIColor.orangeColor()
    labelDynamicLabel.text = "A Dynamic Label"
    labelDynamicLabel.translatesAutoresizingMaskIntoConstraints = false
    cell?.contentView.addSubview(labelDynamicLabel)

    let leadingSpaceConstraint: NSLayoutConstraint = NSLayoutConstraint(item: labelDynamicLabel, attribute: NSLayoutAttribute.Leading, relatedBy: NSLayoutRelation.Equal, toItem: labelBAutolayoutStaticLabel, attribute: NSLayoutAttribute.Leading, multiplier: 1, constant: 0);

    let topSpaceConstraint: NSLayoutConstraint = NSLayoutConstraint(item: labelDynamicLabel, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: labelBAutolayoutStaticLabel, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 10);

    cell?.contentView.addConstraint(leadingSpaceConstraint)
    cell?.contentView.addConstraint(topSpaceConstraint)

    return cell!
}

Edit/Update:

If you have to set bottomSpace constraint to the last label (label which is at bottom of cell), there are two way

  1. Use NSLayoutConstraint as below:

    let bottomSpaceConstraint: NSLayoutConstraint = NSLayoutConstraint(item: labelDynamicLabel, attribute: NSLayoutAttribute.BottomMargin, relatedBy: NSLayoutRelation.Equal, toItem: cell.contentView, attribute: NSLayoutAttribute.BottomMargin, multiplier: 1, constant: -8)
    
    cell.contentView.addConstraint(bottomSpaceConstraint)
    
  2. Using Visual Format Language as below,

    let views = ["cell": cell, "labelDynamicLabel": labelDynamicLabel, "labelBAutolayoutStaticLabel": labelBAutolayoutStaticLabel]
    
    let verticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat("V:[labelBAutolayoutStaticLabel]-[labelDynamicLabel]-|", options: [], metrics: nil, views: views)
    
    cell.contentView.addConstraints(verticalConstraints)
    

If you set constraint using VFL make sure you remove topSpaceConstraint

//cell.contentView.addConstraint(topSpaceConstraint)

What this "V:[labelBAutolayoutStaticLabel]-[labelDynamicLabel]-|" string mean is,

  1. labelDynamicLabel should have TopSpace to labelBAutolayoutStaticLabel with standardSpacing (8pts) and labelDynamicLabel should have bottom space to SuperView with standardSpacing. ('-|' indicates the standard space to superView)
like image 167
Bharat Modi Avatar answered Sep 29 '22 07:09

Bharat Modi