Anyone run in to following issue when trying to in...
# compose-ios
j
Anyone run in to following issue when trying to include a UIViewControllerRepresentable (that wraps Compose code) inside a SwiftUI ScrollView (without adding a frame() with a particular height)? https://stackoverflow.com/questions/67234508/uiviewcontrollerrepresentable-not-correctly-taking-up-space
a
I think this happens because of the constraints that don't have a set height, whereas the SKIA view would require one
Same reason we can't constrain a view in compose where the max height is infinite
d
We have a sample with Compose inside SwiftUI here: https://github.com/JetBrains/compose-multiplatform/tree/master/examples/chat We know some problems with the size of UIViewControllerRepresentable. For example when a device rotates. We will make interop between SwiftUI and Compose better.
j
In the code I'm working on I don't see the Compose UI (wrapped in the UIViewControllerRepresentable) at all if it's included in a ScrollView (unless i add frame with particular height....but that's not workable as height of component is variable)
d
Yeah, thanks for this report. We haven't thought about support for Compose inside scrollsable SwiftUI yet
j
there were a few suggestions in that SO question above but didn't seem to be workable in this particular scenario
I'm sure there's better way than this but hacked something together here (based on
onGloballyPositioned
) that seems to work (emphasis on "hack"!). First hacky part is that I need to use a
frame
initially with height larger than it should need. In my Kotlin code then I have
Copy code
fun SessionSpeakerInfoViewController(speaker: SpeakerDetails, onSocialLinkClicked: (String) -> Unit, heightChanged: (Int) -> Unit): UIViewController =
    ComposeUIViewController {
        MaterialTheme {
            Column(
                modifier = Modifier
                    .onGloballyPositioned { coordinates ->
                        heightChanged(coordinates.size.height)
                    }
            ) {
                SessionSpeakerInfo(speaker, onSocialLinkClicked)
            }
        }
    }
In SwiftUI I have
Copy code
struct SessionSpeakerInfoViewShared: UIViewControllerRepresentable {
    var speaker: SpeakerDetails
    @Binding var measuredHeight: CGFloat
    @Environment(\.openURL) var openURL
    
    func makeUIViewController(context: Context) -> UIViewController {
        let content = SharedViewControllersKt.SessionSpeakerInfoViewController(speaker: speaker, onSocialLinkClicked: { urlString in
            if let url = URL(string: urlString) {
                openURL(url)
            }
        }, heightChanged: { height in
            measuredHeight = CGFloat(height)
        })
        
        return content
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
    }
}
and then
Copy code
@State var measuredHeight: CGFloat = 1000

...

VStack {
    SessionSpeakerInfoViewShared(speaker: speaker.speakerDetails, measuredHeight: $measuredHeight)
        
}
.frame(height: measuredHeight)
(also still need to convert the units)
applying the conversion then here (3 pixels to 1 point on device I'm using)....sizes still a bit off and seeing some inconsistencies so probably not very dependable approach!
a
Out of curiosity, why not do the scrolling inside the compose view host?
j
The particular thing I'm trying out involves using compose code for just one part of the screen
a
Ah, in that case, as far as I know UIKit to Compose interop is good, but compose to UIKit isn't there
That, and I'd be curious to know the implications performance wise of resizing the SKIA canvas dynamically
d
I stumbled upon your article John as I'm trying too accomplish exactly this. Is there a better approach 9 months later or is this still the best way?
j
I haven't seen anything else at least in the meantime
d
Thats unfortunate, my usecase was a bit different my component has to expand on button clicks and what you had in the article, it wouldn't expand after it resized the first time because compose wouldn't grow based the bounds imposed by swift UI. I did get around this though by using
Copy code
.wrapContentHeight(unbounded = true)
on the composable being wrapped with a
Copy code
ComposeUIViewController
h
For everybody coming late to this thread - there is a corresponding open issue: https://github.com/JetBrains/compose-multiplatform/issues/4169 And something I've noticed: When using @John O'Reilly solution, combining it with
.wrapContentHeight(unbound=true)
seems to allow the initial frame height to be set to
1
instead of a large value.
212 Views