TextFieldStateの使い方

Kenji Abe
6 min readSep 23, 2024

--

Photo by Tim Mossholder on Unsplash

TextFieldValueに代わる新しい TextFieldStateの使い方について解説します。 TextFieldStateは新しい BasicTextField(以前は BasicTextField2と呼ばれていたものです。 BasicTextFieldリネームされてます。)で使用されることになります。

TextFieldState はCompose 1.7.0でStableになっています。

新しい BasicTextField も使い方が結構変わってますが、今回は TextFieldState のみに焦点を絞っています。
(気が向けば新しい BasicTextField ついても何か書くかも?)

基本的な使い方

単純に入力欄を作る方法です。

// TextFieldStateの作成
val textFieldState = rememberTextFieldState("test")

BasicTextField(
state = textFieldState, // BasicTextFieldに渡す
decorator = { innerTextField ->
Box(
modifier = Modifier
.fillMaxWidth()
.border(width = 1.dp, color = Color.Black)
.padding(16.dp)
) {
innerTextField()
}
},
modifier = Modifier.fillMaxWidth()
)

rememberTextFieldState を使ってまずは TextFieldState を作成します。実装をみればすぐ分かりますが、 rememberSaveable で囲ったものを作ってるだけです。引数は初期値になります。

あとはこれを BasicTextField に渡すだけです。

これまでとの大きな違いとしては、 onValueChange を使って入力欄を更新する必要がなく自動で反映されます。

ViewModelで状態を保持したい場合も特に難しくはなく、単純に以下のようにViewModelで保持しておくだけです。値の取得も text で取得できます。

// ViewModel
class MainViewModel: ViewModel() {
val textFieldState = TextFieldState("test")

fun execute() {
// 入力された値を取得
val text = textFieldState.text
// ...
}
}

// Composable
BasicTextField(
state = viewModel.textFieldState,
// ...
)

入力の監視

入力状態を監視するには、 snapshotFlow を使って text を監視します。

LaunchedEffect(Unit) {
snapshotFlow { textFieldState.text }.collectLatest {
Log.d(TAG, "text = $it")
}
}

また、入力が特定の状態を満たすかどうかを確認する場合は、 derivedStateOfを使うこともできます。

val isTest by remember {
derivedStateOf {
textFieldState.text == "test"
}
}

// "test"と入力された時だけtrueになる

テキストの編集

コードからテキストを編集する方法です。

まずは一番簡単例として、入力された値をクリアする方法です。 clearText を使うだけです。

textFieldState.clearText()

次に全体のテキストを単純に置き換える方法です。これには2つ方法があり、違いとしては変更後のカーソルになります。

// テキストを置き換えて、すべて選択された状態にする
textFieldState.setTextAndSelectAll("Sample")

// テキストを置き換えて、末尾にカーソルを移動させる
textFieldState.setTextAndPlaceCursorAtEnd("Sample")

さらに柔軟にテキストを編集する場合は edit を使います。上で紹介した編集方法はすべて edit が呼び出されています。また、 selection を使って選択状態を指定できます。

textFieldState.edit {
// 全部消す
delete(0, length)

// "Compose"を追加
append("Compose")

// "Hello, "を先頭に追加
insert(0, "Hello, ")

// "Compose"の部分を選択状態にする
selection = TextRange(7, length)
}

また、 placeCursorBeforeCharAt , placeCursorAfterCharAt , placeCursorAtEnd を使うことでカーソル位置も指定することが可能です。

IME変換状態

日本語ではキーボードから入力されてから漢字等に変換してからテキストが確定しますが、この変換中かどうかを判定する方法です。こちらも snapshotFlow を使い composition を監視します。

LaunchedEffect(Unit) {
snapshotFlow { textFieldState.composition }.collectLatest {
// null => 変換中じゃない
// TextRange => 変換中の範囲
}
}

取得される値としては、変換中じゃない場合はnullになります。変換中のときは変換中の範囲が TextRange として取得できます。

参考

--

--

Kenji Abe

Programmer / Gamer / Google Developers Expert for Android, Kotlin / @STAR_ZERO