Compose学习
Navigation

Compose 导航

基础导航

NavController

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val navController = rememberNavController()
            
            NavHost(navController, startDestination = "home") {
                composable("home") { HomeScreen(navController) }
                composable("detail/{id}") { backStackEntry ->
                    val id = backStackEntry.arguments?.getString("id")
                    DetailScreen(id, navController)
                }
            }
        }
    }
}

导航操作

@Composable
fun HomeScreen(navController: NavController) {
    Button(onClick = { 
        navController.navigate("detail/123") 
    }) {
        Text("跳转到详情")
    }
}
 
@Composable
fun DetailScreen(id: String?, navController: NavController) {
    Button(onClick = { 
        navController.popBackStack() 
    }) {
        Text("返回")
    }
}

高级特性

深层链接

AndroidManifest.xml:
<activity>
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="myapp" android:host="example.com" />
    </intent-filter>
</activity>
 
NavHost {
    composable(
        "detail/{id}",
        deepLinks = listOf(navDeepLink { 
            uriPattern = "myapp://example.com/detail/{id}" 
        })
    ) { backStackEntry ->
        DetailScreen(backStackEntry.arguments?.getString("id"))
    }
}

参数传递

// 定义参数
composable(
    route = "profile/{userId}?showDetails={showDetails}",
    arguments = listOf(
        navArgument("userId") { type = NavType.StringType },
        navArgument("showDetails") { 
            type = NavType.BoolType 
            defaultValue = false
        }
    )
) { backStackEntry ->
    val userId = backStackEntry.arguments?.getString("userId")
    val showDetails = backStackEntry.arguments?.getBoolean("showDetails") ?: false
    ProfileScreen(userId, showDetails)
}
 
// 导航时传递参数
navController.navigate("profile/123?showDetails=true")

导航架构

导航图

fun NavGraphBuilder.profileGraph(navController: NavController) {
    navigation(startDestination = "profile", route = "profile_graph") {
        composable("profile") { ProfileScreen(navController) }
        composable("settings") { SettingsScreen(navController) }
        composable("edit_profile") { EditProfileScreen(navController) }
    }
}
 
NavHost(navController, startDestination = "home") {
    composable("home") { HomeScreen(navController) }
    profileGraph(navController)
}

共享元素过渡

@Composable
fun ListScreen(navController: NavController) {
    val items = remember { listOf("Item 1", "Item 2", "Item 3") }
    
    LazyColumn {
        items(items) { item ->
            ListItem(
                modifier = Modifier.clickable {
                    navController.navigate("detail/$item")
                },
                text = { Text(item) }
            )
        }
    }
}
 
@Composable
fun DetailScreen(item: String, navController: NavController) {
    Column {
        Text(
            text = item,
            style = MaterialTheme.typography.h4
        )
        Button(onClick = { navController.popBackStack() }) {
            Text("返回")
        }
    }
}

最佳实践

1. 导航状态管理

class MainViewModel : ViewModel() {
    private val _navigationState = MutableStateFlow<NavigationState>(NavigationState.None)
    val navigationState: StateFlow<NavigationState> = _navigationState.asStateFlow()
 
    fun navigate(state: NavigationState) {
        _navigationState.value = state
    }
}
 
sealed class NavigationState {
    object None : NavigationState()
    data class ToDetail(val id: String) : NavigationState()
    object Back : NavigationState()
}

2. 类型安全的导航

sealed class Screen(val route: String) {
    object Home : Screen("home")
    object Profile : Screen("profile")
    data class Detail(val id: String) : Screen("detail/{id}") {
        fun createRoute() = "detail/$id"
    }
}
 
// 使用
navController.navigate(Screen.Detail("123").createRoute())

3. 导航拦截

val navController = rememberNavController()
 
LaunchedEffect(navController) {
    navController.addOnDestinationChangedListener { _, destination, _ ->
        // 处理导航变化
        when(destination.route) {
            "profile" -> {
                // 检查是否登录
                if (!isLoggedIn) {
                    navController.navigate("login")
                }
            }
        }
    }
}