3

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.

Giorgio
  • 1,973
  • 4
  • 36
  • 51
Isuru
  • 30,617
  • 60
  • 187
  • 303

3 Answers3

0

Try to have an outlet for the top constraint for the label 1. And when you remove the label 2, update the top constraint for the label1 which is the container.height/2 Or Remove the top constraint and give the centerY constraint to the label 1. And do layout if needed, once you updated the constraints.

Teja Nandamuri
  • 11,045
  • 6
  • 57
  • 109
0

I am pretty much impressed the way you came so far as that would have been exactly the same steps i would have followed if i had to accomplish it :)

Now my suggestion: remove an extra "Align center to Y with the value of 0 to Label 1" that you have added that is not serving any purpose :)

I can see you already have a align center to y with some offset i believe -13 to label 1. Create an iboutlet for that :) let's say its name as centerLabel1Constraint :)

whenever you want to bring label 1 to center hide label 2 and set centerLabel1Constraint.constant = 0 and call [cell layoutIfNeeded]

That should do the job :) Happy coding :)

Sandeep Bhandari
  • 19,999
  • 5
  • 45
  • 78
  • Thanks for the response. I tried this. It works but only partially. The problem is there's no way to determine the value for the constant for cells that do have Label 2 because once you set it to 0, it gets reused when the cells are reused. – Isuru Dec 22 '15 at 17:07
  • you already know the constant value right??? I mean when you want to show label2 simply make it visible and set the value of centerLabel1Constraint.constant back to -13 and call [cell layoutifneeded] – Sandeep Bhandari Dec 22 '15 at 17:09
  • In summary: your cell for row at indexpath looks like if(condition:show label2){centerLabel1Constraint.constant=-13; label2.Hidden=NO; [cell layoutIfNeeded]} else{{centerLabel1Constraint.constant=0;label2.Hidden=YES; [cell layoutIfNeeded]} Isn't it???? :) – Sandeep Bhandari Dec 22 '15 at 17:12
  • The thing is I'm not comfortable hardcoding the value -13. Because these are cells are self-resizing ones. Anyway I figured out a way to do this. I posted it [below](http://stackoverflow.com/a/34421192/1077789). Thanks for the help. – Isuru Dec 22 '15 at 17:20
  • hardcoding -13 will not make any difference buddy :) because it is always subtracted from the center to y value which gets calculated dynamically based on the heights of the cell :) So no matter what is the size of your cell it will always be shown 13 pixel above the vertically centered line :) thats the purpose apple has provided that constant concept :) anyway glad that you found your solution :) – Sandeep Bhandari Dec 22 '15 at 17:24
0

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

Community
  • 1
  • 1
Isuru
  • 30,617
  • 60
  • 187
  • 303
  • I still dont think this is a best solution to this. Since label has intrinsic size there should be a way to achive this only by setting label text to nil. Will check that tomorrow and come with an answer – Zell B. Dec 22 '15 at 19:15