返回

Compose Multiplatform 集成 iOS 原生导航及滑动返回

Android

Compose Multiplatform 中集成原生 iOS 导航

在 Compose Multiplatform 项目中,实现流畅的 iOS 原生导航,特别是支持滑动返回手势,是一个常见的需求。虽然 Voyager 等跨平台导航库提供了一定的解决方案,但在 iOS 上的流畅度和手势响应方面仍有提升空间。本文将探讨如何集成原生 iOS 导航并支持滑动返回,以提升用户体验。

问题分析

Compose Multiplatform 使用 Kotlin 编写 UI,并通过平台特定的渲染器将其转换为原生控件。直接在 Compose 层处理 iOS 导航,往往难以完美复制原生导航的体验,尤其是在滑动返回等复杂手势交互方面。

解决方案:拥抱原生 UINavigationController

为了获得最佳的 iOS 导航体验,建议直接使用 iOS 原生的 UINavigationController。这意味着 iOS 部分的 Compose UI 将嵌入到 UINavigationController 管理的视图层次结构中。

步骤一:创建 iOS Compose View 包装器

首先,创建一个 UIViewController 子类,用于承载 Compose UI。这个 UIViewController 将作为 UINavigationController 的子视图控制器。

import UIKit
import SwiftUI
import shared // Your shared Compose Multiplatform module

class ComposeViewController: UIViewController {

    private let content: @Composable () -> Unit

    init(content: @Composable () -> Unit) {
        self.content = content
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func loadView() {
        view = ComposeView().apply {
            $0.setContent {
                content()
            }
        }
    }
}

步骤二:使用 UINavigationController 管理导航

在 iOS App 入口(通常是 AppDelegateSceneDelegate)中,使用 UINavigationController 作为根视图控制器,并将包含 Compose UI 的 ComposeViewController 作为其第一个子视图控制器。

import UIKit
import shared // Your shared Compose Multiplatform module


class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }
        window = UIWindow(windowScene: windowScene)

        let firstComposeView = ComposeViewController {
           // Your Compose UI content for the first screen
           Text("First Screen")
           Button("Go to Second Screen") {
               // Push the next ComposeViewController
               let nextScreen = ComposeViewController {
                   Text("Second Screen")
               }
               navigationController?.pushViewController(nextScreen, animated: true)

           }

        }


        let navigationController = UINavigationController(rootViewController: firstComposeView)

        window?.rootViewController = navigationController
        window?.makeKeyAndVisible()
    }

   // ... other SceneDelegate methods
}

步骤三:在 Compose 代码中触发导航

在 Compose 代码中,可以通过平台通道或共享 ViewModel 等方式,与 iOS 代码交互,触发 UINavigationControllerpushViewControllerpopViewController 方法进行导航操作。

// In your shared Compose Multiplatform ViewModel or other shared logic

interface NavigationManager {
    fun navigateToScreen(route: String)
    fun navigateBack()
}

class IosNavigationManager(private val navigationController: UINavigationController): NavigationManager {

    override fun navigateToScreen(route: String) {
       // Create the next ComposeViewController based on the route
       val nextScreen = ComposeViewController { /*... Compose UI based on route */ }
       navigationController.pushViewController(nextScreen, animated: true)

    }
    override fun navigateBack() {
       navigationController.popViewController(animated: true)
    }
}


// In your Compose Composable
@Composable
fun SomeScreen(navigationManager: NavigationManager) {
    Button(onClick = { navigationManager.navigateToScreen("next_screen") } ) {
       Text("Go to next screen")
    }
}

通过这种方式,可以充分利用 iOS 原生导航的流畅性和滑动返回功能,并保持 Compose Multiplatform 的跨平台优势。需要注意的是,在处理导航逻辑时,需要仔细考虑平台差异,并确保在 Android 平台上使用合适的导航方案。

安全建议:

  • 确保共享的导航逻辑不会直接依赖平台特定的 API,可以使用接口或抽象类进行封装。
  • 注意内存管理,避免循环引用。