I got a ViewController with a bunch of Labels ordered in 2 columns (title and description values). All the Labels are children of the main View. I want the right column with the description Labels aligned vertically:

enter image description here

My first attempt:

I set a fixed width constraint width = 180 to each Label of the left column. Then each Label of the right column had a constraint to the corresponding Label to its left. This worked and looked fine, but I got this warning I wanted to get rid of:

Fixed width constraints may cause clipping

My second attempt:

Deleted all fixed width constraints of the left side Labels to get rid of the warning. Right side wasn't aligned anymore. In viewDidLoad() I tried setting all left side Labels' frame sizes to the size of the longest Label (in my case "Some long long text")

    shorterTitle.frame.size = longTitle.frame.size
    tinyTitle.frame.size = longTitle.frame.size

This didn't have any visible impact though (left constraints of the right Labels don't seem to be dynamic).

My third attempt:

I ignored the different sizes of the left side Labels but looked at those on the right. I check the x position the right side Label of the longest left side Label and set this position to all other right side Labels:

    secondDes.frame.origin.x = firstDes.frame.origin.x
    thirdDes.frame.origin.x = firstDes.frame.origin.x

This worked out fine but there's a problem to it:

This doesn't work if the value Labels are empty. In my app these are empty first and then the information of the right side Labels gets downloaded from a webserver.

So if I do this:

    secondDes.frame.origin.x = firstDes.frame.origin.x
    thirdDes.frame.origin.x = firstDes.frame.origin.x

    firstDes.text = "test1"
    secondDes.text = "test2"
    thirdDes.text = "test3"

the right side won't be aligned correctly.

So I changed the order so the text gets set first and therefore the Labels get a new width size depending on their new text.

    firstDes.text = "test1"
    secondDes.text = "test2"
    thirdDes.text = "test3"

    secondDes.frame.origin.x = firstDes.frame.origin.x
    thirdDes.frame.origin.x = firstDes.frame.origin.x

Surprisingly this doesn't work neither. The reason is: The text attributes are set but by the time the last 2 lines are executed the sizes of the Labels haven't adjusted yet. So I would have to wait a little bit for the sizes to be applied and then call the last two lines again.

If I did that the user would be able to see the text jump though.

Hope you guys have an idea.

3 Answers

1
Helge Becker On Best Solutions

Autolayout should be the best approach.
Regarding solution 1:
The UILabels firstDes, secondDes and thirdDes are looking like being horizontal centered. If you now enforce a width of 160 it will absolutely have overlapping/breaking constraints.
A iPhone 5s/LE will have a width of 320. If the "Some long long text:" label has a 180 width it will overlap the "test1" Label.

Normally its best to use an intrinsic approach. Let the control figure out how much room it need for its text.

If it is your first project I suggest you have a look on some tutorials for Autolayout. (Ray Wenderlich for instance)

Edit:
Suggestion from comments. Use a UIView as Container. Place all UILabels there and align them as u like. The UILabels "test2"and "test3"have LayoutContraints that tells them to have the same leading as "test1".
Image 2 shows the constraints you are looking in the StoryBoard editor. Adding them by code is less trivial if you are unfamiliar with Autolayout.

enter image description here enter image description here

0
Usama Azam On

If your data is static then you should use UIStackView. And if your data is dynamic then UICollectionView is better option. In that case you can create a single prototype cell containing your label and then use dequeueReusableCell to use that cell. I hope you get some idea if you have understanding of UICollectionView.

1
dahiya_boy On

How to set UI from 1st method


  1. In your VC take Horizontal-StackView first and give it some constraints. Right now I am giving it

    • Leading, trailing - 10 (constant)
    • Vertically center to the Vc view.
    • height - 200 (constant) .. later we will remove this
  2. First we will set first topmost view and then we will replicate same views.So now add a single view in your stackview. Its say its view1.

  3. Add left label (labelLeft) in view1 and give it constraint :

    • Leading, top, bottom - 5 (constant)
    • Width - 80 (constant) .. you can set as per your need
  4. Now set middle label (labelMid) for colon (if you do not wanted this then skip this step) and give constraint :

    • Leading to the labelLeft - 5 (constant)
    • Top to the labelLeft
  5. Now set rightLabel (labelRight) and give constaints :

    • Leading to the labelMid - 5 (constant)
    • Top to the labelLeft
    • Trailing - 5 (constant)
  6. Now set number of lines of each label as zero (0) and remove stackView Height constraint. Set text in labelLeft and labelRight whatever length you wanted to be and see the magic below.

Outputs :

First Output (Left label is longer)

enter image description here

Second Output (Right label is longer)

enter image description here

  1. For multiple views you can directly copy the view1 and paste it in the stackView like below.

enter image description here

Final Output:

enter image description here

Background purple colour is the main view.