Hello. Im trying to implement navigating back with...
# compose-ios
m
Hello. Im trying to implement navigating back with ios touch gestures, but since I'm a newbie when it comes to kmp and ios I require some help. I tried something like that :
Copy code
class GestureViewController(
    private val onBackPressed: () -> Unit
) : UIViewController() {
    override fun viewDidLoad() {
        super.viewDidLoad()

        val edgePanGesture = UIScreenEdgePanGestureRecognizer(target = this, action = NSSelectorFromString("handleEdgePan:"))
        edgePanGesture.edges = UIRectEdgeRight
        view.addGestureRecognizer(edgePanGesture)
    }

    @ObjCAction
    fun handleEdgePan(gesture: UIScreenEdgePanGestureRecognizer) {
        if (gesture.state == UIGestureRecognizerStateEnded) {
            onBackPressed()
        }
    }
}

fun MainViewController(): UIViewController {
    GlobalKtorClient.initClient()
    initKoin()
    return ComposeUIViewController {
        AppTheme {
            val navController = rememberNavController()
            GestureViewController(onBackPressed = navController::navigateUp).apply {
                setContent {
                    NavigationHost(
                        navController = navController,
                        loginDataStore = remember { createDataStore() },
                        testDataStore = remember { createDataStore() }
                    )
                }
            }
        }
    }
}
But it doesnt work. If it isnt possible with compose navigation, then it's ok. It's just a feature
🧵 1
a
1.7.2 release will include this fix: https://github.com/JetBrains/compose-multiplatform-core/pull/1731 It does 2 helpful things: • Fixes swipe back for a compose view controllers inside UINavigationController. • Allows to configure your own
UIScreenEdgePanGestureRecognizer
to trigger navigate back actions.
thank you color 1
h
Are there any samples referencing these changes?
a
GestureViewController(onBackPressed = navController::navigateUp)
You didn't add GestureViewController to hierarchy, that's why it does not work. You either should put the ComposeUIViewController inside the GestureViewController as a child view controller, or add
UIScreenEdgePanGestureRecognizer
directly to the ComposeUIViewController.view (See
LocalUIViewController
) Ah, and it should work (but with no guarantee) only with 1.7.2 when it becomes available.
h
Copy code
fun MainViewController(
    onAppInitialized: (() -> Unit)? = null,
): UIViewController =
    GestureViewController(
        contentViewController = ComposeUIViewController(configure = {
            onFocusBehavior = OnFocusBehavior.DoNothing
        }) {
            MyApp(onAppInitialized = onAppInitialized)
        },
        onBackPressed = coreComponent.navigatorDispatcher::navigateUp
    )


class GestureViewController(
    private val contentViewController: UIViewController,
    private val onBackPressed: () -> Unit
) : UIViewController(null, null) {

    @OptIn(ExperimentalForeignApi::class)
    override fun viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(contentViewController.view)

        val edgePanGesture = UIScreenEdgePanGestureRecognizer(
            target = this,
            action = NSSelectorFromString("handleEdgePan:")
        )
        edgePanGesture.edges = UIRectEdgeRight
        contentViewController.view.addGestureRecognizer(edgePanGesture)
    }

    @OptIn(BetaInteropApi::class)
    @ObjCAction
    fun handleEdgePan(gesture: UIScreenEdgePanGestureRecognizer) {
        if (gesture.state == UIGestureRecognizerStateEnded) {
            onBackPressed()
        }
    }
}
i guess this is not the correct code?
a
Well.. looks better, still few pieces missing. 1. You have to provide correct size for
contentViewController.view
either by adding constrains or in
viewDidLayoutSubiviews
method. 2. Add
contentViewController
as a child and don't forget to call
didMoveToParent
3. Are you using compose 1.7.3 ? 4. Not sure if it's important, but still - try to attach
UIScreenEdgePanGestureRecognizer
to the
self.view
, not to the
contentViewController.view
h
Maybe it'll be a good idea to write some documentation and guide us (devs) or write some samples about this. I don't have this code, i just tried to adapt the one from the thread
I have this code
Copy code
struct ComposeView: UIViewControllerRepresentable {
     var onAppInitialized: (() -> Void)?
     func makeUIViewController(context: Context) -> UIViewController {
         MainViewControllerKt.MainViewController(
             onAppInitialized: onAppInitialized
         )
     }
     
     func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
 }
 
 
 struct ContentView: View {
     
     var body: some View {
         ZStack {
             Color(.surface)
             ComposeView(onAppInitialized: {
                 
                 }
             })
 }
 }
Copy code
fun MainViewController(
     onAppInitialized: (() -> Unit)? = null
 ) = ComposeUIViewController(
     configure = {
         onFocusBehavior = OnFocusBehavior.DoNothing
     }
 ) {
     CMPApp(
         onAppInitialized = onAppInitialized
     )
 }
@Andrei Salavei sorry to tag you but it seems you're the person who's most up to date, I saw that back handler is merged in KMP, is it possible to achieve this now? Again sorry for tag, I just couldn't find any other resource
a
This change will be included in 1.8.0 release. The feature is not ready yet, still some fixes are coming. As for now, you have two ways: Wait for upcoming dev or alpha build that include this change or build compose multyplatform locally from sources and use it.
h
Would there be some samples regarding how we can achieve it with single Compose view controller?
a
It should be available via the
BackHandler
/
PredictiveBackHandler
API
1
183 Views