Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix measurement of Row and Column on iOS inside of UIStackView #2426

Merged
merged 3 commits into from
Nov 5, 2024

Conversation

squarejesse
Copy link
Contributor

UIStackView uses UIView.intrinsicContentSize on its subviews, but our Row and Column implementations don't have a natural implementation of this API. In particular, if any subview wraps its contents (so its height depends on its available width), there's no single intrinsicContentSize().

We work around this by following some online advice: invalidate the intrinsic size when the bounds change, and then use those bounds when computing the new intrinsic size.

This is more fragile and stateful than I'd like, but it seems like a common practice for working around UIStackView's API.


  • CHANGELOG.md's "Unreleased" section has been updated, if applicable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More ComposeUI layouts that are broken. This is a problem, but it’s not new and it’s not urgent.

this.alignment = UIStackViewAlignmentLeading
this.distribution = UIStackViewDistributionFill
this.alignment = UIStackViewAlignmentFill
this.distribution = UIStackViewDistributionEqualSpacing
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had better luck with these ones

@@ -144,8 +144,8 @@ class UIViewScrollWrapper : ScrollWrapper<UIView> {
scrollView.addSubview(value)
value.translatesAutoresizingMaskIntoConstraints = false
value.leadingAnchor.constraintEqualToAnchor(scrollView.leadingAnchor).active = true
value.widthAnchor.constraintEqualToAnchor(scrollView.widthAnchor).active = true
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s way too cute, but UIScrollView scrolls horizontally if you bind leading and trailing, but doesn’t scroll horizontally if you bind leading and width.

override fun invalidateIntrinsicContentSize() {
super.invalidateIntrinsicContentSize()
this.widthForIntrinsicSize = UIViewNoIntrinsicMetric
this.heightForIntrinsicSize = UIViewNoIntrinsicMetric
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t have a test case to prove that this override is necessary. I might try to make one? That might be tricky

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without the fix, this thing’s intrinsicContentSize is is 10,000 pixels wide and 20 pixels tall

testIntrinsicContentSizeWhenSubviewsRequireScrolling 1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, without the fix each subview is super wide and not very tall

testIntrinsicContentSizeWhenSubviewsWrap 1

Copy link
Collaborator

@edahle edahle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥 🔥

@swankjesse swankjesse force-pushed the jwilson.1104.intrinsicSize branch from a77d94a to c3828da Compare November 4, 2024 19:50
@swankjesse swankjesse force-pushed the jwilson.1031.test_redwood_view_measurement branch from d861e69 to 483577f Compare November 4, 2024 19:51
@swankjesse swankjesse force-pushed the jwilson.1104.intrinsicSize branch from c3828da to 0aa3561 Compare November 4, 2024 19:52
* We work around this by:
*
* 1. Making [intrinsicContentSize] depend on the mostly-recently applied bounds
* 2. Invalidating it each time the bounds change
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This work around sounds good to me, though @edahle do you know how a UITextView and other views that depend on knowing the width to compute the height provide a reasonable intrinsicContentSize? Maybe private APIs of some kind?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UILabel has a feature called preferredMaxLayoutWidth that you can use for this.

Copy link
Member

@colinrtwhite colinrtwhite left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing this! 🙏🏻

Base automatically changed from jwilson.1031.test_redwood_view_measurement to trunk November 4, 2024 22:18
UIStackView uses UIView.intrinsicContentSize on its subviews, but
our Row and Column implementations don't have a natural implementation
of this API. In particular, if any subview wraps its contents (so
its height depends on its available width), there's no single
intrinsicContentSize().

We work around this by following some online advice: invalidate
the intrinsic size when the bounds change, and then use those
bounds when computing the new intrinsic size.

This is more fragile and stateful than I'd like, but it seems
like a common practice for working around UIStackView's API.
@swankjesse swankjesse force-pushed the jwilson.1104.intrinsicSize branch from 0aa3561 to 581c732 Compare November 4, 2024 22:19
@squarejesse squarejesse enabled auto-merge (squash) November 4, 2024 22:19
@squarejesse squarejesse merged commit ce50409 into trunk Nov 5, 2024
11 checks passed
@squarejesse squarejesse deleted the jwilson.1104.intrinsicSize branch November 5, 2024 01:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants