UIViewRepresentable doesn't respect intrinsicContentSize invalidation
This is a quick write-up of an unexpected SwiftUI limitation I encountered recently. In my own searching, I couldn’t find it documented anywhere so I’m hoping this post will help someone in the future.
Problem summary
You can’t wrap a UIView
in SwiftUI’s UIViewRepresentable
if that UIView
changes its intrinsicContentSize
based in its frame
width, because UIViewRepresentable
will ignore invalidateIntrinsicContentSize()
. As a result, the UIView
will have its height clipped.
To make it a bit more concrete, imagine you have a UIView
that draws multiline text that can line wrap. UILabel
would be an example. If you were to adjust the label’s frame
width, it would reflow the text and the intrinsic content height would change to reflect that.
During SwiftUI layout, what UIViewRepresentable
does is ask the UIView
for its intrinsic content size before it has set the UIView
‘s frame. It then takes the minimum of the available size from the superview and the UIView
‘s intrinsicContentSize
, and sets that as the UIView
‘s frame
. This causes the UIView
to reflow the text and invalidate its intrinsic content size. UIViewRepresentable
ignores this, and as a result the UIView
is clipped too short.
You can find a simplified version of this bug using UILabel on Github.
Investigation
I tried many suggestions from Stack Overflow, and override any size or layout related UIView
method that I could. None of the suggestions worked, and almost none of the UIView
methods were ever called during layout. I felt I was probably missing something obvious, so I filed a Developer Tech Support incident with Apple to get an official answer. My submission is summarized in the Github repo.
Results
Here’s the official response from Apple:
Hello Andy,
Thank you for contacting Apple Developer Technical Support (DTS). We have reviewed your request and have concluded that there is no supported way to achieve the desired functionality given the currently shipping system configurations.
If you would like for Apple to consider adding support for such features in the future, please submit an enhancement request via Feedback Assistant (https://feedbackassistant.apple.com). For more information on Feedback Assistant, please visit https://developer.apple.com/bug-reporting/.
While a Technical Support Incident (TSI) was initially debited from your Apple Developer Program account for this request, we have assigned a replacement incident back to your account.
Best Regards,
Developer Technical Support
Worldwide Developer Relations
Apple, Inc.
According to the response this is expected behavior, so any change would an enhancement request. I have since filed the enhancement request as feedback FB8499811
.
Moment of Zen
I have the exact same view on macOS as an NSView
wrapped up in an NSViewRepresentable
. It works great. When the NSView
invalidates its intrinsic size, NSViewRepresentable
re-queries the intrinsic size and updates the frame
appropriately.
I guess someone already filed that enhancement request.