我正在将基于 Kotlin 视图的应用程序转换为 JetPack Compose。 第一个要转换的是登录屏幕。 它有许多 OutlinedTextFields。 当用户单击其中一个字段时,我希望显示适当的软键盘。
我已将键盘类型编码为
keyboardType = KeyboardType.Text,
keyboardType = KeyboardType.Email,
keyboardType = KeyboardType.Phone,
keyboardType = KeyboardType.Password
以上唯一自动显示软键盘的是Password。 所有其他的都在菜单中显示幻灯片,允许用户请求软键盘。 请参阅附图。
这里有一些屏幕截图可以提供帮助。
当我点击密码字段时,我想要的键盘显示如下:
这是我收到的菜单中的幻灯片。
这是当前的撰写屏幕代码。
enter code here
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun RegisterUserProfileScreen(registerUserProfileViewModel: RegisterUserProfileViewModel = viewModel(), navController: NavController) {
val _uiState = MutableStateFlow(
RegisterUserProfileUiState(
registerUserProfileErrorMessage = "",
primaryUserSelected = true,
familyAdminSelected = false,
registerUserProfileLastName = "",
registerUserProfileFirstName = "",
registerUserProfileMobilePhone = "",
registerUserProfileEmailAddress = "",
registerUserProfilePassword = "",
registerUserProfileConfirmPassword = "",
shouldShowAlertDialog = false,
alertDialogTitle = " ",
alertDialogMessage = " ",
alertDialogType = " ",
shouldShowIdentityVerificationDialog = false,
identityVerificationTextCode = 0,
identityVerificationEmailCode = 0,
identityVerificationErrorMessage = " ",
identityVerificationResponseReceived = false,
mSendingActivity = " ",
isConnected = false
)
)
val registerUserProfileUiState by registerUserProfileViewModel.uiState.collectAsState()
var showPassword by remember { mutableStateOf(value = false) }
var shouldShowIdentityVerificationDialog = remember { mutableStateOf(false) }
var primaryUserSelectedIn: Boolean = true
var familyAdminSelectedIn: Boolean = false
val myContext = LocalContext.current
var registerUserProfilePassword2: String
var verificationErrorMessage: String = " "
val focusManager = LocalFocusManager.current
val coroutineScope = CoroutineScope(Dispatchers.Main)
LaunchedEffect(Unit) {
registerUserProfileViewModel.initializeServices(myContext)
}
Log.i(" ", "RegisterUserProfileScreen: shouldShowIdentityVerificationDialog ${registerUserProfileViewModel.shouldShowIdentityVerificationDialog}")
if (registerUserProfileViewModel.shouldShowIdentityVerificationDialog) {
IdentityVerificationDialog(
onDismiss = { /*TODO*/ },
onExit = {
_uiState.value.identityVerificationResponseReceived = true
val mAnswer1 = _uiState.value.identityVerificationTextCode
val mAnswer2 = _uiState.value.identityVerificationEmailCode
val twoFactorTextResponse = mAnswer1
val twoFactorEmailResponse = mAnswer2
if (twoFactorTextResponse != registerUserProfileViewModel.randomNumberText) {
verificationErrorMessage =
"Incorrect answer to phone text security code"
registerUserProfileViewModel.responseCorrect = false
} else if (twoFactorEmailResponse != registerUserProfileViewModel.randomNumberEmail) {
verificationErrorMessage =
"Incorrect answer to email security code"
registerUserProfileViewModel.responseCorrect = false
} else {
registerUserProfileViewModel.responseCorrect = true
}
if (!registerUserProfileViewModel.responseCorrect) {
_uiState.update { currentState ->
currentState.copy(
alertDialogTitle = "Identity Verification",
alertDialogMessage = "A text has been sent to the mobile number you provided and an email " +
"has been sent to the email you entered. Please get the codes and enter below. ",
alertDialogType = " ",
identityVerificationErrorMessage = verificationErrorMessage,
shouldShowIdentityVerificationDialog = true,
identityVerificationResponseReceived = false,
)
}
}
else {
registerUserProfileViewModel.responseCorrect = true
registerUserProfileViewModel.completeUserProfileRegistration()
_uiState.update { currentState ->
currentState.copy(
identityVerificationErrorMessage = " ",
shouldShowIdentityVerificationDialog = false,
identityVerificationResponseReceived = false,
)
}
}
},
registerUserProfileViewModel = registerUserProfileViewModel,
shouldShowIdentityVerificationDialog = registerUserProfileViewModel.shouldShowIdentityVerificationDialog
)
}
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 10.dp)
) {
val (a, b, c, d, e, f) = FocusRequester.createRefs()
Spacer(modifier = Modifier.height(120.dp))
//Header text instructions
Text(
text = "Please enter your user profile information",
fontSize = 18.sp,
color = Color.Blue,
)
Spacer(modifier = Modifier.height(1.dp))
var commentsAlpha: Float = 0f
if ((registerUserProfileUiState.registerUserProfileErrorMessage != " ") &&
(registerUserProfileUiState.registerUserProfileErrorMessage != ""))
{
commentsAlpha = 1f
}
//Error message text
var registerUserProfileErrorMessage by remember {
mutableStateOf(
TextFieldValue(
""
)
)
}
TextField(
value = registerUserProfileErrorMessage,
onValueChange = { newErrorMessage ->
registerUserProfileErrorMessage = newErrorMessage
},
modifier = Modifier
.height(20.dp)
.focusTarget()
.alpha(commentsAlpha),
)
Spacer(modifier = Modifier.height(1.dp))
val radioOptions = listOf("Primary User", "Family Admin")
var (selectedOption, onOptionSelected) = remember { mutableStateOf(radioOptions[0]) }
Row(Modifier.selectableGroup()) {
radioOptions.forEach { text ->
Column(
Modifier//.fillMaxWidth()
.height(76.dp)
.selectable(
selected = (text == selectedOption),
onClick = { onOptionSelected(text) },
role = Role.RadioButton
)
.padding(horizontal = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
RadioButton(
selected = (text == selectedOption),
onClick = { if (text == "Primary User") {
selectedOption = "Primary User"
onOptionSelected(selectedOption)
primaryUserSelectedIn = true
familyAdminSelectedIn = false
}
else {
selectedOption = "Family Admin"
onOptionSelected(selectedOption)
primaryUserSelectedIn = false
familyAdminSelectedIn = true
}
}
)
Text(
text = text,
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier
.focusTarget()
.padding(start = 16.dp)
)
}
}
}
Spacer(modifier = Modifier.height(10.dp))
Column(
modifier = Modifier
.fillMaxSize()
.padding(vertical = 10.dp),
Arrangement.Center,
Alignment.CenterHorizontally
) {
//Last Name
var registerUserProfileLastName by remember {mutableStateOf(TextFieldValue(""))
}
OutlinedTextField(
value = registerUserProfileLastName,
label = { Text("Last Name") },
enabled = true,
onValueChange = {
registerUserProfileLastName = it
registerUserProfileViewModel.registerUserProfileLastName =
registerUserProfileLastName.toString()
registerUserProfileViewModel.registerUserProfileLastNameIn =
registerUserProfileLastName.toString()
},
modifier = Modifier
.fillMaxWidth()
.focusTarget()
.focusRequester(a)
.focusProperties {
next = b
}
.padding(10.dp),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = Blue,
unfocusedBorderColor = Blue),
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Text,
showKeyboardOnFocus = true,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
focusManager.moveFocus(FocusDirection.Down)
}
),
singleLine = true,
)
//First Name
var registerUserProfileFirstName by remember {mutableStateOf(TextFieldValue(""))
}
OutlinedTextField(
value = registerUserProfileFirstName,
label = { Text(text = "First Name") },
onValueChange = {
registerUserProfileFirstName = it
registerUserProfileViewModel.registerUserProfileFirstName =
registerUserProfileFirstName.toString()
},
modifier = Modifier
.fillMaxWidth()
.focusable(true)
.focusRequester(b)
.focusProperties {
next = c
previous = a
}
.padding(10.dp),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = Blue,
unfocusedBorderColor = Blue),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
showKeyboardOnFocus = true,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
focusManager.moveFocus(FocusDirection.Down)
}
),
singleLine = true,
)
Spacer(modifier = Modifier.width(4.dp))
//Mobile Phone
var registerUserProfileMobilePhone by remember {mutableStateOf(TextFieldValue(""))
}
OutlinedTextField(
value = registerUserProfileMobilePhone,
label = { Text(text = "Mobile Phone Number") },
onValueChange = {
registerUserProfileMobilePhone = it
registerUserProfileViewModel.registerUserProfileMobilePhone =
registerUserProfileMobilePhone.toString()
},
modifier = Modifier
.fillMaxWidth()
.focusTarget()
.focusRequester(c)
.focusProperties {
next = d
previous = b
}
.padding(10.dp),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = Blue,
unfocusedBorderColor = Blue),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Phone,
showKeyboardOnFocus = true,
imeAction = ImeAction.Next
),
keyboardActions = KeyboardActions(
onNext = {
focusManager.moveFocus(FocusDirection.Down)
}
),
singleLine = true,
visualTransformation = NanpVisualTransformation(),
)
Spacer(modifier = Modifier.width(4.dp))
//Email address
var registerUserProfileEmailAddress by remember { mutableStateOf(TextFieldValue("")) }
OutlinedTextField(
value = registerUserProfileEmailAddress,
label = { Text(text = "Email Address") },
onValueChange = {
registerUserProfileEmailAddress = it
registerUserProfileViewModel.registerUserProfileEmailAddress =
registerUserProfileEmailAddress.toString()
},
modifier = Modifier
.fillMaxWidth()
.focusTarget()
.focusRequester(d)
.focusProperties {
next = e
previous = c
}
.padding(10.dp),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = Blue,
unfocusedBorderColor = Blue),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Email,
autoCorrect = false,
showKeyboardOnFocus = true,
imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(
onNext = {
focusManager.moveFocus(FocusDirection.Down)
}
),
)
Spacer(modifier = Modifier.width(4.dp))
//Password
var registerUserProfilePassword by remember { mutableStateOf(TextFieldValue("")) }
OutlinedTextField(
value = registerUserProfilePassword,
onValueChange = {
registerUserProfilePassword = it
registerUserProfileViewModel.registerUserProfilePassword =
registerUserProfilePassword.toString()
},
label = { Text(text = "Password") },
trailingIcon = {
if (showPassword) {
IconButton(onClick = { showPassword = false }) {
Icon(
imageVector = Icons.Filled.Visibility,
contentDescription = "hide_password"
)
}
} else {
IconButton(
onClick = { showPassword = true }) {
Icon(
imageVector = Icons.Filled.VisibilityOff,
contentDescription = "hide_password"
)
}
}
},
modifier = Modifier
.fillMaxWidth()
.focusTarget()
.focusRequester(e)
.focusProperties {
next = f
previous = d
}
.padding(10.dp),
visualTransformation = if (showPassword) {
VisualTransformation.None
} else {
PasswordVisualTransformation()
},
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Password,
showKeyboardOnFocus = true,
imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(
onNext = {
focusManager.moveFocus(FocusDirection.Down)
// focusManager.moveFocus(FocusDirection.Next)
}
),
singleLine = true,
shape = RoundedCornerShape(percent = 20),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = Blue,
unfocusedBorderColor = Blue)
)
Spacer(modifier = Modifier.width(4.dp))
//Confirm Password
var registerUserProfileConfirmPassword by remember { mutableStateOf(TextFieldValue(""))}
OutlinedTextField(value = registerUserProfileConfirmPassword,
onValueChange = {
registerUserProfileConfirmPassword = it
registerUserProfileViewModel.registerUserProfileConfirmPassword =
registerUserProfileConfirmPassword.toString()
},
label = { Text(text = "Confirm Password") },
trailingIcon = {
if (showPassword) {
IconButton(onClick = { showPassword = false }) {
Icon(
imageVector = Icons.Filled.Visibility,
contentDescription = "hide_password"
)
}
} else {
IconButton(
onClick = { showPassword = true }) {
Icon(
imageVector = Icons.Filled.VisibilityOff,
contentDescription = "hide_password"
)
}
}
},
modifier = Modifier
.fillMaxWidth()
.focusTarget()
.focusRequester(f)
.focusProperties {
previous = e
}
.padding(10.dp),
visualTransformation = if (showPassword) {
VisualTransformation.None
} else {
PasswordVisualTransformation()
},
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Password,
showKeyboardOnFocus = true,
imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(
onNext = {
focusManager.moveFocus(FocusDirection.Down)
}
),
singleLine = true,
shape = RoundedCornerShape(percent = 20),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = Blue,
unfocusedBorderColor = Blue)
)
Spacer(modifier = Modifier.width(4.dp))
//Button - Next
Button(
onClick = {
_uiState.update { currentState ->
currentState.copy(
primaryUserSelected = primaryUserSelectedIn,
familyAdminSelected = familyAdminSelectedIn,
registerUserProfileLastName = registerUserProfileLastName.text,
registerUserProfileFirstName = registerUserProfileFirstName.text,
registerUserProfileMobilePhone = registerUserProfileMobilePhone.text,
registerUserProfileEmailAddress = registerUserProfileEmailAddress.text,
registerUserProfilePassword = registerUserProfilePassword.text,
registerUserProfileConfirmPassword = registerUserProfileConfirmPassword.text
)
}
Log.i(" ", "RegisterUserProfileScreen: lastname = ${_uiState.value.registerUserProfileLastName}")
coroutineScope.launch {
registerUserProfileViewModel.registerUserNextButtonOnClickListener(
uiState = _uiState)}
},
colors = ButtonDefaults.buttonColors(containerColor = Color.Blue),
shape = RoundedCornerShape(8.dp),
modifier = Modifier
.padding(8.dp)
.width(120.dp)
.height(40.dp)
) {
Text("Next")
}
Spacer(modifier = Modifier.width(4.dp))
//Fragment - Adview
AdmobBanner(modifier = Modifier.fillMaxWidth())
}
}
}
@Preview (
showSystemUi = true,
)
@PreviewScreenSizes
@Composable
fun RegisterUserProfilePreview() {
PeepsConnectionTheme {
}
}
有趣的问题。
抱歉,如果我偏离主题,但在这种情况下,您不应该在单个可组合项中编写整个屏幕代码 RegisterUserProfileScreen。如果发生重组,将会非常昂贵且令人疲惫不堪。
您可以将其分解为单一的模块化可组合方法。我已经实现了相同的功能,可以给你基本的片段。
以下只是一个基本要点,您可以根据自己的需要进行修改。
例如:-
EmailInput (emailState = email, enabled = !loading, onAction = KeyboardActions {
passwordFocusRequest.requestFocus()
}
你可以将此函数放在组件文件中,它会像:-
@Composable fun EmailInput(
modifier: Modifier = Modifier,
emailState: MutableState<String>,
labelId: String = "Email",
enabled: Boolean = true,
imeAction: ImeAction = ImeAction.Next,
onAction: KeyboardActions = KeyboardActions.Default) {
InputField(
modifier = modifier,
valueState = emailState,
labelId = labelId,
enabled = enabled,
keyboardType = KeyboardType.Email,
imeAction = imeAction,
onAction = onAction
)}
输入字段就像:-
@Composable fun InputField(
modifier: Modifier = Modifier,
valueState: MutableState<String>,
labelId: String,
enabled: Boolean,
isSingleLine: Boolean = true,
keyboardType: KeyboardType = KeyboardType.Text,
imeAction: ImeAction = ImeAction.Next,
onAction: KeyboardActions = KeyboardActions.Default) { OutlinedTextField(
value = valueState.value,
onValueChange = { valueState.value = it },
label = { Text(text = labelId) },
singleLine = isSingleLine,
textStyle = TextStyle(
fontSize = 18.sp, color = MaterialTheme.colorScheme.onBackground
),
modifier = modifier
.padding(bottom = 10.dp, start = 10.dp, end = 10.dp)
.fillMaxWidth(),
enabled = enabled,
keyboardOptions = KeyboardOptions(
keyboardType = keyboardType, imeAction = imeAction,
),
keyboardActions = onAction
)}