[Android]compose1.5.4(BOM2023.10.01) enterキー(ハード)でボタンが押せない問題
composeのバージョンをあげたら今までenterで押せていたボタンが押せなくなったりしているので調査する。
BOMを2023.6.01(compose 1.4.3)から2023.10.01(compose 1.5.4)に変更したら起きた。
bom-mapping、日本語だと古いのしか出ないので注意。自動生成でいいから最新にしてほしいな。起きてること
今までfocus+enterで発火していたButtonのonClickが呼ばれないケースがある。
(呼ばれるケースもある)
追記:
前提の情報を書き忘れていたんだけど、画面を開いた瞬間にボタンにfocusを当てたくてbuttonにfocusRequesterをセットしてrequestFocusしてます。
つまり、ButtonにFocusRequesterとfocasableをつけるとenterでonClickが呼ばれないケースがある。
とりあえずfocusableとonClickに何か起きている
androidStudioのnewProjectで作ったprojectがビルド失敗するの初心者に厳しくない?
まずfocusRequesterの挙動に違いあるんだっけ?の確認
ButtonにfocusableをつけずにrequestFocusした場合と、つけてした場合を見る。
focusRequesteの挙動としては
1.子の最初のfocasableにfocusする& Modifier.focusRequester()の下に書いたfocasableは子の最初のfocasable扱い(これは重要情報)
- なければ自分のfocasableにfocusする
だったはず。
TextはデフォルトでfocasableがないけどButtonはどうだったっけな。流石に今まではあった気がするけど…ということで実践。
a.focasableがないパターンのコード
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeButtonSampleTheme {
var button1Count by remember { mutableIntStateOf(0) }
val focusRequester = remember { FocusRequester() }
LaunchedEffect(key1 = Unit) {
focusRequester.requestFocus()
}
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(onClick = { /* no-op */ }) {
Text("Fake first Button")
}
Text(text = "ButtonCount : $button1Count")
Button(
modifier = Modifier
.focusRequester(focusRequester = focusRequester),
onClick = { button1Count = button1Count.inc() }
) {
Text("Target Button")
}
}
}
}
}
}
}
b.あるパターンのコード
略...
Button(
modifier = Modifier
.focusRequester(focusRequester = focusRequester)
.focusable(),
onClick = { button1Count = button1Count.inc() }
) {
Text("Target Button")
}
略...
compose 1.5.4
a.フォーカスされず。当然enterでonClickも呼ばれない。
b.フォーカスされる。enterでonClickも呼ばれる。
bならonClickも呼ばれるんだな…?
compose 1.4.3
a.フォーカスされず。当然enterでonClickも呼ばれない。
b.フォーカスされる。enterでonClickも呼ばれる。
1.5.4と同じだった。
あー
さっき書いた
なければ自分のfocasableにfocusする
は明示的にfocusRequesterの上にfocasableつけたらって話なのかな。
ButtonとかはclickableであってfocasableじゃないからfocusRequesterでfocusはしないけどclickableであればキーボードでのfocusは可能みたいな感じなのかな…
関係ないけど面白い(便利そうな)modifierのメソッド見つけた
もう一歩プロダクトコードに近づける。
Buttonを利用した独自のボタンを定義する
@Composable
fun OriginalButton(
modifier: Modifier
) {
var originalButtonCount by remember { mutableStateOf(0) }
Button(
modifier = modifier,
onClick = { originalButtonCount = originalButtonCount.inc() }
) {
Text("Original Button : $originalButtonCount")
}
}
でさっきのボタンの代わりに以下を入れて試します。
OriginalButton(
modifier = Modifier
.focusRequester(firstFocusRequester)
.focusable()
)
compose 1.4.3
フォーカスされる。onClickも呼ばれる。
ok
1.5.4、頼むぞ…
compose 1.5.4
同上
ん〜?
何か別の条件がある?
チョンボだったらやだなあ
プロダクトの方はMaterial3だな
やり直し…
逆だ、sampleがmaterial3だ
↑ここまでmaterial3
うーん普通に動くな
どういうこと?
ちょっくら読んでくるわ
やっぱいプロダクトだとonClick呼ばれんな。
差分があって
画面開いた瞬間、isFocusedもhasFocusもtrueなのはどちらも一緒なんだけど、sampleの方はenterを押した瞬間にOriginalButtonのisFocusedがfalseになる(hasFocusはtrueのまま)
そして中のButtonのisFocusとhasFocusがtrueになる。
これはつまりenterが押された瞬間に子のclickableまでfocusを移動して実行してるってことだと思うんだけど、なんでサンプルはそうなっていてプロダクトはそうならないの?なんでなんで?
プロダクトの方は依存の関係でcomposeのバージョン下げるのが簡単にできないのがまた難しいな
簡単にできたわ
もしかしてcomposeBomではなく何か他のバージョンかもしれないぞ
composeと合わせてあげられたなにがしのバージョンと実装のハーモニー説が濃厚になってまいりました。
疑ってごめんねcompose…
composeDestinationsを使っているんですが
"1.8.42-beta"-> "1.9.54"
へのバージョンアップ+それに伴う何かしらの変更で発生したというところまでは確定しました。
composeDestinationsの問題なのかこちらの実装の問題なのかはこれから調査します。
本当に疑ってごめんなcompose…
やっぱcomposeによる挙動の変更が関係してました。
でもこちらの実装とのハーモニーだった。
前提の情報を書き忘れていたんだけど、画面を開いた瞬間にボタンにfocusを当てたくてbuttonにfocusRequesterをセットしてrequestFocusしてます。