Skip to content

Ability to define a UIViewController type #3478

@GuilhE

Description

@GuilhE

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.

Metadata

Metadata

Labels

discussionNeed further discussion to understand if it actually neededenhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions