UIStackView behaviour of disambiguating multi-line label width is confusing

Originator:argentumko
Number:rdar://41192642 Date Originated:17 June 2018
Status:Open Resolved:
Product:iOS + SDK Product Version:9.0+
Classification:UI/Usability Reproducible:Always
 
Summary:
Adding a multi-line UILabel as an arranged subview in a horizontal stack view with "fill" distribution causes the stack view to add an undocumented "UISV-text-width-disambiguation" constraint on that label. This constraint is present regardless of whether the layout is *actually* ambiguous or not: for example, if the other view in the stack view is a single-line label with both content hugging and compression resistance priorities *higher* than the multi-line label's, layout can be evaluated unambiguously even without this constraint, which can be tested experimentally by implementing a trivial layout that stacks these two labels horizontally.

Internally, "UISV-text-width-disambiguation" constraint is "width = SV_width * 1/N + C @(CRP+10)" (where SV_width is stack view's width, N is number of arranged subviews in it, C is a constant calculated based on stack view spacing, and CRP is label's compression resistance priority). Because of this, the resulting layout often doesn't match the expected one, which confuses the developer of client code, and requires them to be aware of this constraint and know how to counteract it using higher priorities in other views or by applying extra constraints. This is of course suboptimal as it diminishes stack view's usability and predictability.

Steps to Reproduce:
In a storyboard of a new project, create a horizontal stack view with default configuration (i.e. fill distribution) with two labels: one multi-line with long text, another – single-line with short text. Keep default hugging/compression priorities on the multi-line label, but increase those of single-line label (e.g. to 300/800) to make these two labels laid out unambiguously.
Constraint this stack view to superview's leading/trailing/top edges, and keep it unconstrained vertically, so that it auto-sizes to hug content.

Expected Results:
At runtime, single-line label hugs its content horizontally, and multi-line label fills the remaining horizontal space. Stack view grows and shrinks vertically to fit both labels. This matches a result one could get by implementing simple horizontal constraint-based stacking manually.

Actual Results:
Both labels occupy half of the stack view's width, which is unexpected and confusing.

Version/Build:
All iOS versions since 9.x; reproducible in iOS 12 beta 1.

Configuration:
Any device or simulator.

Additional Notes:
The attached sample project demonstrates the issue. It displays additional labels to annotate the observed behaviour, potential workarounds, and debug description of the disambiguation constraint.

Understandably, the described behaviour may be expected – at least in certain cases – but for those some additional documentation would be welcome. Because of its absence, some developers tend to implement hacky workarounds or stop using UIStackView altogether.

This issue together with the sample project has been shown to an Apple engineer at WWDC labs – and I've been asked to file this radar.

Comments

The issue is still here XCode 10.2, iOS 12.2

By uni.nova.tih at April 28, 2019, 6:40 p.m. (reply...)

Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!