カスタム構成可能なビュー(基本的に表面+テキスト)があり、フォーカスの状態に応じて表面の色を変更したいと思います。 FocusManager#FocusNodeは内部としてマークされており、これを達成する方法は知りません。これは単にまだまだ利用できませんか?他に誰かがこれに取り組む必要がありますか?
dev11
以降、FocusManagerAmbient
が廃止され、FocusModifier
が採用されました。その他の例については、 KeyInputDemo 、 ComposeInputFieldFocusTransition または FocusableDemo を確認してください。
@Composable
private fun FocusableText(text: MutableState<String>) {
val focusModifier = FocusModifier()
Text(
modifier = focusModifier
.tapGestureFilter { focusModifier.requestFocus() }
.keyInputFilter { it.value?.let { text.value += it; true } ?: false },
text = text.value,
color = when (focusModifier.focusState) {
Focused -> Color.Green
NotFocused -> Color.Black
NotFocusable -> Color.Gray
}
)
}
その後、ComposeはFocusManager
メンバーを更新および作成しましたpublic
;ただし、APIがdev10
の時点でどれだけ最終版かは正確にはわかりません。ただし、現時点ではFocusNode
を作成し、FocusManager.registerObserver
を使用して変更をリッスンできます。
val focusNode = remember {
FocusNode().apply {
focusManager.registerObserver(node = this) { fromNode, toNode ->
if (toNode == this) {
// has focus
} else {
// lost focus
}
}
}
}
フォーカスを取得したい場合は、FocusManager.requestFocus
を呼び出すことができます。
val focusManager = FocusManagerAmbient.current
focusManager.requestFocus(focusNode)
focusIdentifier
にFocusNode
を設定することもできます:
val focusNode = remember {
FocusNode().apply {
...
focusManager.registerFocusNode("your-focus-identifier", node = this)
}
}
特定の識別子に焦点を当てるには、FocusManager.requestFocusById
を呼び出すだけです。
これを使用すると、たとえば、フォーカスを提供および要求できるComposable
を簡単に作成できます。
@Composable
fun useFocus(focusIdentifier: String? = null): Pair<Boolean, () -> Unit> {
val focusManager = FocusManagerAmbient.current
val (hasFocus, setHasFocus) = state { false }
val focusNode = remember {
FocusNode().apply {
focusManager.registerObserver(node = this) { fromNode, toNode ->
setHasFocus(toNode == this)
}
focusIdentifier?.let { identifier ->
focusManager.registerFocusNode(identifier, node = this)
}
}
}
onDispose {
focusIdentifier?.let { identifier ->
focusManager.unregisterFocusNode(identifier)
}
}
return hasFocus to {
focusManager.requestFocus(focusNode)
}
}
val (hasFocus, requestFocus) = useFocus("your-focus-identifier")
それと一緒に子供を作成することもできます:
@Composable
fun FocusableTextButton(
text: String,
focusedColor: Color = Color.Unset,
unFocusedColor: Color = Color.Unset,
textColor: Color = Color.White,
focusIdentifier: String? = null
) {
val (hasFocus, requestFocus) = useFocus(focusIdentifier)
Surface(color = if (hasFocus) focusedColor else unFocusedColor) {
TextButton(onClick = requestFocus) {
Text(text = text, color = textColor)
}
}
}
または、FocusModifier
もあります。これは、現時点では次のとおりです。
/**
* A [Modifier.Element] that wraps makes the modifiers on the right into a Focusable. Use a
* different instance of [FocusModifier] for each focusable component.
*
* TODO(b/152528891): Write tests for [FocusModifier] after we finalize on the api (API
* review tracked by b/152529882).
*/
しかし、私はあなたが現在それで識別子を適用することができるとは思いません。
val focusModifier = FocusModifier()
val hasFocus = focusModifier.focusDetailedState == FocusDetailedState.Active
Surface(
modifier = focusModifier,
color = if (hasFocus) focusedColor else unFocusedColor
) {
TextButton(onClick = { focusModifier.requestFocus() }) {
Text(text = text, color = textColor)
}
}
とはいえ、これが現在フォーカスを処理するための意図された方法であることは100%確実ではありません。私は CoreTextField をたくさん参照して、そこでどのように処理されているかを確認しました。
例:
@Composable
fun FocusTest() {
val focusManager = FocusManagerAmbient.current
val selectRandomIdentifier: () -> Unit = {
focusManager.requestFocusById(arrayOf("red,", "blue", "green", "yellow").random())
}
Column(verticalArrangement = Arrangement.SpaceBetween) {
FocusableTextButton(
text = "When I gain focus, I turn red",
focusedColor = Color.Red,
focusIdentifier = "red"
)
FocusableTextButton(
text = "When I gain focus, I turn blue",
focusedColor = Color.Blue,
focusIdentifier = "blue"
)
FocusableTextButton(
text = "When I gain focus, I turn green",
focusedColor = Color.Green,
focusIdentifier = "green"
)
FocusableTextButton(
text = "When I gain focus, I turn yellow",
focusedColor = Color.Yellow,
focusIdentifier = "yellow"
)
Button(onClick = selectRandomIdentifier) {
Text(text = "Click me to randomly select a node to focus")
}
}
}