I’m working on three pages: StartPage, LoginPage, and SignupPage, and I’m integrating them into a HorizontalPager.
In the SignupPage, i’m using requestFocus on textField.
The navigation flow is Start -> Login, but I’m encountering this error when transitioning to the LoginPage.
java.lang.IllegalStateException:
FocusRequester is not initialized. Here are some possible fixes:
1. Remember the FocusRequester: val focusRequester = remember { FocusRequester() }
2. Did you forget to add a Modifier.focusRequester() ?
3. Are you attempting to request focus during composition? Focus requests should be made in
response to some event. Eg Modifier.clickable { focusRequester.requestFocus() }
This is MyNavigation.kt
@Composable
fun MyAppNavigation(
modifier: Modifier, authViewModel: AuthViewModel
) {
val pages = registerInfoList.size
val pagerState = rememberPagerState(pageCount = { pages })
val scope = rememberCoroutineScope()
Column(
modifier = modifier.fillMaxSize()
) {
HorizontalPager(
state = pagerState, userScrollEnabled = false
) { page ->
when (page) {
0 -> StartPage(modifier = modifier,
toSignUp = {
scope.launch {
pagerState.animateScrollToPage(2)
}
}, toLogin = {
scope.launch {
pagerState.animateScrollToPage(1)
}
}, authViewModel = authViewModel
)
1 -> LoginPage(modifier = modifier,
toHome = {
scope.launch {
pagerState.animateScrollToPage(3)
}
}, toSignUp = {
scope.launch {
pagerState.animateScrollToPage(2)
}
},
toStart = {
scope.launch {
pagerState.animateScrollToPage(0)
}
}, authViewModel = authViewModel
)
2 -> SignupPage(
modifier = modifier,
toStart = {
scope.launch {
pagerState.animateScrollToPage(0)
}
},
toHome = {
scope.launch {
pagerState.animateScrollToPage(3)
}
},
authViewModel = authViewModel
)
......
}
}
}
}
LoginPage.kt
@OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class)
@Composable
fun LoginPage(
modifier: Modifier = Modifier,
toSignUp: () -> Unit,
toHome: () -> Unit,
toStart: () -> Unit,
authViewModel: AuthViewModel
) {
...................
if (shouldShowDialog.value) {
AlertDialog(shouldShowDialog = shouldShowDialog, message = errorMessage)
}
val authState = authViewModel.authState.observeAsState()
LocalContext.current
LaunchedEffect(authState.value) {
when (authState.value) {
is AuthState.Authenticated -> toHome()
is AuthState.Error.InvalidCredentialsError -> {
errorMessage = (authState.value as AuthState.Error.InvalidCredentialsError).message
shouldShowDialog.value = true
}
is AuthState.Error.NetworkError -> {
errorMessage = (authState.value as AuthState.Error.NetworkError).message
}
else -> Unit
}
}
Scaffold(...................
) { innerPadding ->
Column(
.......
) {
Text(
............
)
Spacer(modifier = Modifier.size(4.dp))
TextField(............)
Spacer(modifier = Modifier.size(32.dp))
Text(.............)
Spacer(modifier = Modifier.size(4.dp))
TextField(.........)
Text(
..........
)
Spacer(modifier = Modifier.height(32.dp))
var colorButton by remember { mutableStateOf(Color.White) }
Button(..........)
Spacer(modifier = Modifier.height(8.dp))
TextButton(.......)
}
}
}
SignupPage.kt
@Composable
fun SignupPage(
modifier: Modifier = Modifier,
toStart: () -> Unit,
toHome: () -> Unit,
authViewModel: AuthViewModel
) {
.........
// Added FocusRequesters for each TextField
val emailFocusRequester = remember { FocusRequester() }
val passwordFocusRequester = remember { FocusRequester() }
val userNameFocusRequester = remember { FocusRequester() }
val keyboardController = LocalSoftwareKeyboardController.current
val context = LocalContext.current
LaunchedEffect(authState.value) {
when (authState.value) {
is AuthState.Authenticated -> toHome()
is AuthState.Error.NetworkError -> Toast.makeText(
context,
(authState.value as AuthState.Error.NetworkError).message, Toast.LENGTH_SHORT
).show()
else -> Unit
}
}
// Updated LaunchedEffect to handle focus and keyboard visibility
LaunchedEffect(pagerState.currentPage) {//------> this where the crash happen
when (pagerState.currentPage) {
0 -> emailFocusRequester.requestFocus()
1 -> passwordFocusRequester.requestFocus()
2 -> keyboardController?.hide()
3 -> keyboardController?.hide() // No TextField on this page
4 -> userNameFocusRequester.requestFocus()
}
// Delay to ensure the focus change is processed
delay(100)
if (pagerState.currentPage in listOf(0, 1, 4)) {
keyboardController?.show()
} else {
keyboardController?.hide()
}
}
Scaffold(
..........
) { innerPadding ->
Column(
..................
) {
HorizontalPager(
state = pagerState,
userScrollEnabled = false
) { index ->
Column(
...............
) {
Text(
..................
)
Spacer(modifier = Modifier.size(4.dp))
when (index) {
0 -> // email and name
TextField(
modifier = Modifier
.fillMaxWidth()
.focusRequester(emailFocusRequester),
)
1 -> {
TextField(modifier = Modifier
.fillMaxWidth()
.focusRequester(passwordFocusRequester))
2 -> {
DatePicker { date ->
dateOfBirth = date.let {
SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()).format(it)
}
}
}
3 -> {
ExposedDropdownMenuBox(............)
4 -> // email and name
TextField(
modifier = Modifier
.fillMaxWidth()
.focusRequester(userNameFocusRequester),
)
Spacer(modifier = Modifier.size(4.dp))
Text(
....................
)
}
}
Spacer(modifier = Modifier.height(16.dp))
Button(..............)
}
}
}