-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
The absence of a specific type for androidx.compose.ui.window.ComposeUIViewControllerand platform.UIKit.UIViewController presents a limitation in using updateUIViewController and, consequently, the associated Composable.
In scenarios where the iOS application requires management of Composable state through an iOS ViewModel, the availability of such types would prove to be advantageous:
struct SampleUIViewController: UIViewControllerRepresentable {
@Binding var status: String
let action: () -> Void
func makeUIViewController(context: Context) -> UIViewController {
return SharedViewControllers().sampleComposable(status: status, click: action)
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
//how to update the composable state when binding values changes?
}
}
struct ComposeScreen: View {
@StateObject private var viewModel = ViewModels.sampleViewModel()
@State private var status: String = ""
var body: some View {
SampleUIViewController(
status: $status,
action: { viewModel.doSomething() }
)
.onReceive(viewModel.$state) { new in
status = new.label()
}
.ignoresSafeArea()
}
}
I find this use-case quite intriguing, particularly in its potential to attract iOS developers and facilitate incremental adoption. Furthermore, it introduces the exciting possibility of incorporating Composables into a project without the necessity of sharing ViewModels. This offers a more flexible approach compared to a full-fledged Composable + ViewModel sharing strategy.
Currently, the workaround I've discovered involves incorporating a MutableStateFlow within the ComposeUIViewController, which responds to changes in state properties:
object SharedViewControllers {
private data class ComposeUIViewState(val status: String = "")
private val state = MutableStateFlow(ComposeUIViewState())
fun sampleComposable(click: () -> Unit): UIViewController {
return ComposeUIViewController {
with(state.collectAsState().value) {
Composable(state.status, click)
}
}
}
fun updateSampleComposable(status: String) {
state.update { ComposeUIViewState(status = status) }
}
}
on iosApp side:
struct SampleUIViewController: UIViewControllerRepresentable {
@Binding var status: String
let action: () -> Void
func makeUIViewController(context: Context) -> UIViewController {
return SharedViewControllers().sampleComposable(click: action)
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
SharedViewControllers().updateSampleComposable(status: status)
}
}
It works, but it's not very graceful.