2

I've tried to get this to work but interface builder is doing my head in and I was wondering if anyone has a proper solution for this.

So I want to have a stackview that contains a label with multiple lines inside. The first hit on google (read here) tells you to embed the label within a view (A), then drag that view into another view (B) (because the embedded view (A) has a 20pixel pad) and then unembed the first view (A).... voila. Except this only tricks the stackview for horizontal stacks and if you continue to stack the view you will still have a ton of problems (I will demonstrate with screenshots later in the question).

I found another guide on google that criticizes a potential fix for the problem, fixing the stackviews width. The author makes the point that Apple didn't intend for you to be doing that, after all it's supposed to be auto layout, not fixed layout. This guide theorises that the issue is just a bug and that you can create a stackview with a single line label, set it all up and THEN add the multiple lines. I tried this and it didn't work, it simply messed the entire stack view up! The stack view will warp and essentially break unless the label has number of lines set to 1 and only 1. (Image 1) Stackview with label set to have multiple lines.

So I talked earlier about embedding the paragraph label within a view. This doesn't cause any errors in the storyboard,(Image 2) you can't really align the text properly with the other UIStacks but that's not an immediate problem for me to solve. What IS a problem is what happens at runtime.... Simulator, Portrait (Image 3), Simulator, Landscape (Image 4).

I tried running this on an actual device to see if it was just a simulator bug but the same thing happened on my iphone 6. Safe to say this is probably not going to work!

Oh and just before we go any further, I am building the stack views in the following way:

[name - placeholder]
[phone - placeholder]
[address - placeholder]
, setting a spacing of 8 and equal fill
,vertically stacking all of these stacks (3 into 1) and setting a spacing of 8
, vertically stacking the details titles with the big stack and 8 spacing
,finally adding the title and button into the stack view with a spacing of 32.

I then apply some storyboard constraints: in this case just centre vertically & horizontally, so the view is always centred and displays properly in both screen orientations.

Even though this isn't aligned properly, this is the view before applying the stacks and constraints, this is what I want my endgame to look like: Looks kind of silly, but I want to figure this out so I can actually stack my paragraphs! (Image - 5).

So now hopefully I've established that you can't really embed the label within a view as it doesn't render correctly at runtime, and you can't trick the stack into adding new lines.

How do I put a label with multiple lines into a stack view safely?

This is almost an offshoot question but when you try applying a stack to a paragraphed label, it sets the width of the label to be absolutely massive (sometimes it throws an error that interface builder can't render it Demonstrated here (Image 6). I've seen this happen a few times and don't really understand how xcode thinks that is a sensible option.

I don't want to apply fixed widths to my labels or stacks because I'll only be left with another warning, and warnings are bad!

I'm pretty lost at what to do, if anyone knows of a way this can be achieved I would be eternally grateful!

Thanks

Axemasta
  • 604
  • 8
  • 21
  • Looking at your image 5, why is this a case for a stack view at all? What you've shown is easy to achieve without one, so why even bother with a stack view? – matt Nov 01 '17 at 22:55
  • @matt mainly because this view has absolutely no autolayouts applied to it at all. The purposes of this question and the sample I have provided is to act as a demo of the concepts I want to implement. – Axemasta Nov 01 '17 at 22:56
  • @matt I could in theory just auto layout everything to the bounds of the screen, just using layout constraints.. But I really like sticking things into stack views because it seems to work better across different devices and requires less fiddling with constraints. Plus I think apple do want you be putting as much as you can into stack views (correct me if i'm wrong) – Axemasta Nov 01 '17 at 22:58
  • This is a bug. I have reported it as a radar to Apple and it was closed as a duplicate ticket. There are quite a few radars for the same thing. Add your own as it will help get this fixed. But yeah, stack views are generally broken in Interface Builder. One way is that it can’t display multi line labels. It works fine at runtime. But in interface builder it is broken. – Fogmeister Nov 01 '17 at 22:59
  • Incidentally. I much prefer creating stack views in code. It’s nice to practice too as you can create some really nice layouts and have to conceptualise them but also keep the code easy to read and maintain etc... – Fogmeister Nov 01 '17 at 23:00
  • @Axemasta I don't say you're wrong but I do say I don't see what real-world problem you're having, since the layout you show is easy to achieve, coherently, on different screen sizes, which is the ultimate goal. – matt Nov 01 '17 at 23:15
  • @Fogmeister ok thanks, I will raise it as an issue on radar. Hope apple eventually listen :D and I will give creating them in code a bash, anything to keep me away from interface builder! – Axemasta Nov 01 '17 at 23:19
  • @matt mainly just to practise my chops with interface builder. I actually hate the thing and would much prefer just specifying a view layout for every device and orientation individually. This way I am trying to teach myself everything to do with interface builder incase I need to use it in the future. What if I find myself doing a project where I do need this to work and I don't know how to fix it? I guess this is a case of me being me and wanting the answer to something I can't solve! – Axemasta Nov 01 '17 at 23:21
  • "mainly just to practise my chops with interface builder" What I'm suggesting you do _is_ Interface Builder. - Look: all a stack view does is generate constraints for you automatically. It does _nothing_ you can't do yourself, directly. So isn't it better for you to learn to do it yourself, directly? In Interface Builder? Using stack view is the _opposite_ of your claimed goals! – matt Nov 01 '17 at 23:47
  • @matt ok I see where you are coming from now. Im just very used to placing everything into stack views and then stacking those views stacks. Leaving me with one massive box I can add constraints too. I almost think I'm doing things wrong when Im adding constraints to everything individually, I'll do that on this, should work fine! – Axemasta Nov 02 '17 at 00:06

3 Answers3

2

While I do agree this is an issue in UIStackView as layouting should work according to the intrinsic size of the UILabel. When using stackview with multiline label, it is not able to update its size according to the label. For resolving this issue, use preferredMaxLayoutWidth property of the label and set it to any value.

label.preferredMaxLayoutWidth = 1

Note: This even worked for me when I set it to 1

The preferredMaxLayoutWidth property as defined in the Apple Docs:

This property affects the size of the label when layout constraints are applied to it. During layout, if the text extends beyond the width specified by this property, the additional text flows to one or more new lines, increasing the height of the label.

which we do want to increase for a vertical UIStackView.

1

This really seems to be a bug.

A workaround that works for me is embedding the multiline label in a view and leaving it there.

That fixes the layout on the Storyboard editor and also works in the simulator.

A weird thing is that if I have several multiline labels on the same StackView I only have to embed one of them in a UIView, and then all the other multiline labels will behave properly.

Felipe Ferri
  • 3,179
  • 1
  • 26
  • 37
0

the solution is about embedding the UILabel inside "view without inset". and then update your constraints.

Niib Fouda
  • 1,242
  • 13
  • 19