如何在 HorizontalPager 和包含该寻呼机的父可组合屏幕之间共享 HiltViewModel?
我有一个 SignupScreen
来容纳水平寻呼机。寻呼机有 3 个选项卡: Register
Otp
Questions
。这三个选项卡还更新并监听来自其父屏幕的 SignupViewModel 的数据 这些是我的代码:
@Composable
fun SignupScreen(
navController: NavController
) {
SignupView(navController = navController)
}
@OptIn(ExperimentalPagerApi::class)
@Composable
fun SignupView(
navController: NavController
) {
val vm: SignupViewModel = hiltViewModel()
val signupUiState = vm.signupUiState.value
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
val pagerState = rememberPagerState()
val signupTabs = listOf(
SignupPagerTabs.Register,
SignupPagerTabs.Otp,
SignupPagerTabs.Questions,
)
LaunchedEffect(key1 = true) {
vm.signupUiEvent.collect {
when (it) {
SignupUiEvent.GoNextPage -> {
}
SignupUiEvent.GoPreviousPage -> {
}
SignupUiEvent.NavigateToHomeScreen -> {
navController.popBackStack(AppDestination.Home.route, inclusive = true)
navController.navigate(Routes.HOME_ROUTE)
}
SignupUiEvent.Popup -> {
navController.popBackStack()
}
is SignupUiEvent.ShowSnackBar -> {
scaffoldState.snackbarHostState.showSnackbar(
message = it.message
)
}
}
}
}
Scaffold(
scaffoldState = scaffoldState,
topBar = {
TopBar2(
navIcon = painterResource(id = R.drawable.ic_back),
title = stringResource(id = R.string.top_bar_signup),
onNavIconClicked = {
vm.onEvent(SignupUiAction.ClickPreviousPage)
}
)
},
content = {
SignupContentView(
tabs = signupTabs,
pagerState = pagerState
)
}
)
}
@OptIn(ExperimentalPagerApi::class)
@Composable
fun SignupContentView(
tabs: List<SignupPagerTabs>,
pagerState: PagerState
) {
Column(modifier = Modifier.fillMaxSize()) {
PagerIndicator(tabs.size, pagerState.currentPage)
HorizontalPager(
count = tabs.size,
state = pagerState
) { index ->
tabs[index].screenToLoad()
}
}
}
这是我的 ViewModel。
@HiltViewModel
class SignupViewModel @Inject constructor(
private val signupUseCase: SignupUseCase
) : ViewModel() {
private val _signupUiState: MutableState<SignupUiState> = mutableStateOf(SignupUiState())
val signupUiState: State<SignupUiState> get() = _signupUiState
private val _signupUiEvent = MutableSharedFlow<SignupUiEvent>()
val signupUiEvent = _signupUiEvent.asSharedFlow()
private val currentPage = signupUiState.value.currentPage
private val completedPage = signupUiState.value.completedPage
fun onEvent(action: SignupUiAction) {
when (action) {
is SignupUiAction.ChangeFullName -> {
_signupUiState.value = signupUiState.value.copy(
fullName = action.name
)
}
is SignupUiAction.ChangePassword -> {
_signupUiState.value = signupUiState.value.copy(
password = action.password
)
}
is SignupUiAction.ChangePasswordConfirm -> {
_signupUiState.value = signupUiState.value.copy(
passwordConfirm = action.passwordConfirm
)
}
is SignupUiAction.ChangePhoneNumber -> {
_signupUiState.value = signupUiState.value.copy(
phoneNumber = action.phone
)
}
is SignupUiAction.ChangeRegion -> {
_signupUiState.value = signupUiState.value.copy(
region = action.country
)
}
SignupUiAction.ClickNextPage -> {
when (currentPage) {
SignupPage.REGISTER_PAGE -> {
_signupUiState.value = signupUiState.value.copy(
currentPage = currentPage + 1
)
}
SignupPage.OTP_PAGE -> {
_signupUiState.value = signupUiState.value.copy(
currentPage = currentPage + 1
)
}
SignupPage.SECURITY_QUESTION_PAGE -> {
//do request to server
viewModelScope.launch {
_signupUiEvent.emit(
SignupUiEvent.NavigateToHomeScreen
)
}
}
}
}
SignupUiAction.ClickPreviousPage -> {
when (currentPage) {
SignupPage.REGISTER_PAGE -> {
viewModelScope.launch {
_signupUiEvent.emit(
SignupUiEvent.Popup
)
}
}
SignupPage.OTP_PAGE -> {
_signupUiState.value = signupUiState.value.copy(
currentPage = currentPage - 1
)
}
SignupPage.SECURITY_QUESTION_PAGE -> {
_signupUiState.value = signupUiState.value.copy(
currentPage = currentPage - 1
)
}
}
}
SignupUiAction.ClickStart -> {
}
SignupUiAction.ClearFullName -> {
_signupUiState.value = signupUiState.value.copy(
fullName = ""
)
}
SignupUiAction.ClearPassword -> {
_signupUiState.value = signupUiState.value.copy(
password = ""
)
}
SignupUiAction.ClearPasswordConfirm -> {
_signupUiState.value = signupUiState.value.copy(
passwordConfirm = ""
)
}
SignupUiAction.ClearPhoneNumber -> {
_signupUiState.value = signupUiState.value.copy(
phoneNumber = ""
)
}
is SignupUiAction.ChangeOtpCode -> {
_signupUiState.value = signupUiState.value.copy(
otpCode = action.code
)
}
SignupUiAction.ClickResend -> {
//todo resend logic
viewModelScope.launch {
}
}
}
}
private fun signup() {
val requestBody = SignupRequest(
countryCodeId = signupUiState.value.region.id,
name = signupUiState.value.fullName,
mobile = signupUiState.value.phoneNumber,
password = signupUiState.value.password,
securityQuestionUsage = listOf()
)
viewModelScope.launch {
signupUseCase(body = requestBody).collect {
when (it) {
is Resource.ErrorEvent -> {
_signupUiEvent.emit(
SignupUiEvent.ShowSnackBar(
message =
it.message ?: "Error"
)
)
}
is Resource.LoadingEvent -> {
_signupUiState.value = signupUiState.value.copy(
isLoading = true,
loadingMessageType = SignupStatus.SECURITY_QUESTION_PAGE
)
}
is Resource.SuccessEvent -> {
}
}
}
}
}
}
这是我的寻呼机选项卡。
object SignupPage {
const val REGISTER_PAGE = 0
const val OTP_PAGE = 1
const val SECURITY_QUESTION_PAGE = 2
}
enum class SignupStatus(val index: Int) {
REGISTER_PAGE(index = SignupPage.REGISTER_PAGE),
OTP_PAGE(index = SignupPage.OTP_PAGE),
SECURITY_QUESTION_PAGE(index = SignupPage.SECURITY_QUESTION_PAGE),
}
sealed class SignupPagerTabs(
val index: Int,
val screenToLoad: @Composable () -> Unit,
) {
object Register : SignupPagerTabs(
index = 0,
screenToLoad = {
RegisterScreen(
)
}
)
object Otp : SignupPagerTabs(
index = 1,
screenToLoad = {
OtpVerificationSignupScreen(
)
}
)
object Questions : SignupPagerTabs(
index = 2,
screenToLoad = {
SecurityQuestionChooseScreen(
)
}
)
}
在 Register
Otp
Question
屏幕中,我想访问 SignupViewModel
。
请帮助我。
I have a SignupScreen
that holds horizontal pager. The pager has 3 tabs, Register
Otp
Questions
. Those three tabs also update and listen to data from its parent screen's SignupViewModel
These are my code :
@Composable
fun SignupScreen(
navController: NavController
) {
SignupView(navController = navController)
}
@OptIn(ExperimentalPagerApi::class)
@Composable
fun SignupView(
navController: NavController
) {
val vm: SignupViewModel = hiltViewModel()
val signupUiState = vm.signupUiState.value
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
val pagerState = rememberPagerState()
val signupTabs = listOf(
SignupPagerTabs.Register,
SignupPagerTabs.Otp,
SignupPagerTabs.Questions,
)
LaunchedEffect(key1 = true) {
vm.signupUiEvent.collect {
when (it) {
SignupUiEvent.GoNextPage -> {
}
SignupUiEvent.GoPreviousPage -> {
}
SignupUiEvent.NavigateToHomeScreen -> {
navController.popBackStack(AppDestination.Home.route, inclusive = true)
navController.navigate(Routes.HOME_ROUTE)
}
SignupUiEvent.Popup -> {
navController.popBackStack()
}
is SignupUiEvent.ShowSnackBar -> {
scaffoldState.snackbarHostState.showSnackbar(
message = it.message
)
}
}
}
}
Scaffold(
scaffoldState = scaffoldState,
topBar = {
TopBar2(
navIcon = painterResource(id = R.drawable.ic_back),
title = stringResource(id = R.string.top_bar_signup),
onNavIconClicked = {
vm.onEvent(SignupUiAction.ClickPreviousPage)
}
)
},
content = {
SignupContentView(
tabs = signupTabs,
pagerState = pagerState
)
}
)
}
@OptIn(ExperimentalPagerApi::class)
@Composable
fun SignupContentView(
tabs: List<SignupPagerTabs>,
pagerState: PagerState
) {
Column(modifier = Modifier.fillMaxSize()) {
PagerIndicator(tabs.size, pagerState.currentPage)
HorizontalPager(
count = tabs.size,
state = pagerState
) { index ->
tabs[index].screenToLoad()
}
}
}
This is my ViewModel.
@HiltViewModel
class SignupViewModel @Inject constructor(
private val signupUseCase: SignupUseCase
) : ViewModel() {
private val _signupUiState: MutableState<SignupUiState> = mutableStateOf(SignupUiState())
val signupUiState: State<SignupUiState> get() = _signupUiState
private val _signupUiEvent = MutableSharedFlow<SignupUiEvent>()
val signupUiEvent = _signupUiEvent.asSharedFlow()
private val currentPage = signupUiState.value.currentPage
private val completedPage = signupUiState.value.completedPage
fun onEvent(action: SignupUiAction) {
when (action) {
is SignupUiAction.ChangeFullName -> {
_signupUiState.value = signupUiState.value.copy(
fullName = action.name
)
}
is SignupUiAction.ChangePassword -> {
_signupUiState.value = signupUiState.value.copy(
password = action.password
)
}
is SignupUiAction.ChangePasswordConfirm -> {
_signupUiState.value = signupUiState.value.copy(
passwordConfirm = action.passwordConfirm
)
}
is SignupUiAction.ChangePhoneNumber -> {
_signupUiState.value = signupUiState.value.copy(
phoneNumber = action.phone
)
}
is SignupUiAction.ChangeRegion -> {
_signupUiState.value = signupUiState.value.copy(
region = action.country
)
}
SignupUiAction.ClickNextPage -> {
when (currentPage) {
SignupPage.REGISTER_PAGE -> {
_signupUiState.value = signupUiState.value.copy(
currentPage = currentPage + 1
)
}
SignupPage.OTP_PAGE -> {
_signupUiState.value = signupUiState.value.copy(
currentPage = currentPage + 1
)
}
SignupPage.SECURITY_QUESTION_PAGE -> {
//do request to server
viewModelScope.launch {
_signupUiEvent.emit(
SignupUiEvent.NavigateToHomeScreen
)
}
}
}
}
SignupUiAction.ClickPreviousPage -> {
when (currentPage) {
SignupPage.REGISTER_PAGE -> {
viewModelScope.launch {
_signupUiEvent.emit(
SignupUiEvent.Popup
)
}
}
SignupPage.OTP_PAGE -> {
_signupUiState.value = signupUiState.value.copy(
currentPage = currentPage - 1
)
}
SignupPage.SECURITY_QUESTION_PAGE -> {
_signupUiState.value = signupUiState.value.copy(
currentPage = currentPage - 1
)
}
}
}
SignupUiAction.ClickStart -> {
}
SignupUiAction.ClearFullName -> {
_signupUiState.value = signupUiState.value.copy(
fullName = ""
)
}
SignupUiAction.ClearPassword -> {
_signupUiState.value = signupUiState.value.copy(
password = ""
)
}
SignupUiAction.ClearPasswordConfirm -> {
_signupUiState.value = signupUiState.value.copy(
passwordConfirm = ""
)
}
SignupUiAction.ClearPhoneNumber -> {
_signupUiState.value = signupUiState.value.copy(
phoneNumber = ""
)
}
is SignupUiAction.ChangeOtpCode -> {
_signupUiState.value = signupUiState.value.copy(
otpCode = action.code
)
}
SignupUiAction.ClickResend -> {
//todo resend logic
viewModelScope.launch {
}
}
}
}
private fun signup() {
val requestBody = SignupRequest(
countryCodeId = signupUiState.value.region.id,
name = signupUiState.value.fullName,
mobile = signupUiState.value.phoneNumber,
password = signupUiState.value.password,
securityQuestionUsage = listOf()
)
viewModelScope.launch {
signupUseCase(body = requestBody).collect {
when (it) {
is Resource.ErrorEvent -> {
_signupUiEvent.emit(
SignupUiEvent.ShowSnackBar(
message =
it.message ?: "Error"
)
)
}
is Resource.LoadingEvent -> {
_signupUiState.value = signupUiState.value.copy(
isLoading = true,
loadingMessageType = SignupStatus.SECURITY_QUESTION_PAGE
)
}
is Resource.SuccessEvent -> {
}
}
}
}
}
}
This is my Pager Tabs.
object SignupPage {
const val REGISTER_PAGE = 0
const val OTP_PAGE = 1
const val SECURITY_QUESTION_PAGE = 2
}
enum class SignupStatus(val index: Int) {
REGISTER_PAGE(index = SignupPage.REGISTER_PAGE),
OTP_PAGE(index = SignupPage.OTP_PAGE),
SECURITY_QUESTION_PAGE(index = SignupPage.SECURITY_QUESTION_PAGE),
}
sealed class SignupPagerTabs(
val index: Int,
val screenToLoad: @Composable () -> Unit,
) {
object Register : SignupPagerTabs(
index = 0,
screenToLoad = {
RegisterScreen(
)
}
)
object Otp : SignupPagerTabs(
index = 1,
screenToLoad = {
OtpVerificationSignupScreen(
)
}
)
object Questions : SignupPagerTabs(
index = 2,
screenToLoad = {
SecurityQuestionChooseScreen(
)
}
)
}
In Register
Otp
Question
Screens, I want to access the SignupViewModel
.
Please Help Me.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论