Administrator
Administrator
Published on 2025-03-21 / 19 Visits
0
0

compositionLocalOf和viewModel

由于被NavHost(会为每个导航目标创建NavBackStackEntry从而导致不同的生命周期和作用域)包裹后Composable页面无法通过viewModel()得到Activity中的相同实例,所以使用CompositionLocalOf显式传递。

由于NavBackStackEntry每个composeable页面有独立的作用域,所以无法得到Activity的viewModel实例,才需要用到compositionLocalOf向下传递。如果不使用navigation的NavHost,则可以在所有Composable页面/组件直接使用val viewmodel : CustomViewModel = viewModel()得到相同的viewModel实例。

val localNavController = compositionLocalOf <NavController> { error("No NavController found!") }
val localViewModel =  compositionLocalOf <CustomViewModel>{ error("No NavController found!") }
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            val viewmodel : CustomViewModel = viewModel()
            CustomThemeComponent(viewmodel.theme) {
                val navController = rememberNavController()
                CompositionLocalProvider(localNavController provides navController, localViewModel provides viewmodel) {
                    NavHost(navController = navController, startDestination = "home", enterTransition = {
                        EnterTransition.None
                    }, exitTransition = {
                        ExitTransition.None
                    }, popEnterTransition = {
                        EnterTransition.None
                    }) {
                        composable("home") {
                            Button(modifier = Modifier.padding(vertical = 200.dp),onClick = {
                                viewmodel.theme = when(viewmodel.theme) {
                                    CustomTheme.Themes.LIGHT -> CustomTheme.Themes.DARK
                                    CustomTheme.Themes.DARK -> CustomTheme.Themes.LIGHT
                                }
                            }) { Text(text = "切换") }
                            HomeScreen()
                        }
                        composable("profile") {
                            ProfileScreen()
                        }
                        composable("login") {
                            Login()
                        }
                    }
                }
            }
        }
    }
}

@Composable
fun HomeScreen() {
    val nav = localNavController.current
    val viewmodel : CustomViewModel = localViewModel.current

    var i1 by rememberSaveable { mutableStateOf("") }
    Column(modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars).background(color = CustomTheme.colors.bgColor)) {
        Text("首页", color = CustomTheme.colors.textColor, fontWeight = FontWeight.Bold)

        TextField(value = i1, onValueChange = { i1 = it }, modifier = Modifier.clip(RoundedCornerShape(CustomTheme.colors.btnShape)))
        Button(onClick = {
//            nav.navigate("profile")
        }) {
            Text("跳转到个人中心")
        }
    }
}

viewModel.kt

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import com.dmjyb.navtest.ui.theme.CustomTheme

class CustomViewModel : ViewModel() {
    var theme by mutableStateOf(CustomTheme.Themes.DARK)
}


Comment