Каков самый простой способ установить порядок фокуса в Jetpack Compose?
У меня есть столбец текстовых полей, например:
Column {
TextField(
value = ...,
onValueChange = { ... },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.next),
)
TextField(
value = ...,
onValueChange = { ... },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.next),
)
.
.
.
}
Я хотел бы, чтобы каждое поле TextField перемещалось к следующему, когда пользователь нажимает Tab или следующую кнопку на клавиатуре. В настоящее время нажатие клавиши Tab вставляет вкладку в текстовое поле. Нажатие следующей кнопки ничего не делает. Я могу создать FocusRequester для каждого TextField и настроить keyboardActions onNext для запроса фокуса на следующем поле для каждого из них. Это немного утомительно и не касается поведения вкладок.
6 ответов
Недавно я нашел эту статью: https://medium.com/google-developer-experts/focus-in-jetpack-compose-6584252257fe
Он объясняет другой способ обработки фокуса, который немного проще.
val focusManager = LocalFocusManager.current
TextField(
modifier = Modifier
.onKeyEvent {
if (it.key.keyCode == Key.Tab.keyCode){
focusManager.moveFocus(FocusDirection.Next)
true
} else {
false
}
},
value = text,
onValueChange = { it -> text = it },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(
onNext = { focusManager.moveFocus(FocusDirection.Next) }
)
)
Не уверен, что это проще, но вы можете создать
FocusRequester
объект для каждого поля и запросите фокус в нужном вам порядке.
@Composable
fun FocusRequestScreen() {
// Create FocusRequesters... (you can use createRefs function)
val focusRequesters = List(3) { FocusRequester() }
Column {
TextFieldWithFocusRequesters(focusRequesters[0], focusRequesters[1])
TextFieldWithFocusRequesters(focusRequesters[1], focusRequesters[2])
TextFieldWithFocusRequesters(focusRequesters[2], focusRequesters[0])
}
}
@Composable
private fun TextFieldWithFocusRequesters(
focusRequester: FocusRequester,
nextFocusRequester: FocusRequester
) {
var state by rememberSaveable {
mutableStateOf("Focus Transition Test")
}
TextField(
value = state,
onValueChange = { text -> state = text },
// Here it is what you want...
modifier = Modifier
.focusOrder(focusRequester) {
nextFocusRequester.requestFocus()
}
,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next)
)
}
Я получаю этот код отсюда . Но это не решило проблему с вкладками ... :(
Я сейчас на
compose_version = '1.0.2'
.
Фокус не перемещается, когда вы нажимаете следующую кнопку, потому что, хотя действие клавиатуры по умолчанию заключается в перемещении фокуса на следующую , compose, похоже, не знает, какая из них должна быть следующей. Создание
FocusRequester
s для каждого элемента и установите порядок их фокусировки с помощью
Modifier.focusOrder() {}
может работать (кстати, не нужно устанавливать
onNext
чтобы запросить фокус, если вы выбираете этот способ), но поскольку ваши s находятся в том же
Column
, вы можете просто установить
keyboardActions
чтобы сказать составить, переместите фокус на тот, который находится в нижнем направлении. Что-то вроде:
Column {
val focusManager = LocalFocusManager.current
TextField(
value = "", onValueChange = {},
keyboardOptions = KeyboardOptions( imeAction = ImeAction.Next ),
keyboardActions = KeyboardActions(
onNext = { focusManager.moveFocus(FocusDirection.Down) }
)
)
TextField(
value = "", onValueChange = {},
keyboardOptions = KeyboardOptions( imeAction = ImeAction.Next ),
keyboardActions = KeyboardActions(
onNext = { focusManager.moveFocus(FocusDirection.Down) }
)
)
TextField(
value = "", onValueChange = {},
keyboardOptions = KeyboardOptions( imeAction = ImeAction.Next ),
keyboardActions = KeyboardActions(
onNext = { focusManager.moveFocus(FocusDirection.Down) }
)
)
}
После этого должна сработать следующая кнопка на клавиатуре IME.
Для Tabключа, поскольку
TextField
не обрабатывает Tabключ автоматически, поэтому вы можете использовать
focusManager
внутри
Modifier.onKeyEvent{}
для перемещения фокуса так же, как в приведенном выше примере.
О порядке вы можете проверить ответ @nglauber .
Чтобы использовать клавишу Tab, вы можете использовать <strong> <tcode id="52899154"></tcode></strong>модификатор .
TextField(
modifier = Modifier
.focusRequester(focusRequester)
.onKeyEvent {
if (it.key.keyCode == Key.Tab.keyCode){
focusRequesterNext.requestFocus()
true //true -> consumed
} else false },
value = text,
onValueChange = { it -> text = it },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(
onNext = {focusRequesterNext.requestFocus()}
)
)
Установите singleLine , попробуйте
OutlinedTextField(
...
singleLine = true,
)
Простой пример
@Composable
fun Test() {
val focusManager = LocalFocusManager.current
var text1 by remember {
mutableStateOf("")
}
var text2 by remember {
mutableStateOf("")
}
Column() {
OutlinedTextField(value = text1, onValueChange = {
text1 = it
},
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Next,
keyboardType = KeyboardType.Text
),
keyboardActions = KeyboardActions(
onNext ={
focusManager.moveFocus(FocusDirection.Down)
}
),
singleLine = true
)
OutlinedTextField(value = text2, onValueChange = {
text2 = it
},
keyboardOptions = KeyboardOptions(
imeAction = ImeAction.Next,
keyboardType = KeyboardType.Text
),
keyboardActions = KeyboardActions(
onNext ={
focusManager.moveFocus(FocusDirection.Down)
}
),
singleLine = true
)
}
}
Кажется, у Google есть рекомендуемый подход, который еще не был предложен - https://developer.android.com/jetpack/compose/touch-input/focus/change-focus-traversal-order .
val (first, second, third, fourth) = remember { FocusRequester.createRefs() }
Column {
Row {
TextButton(
{},
Modifier
.focusRequester(first)
.focusProperties { next = second }
) {
Text("First field")
}
TextButton(
{},
Modifier
.focusRequester(third)
.focusProperties { next = fourth }
) {
Text("Third field")
}
}
Row {
TextButton(
{},
Modifier
.focusRequester(second)
.focusProperties { next = third }
) {
Text("Second field")
}
TextButton(
{},
Modifier
.focusRequester(fourth)
.focusProperties { next = first }
) {
Text("Fourth field")
}
}
}