Search code examples
iosswiftautolayoutuilabel

Dynamically move a view to a new position in auto layout


I have a custom UITableViewCell layout that looks like this. It has three labels.

enter image description here

Label 2 is an optional one. It's not present in every cell. So I want to hide that and move the Label 1 down a little to be center aligned with the Label 3 when that happens.

enter image description here

Here are the constraints I've added for each label.

Label 1

enter image description here

Label 2

enter image description here

Label 3

enter image description here

Notice I have added an extra constraint, Align center to Y with the value of 0 to Label 1 and have set its priority to 750. I figured if I remove the Label 2, that constraint with the lower priority will take its place and move down.

class TableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    // MARK: - Table view data source
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 3
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomCell

        if indexPath.row == 1 {
            cell.label2.removeFromSuperview()
            cell.updateConstraints()
        }

        return cell
    }
}

But it doesn't seem to work. Label 2 is removed but Label 1's position is still the same.

enter image description here

How can I accomplish what I'm after?


Attempt #1

As per Mr. T's answer below, I added a top constraint to the Label 1. And then in the cellForRowAtIndexPath method, I changed it's value.

override func tableView(tableView: UITableView, cellForRowAtIndexPath 

    indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomCell

        if indexPath.row == 1 {
            cell.label2.removeFromSuperview()
            cell.topConstraint.constant = cell.bounds.height / 2
            cell.layoutIfNeeded()
        }

        return cell
    }

But this didn't work either.


Solution

  • I figured out a way to do this utilizing the new active property of NSLayoutConstraints as described in this answer.

    I made an IBOutlet to the Align center Y constraint with the value -13. Removed the weak keyword from it.

    Then in the cellForRowAtIndexPath method, I'm simply toggling the value for the active property.

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomCell
    
        if indexPath.row % 2 == 0 {
            cell.label2.hidden = true
            cell.oldConstraint.active = false
        } else {
            cell.label2.hidden = false
            cell.oldConstraint.active = true
        }
    
        return cell
    }
    

    enter image description here