前回のボタンクリックに続いて、今回もユーザー操作を受け取って表示を更新する処理を見ていきましょう。今回は文字入力欄を作ります。文字入力欄は、TextField
またはOutlinedTextField
を使って作成します。
目次
TextFieldとOutlinedTextField
文字入力欄を作るためのコンポーネントも、他の多くのコンポーネントと同じくandroidx.compose.materialパッケージに定義されています。TextField
とOutlinedTextField
という見た目の異なる2種類の文字入力欄のコンポーネントが用意されています。名前から想像すると、TextField
のほうがノーマルな文字入力欄っぽいのですが、実際はOutlinedTextField
の方がシンプルな見た目になっています。TextField
の方は、OutlinedTextField
よりも見た目が強調され、文字入力欄であることが分かりやすいようになっています。
定義はほとんど同じです。違うのは最後の2つ、shape
とcolors
だけです。shape
とcolors
のcompanion propertyを定義しておけば、関数定義を分けるほどでもないのでは?という気もしますが、、、まあせっかく2種類あるので、場面に応じて使い分けましょう。Developer Guide曰く、いろんなコンテンツに囲まれている文字入力欄は、目立たせるためにTextField
を使い、文字入力欄がたくさん並んでいるようなUIでは、うるさくならないようにOutlinedTextField
を使いましょう、とのことです。
@Composable
fun TextField(
value: String?,
onValueChange: ((String) -> Unit)?,
modifier: Modifier? = Modifier,
enabled: Boolean? = true,
readOnly: Boolean? = false,
textStyle: TextStyle? = LocalTextStyle.current,
label: (@Composable () -> Unit)? = null,
placeholder: (@Composable () -> Unit)? = null,
leadingIcon: (@Composable () -> Unit)? = null,
trailingIcon: (@Composable () -> Unit)? = null,
isError: Boolean? = false,
visualTransformation: VisualTransformation? = VisualTransformation.None,
keyboardOptions: KeyboardOptions? = KeyboardOptions.Default,
keyboardActions: KeyboardActions? = KeyboardActions(),
singleLine: Boolean? = false,
maxLines: Int? = Int.MAX_VALUE,
interactionSource: MutableInteractionSource? = remember { MutableInteractionSource() },
shape: Shape? = MaterialTheme.shapes.small.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize),
colors: TextFieldColors? = TextFieldDefaults.textFieldColors()
): Unit
@Composable
fun OutlinedTextField(
value: String?,
onValueChange: ((String) -> Unit)?,
modifier: Modifier? = Modifier,
enabled: Boolean? = true,
readOnly: Boolean? = false,
textStyle: TextStyle? = LocalTextStyle.current,
label: (@Composable () -> Unit)? = null,
placeholder: (@Composable () -> Unit)? = null,
leadingIcon: (@Composable () -> Unit)? = null,
trailingIcon: (@Composable () -> Unit)? = null,
isError: Boolean? = false,
visualTransformation: VisualTransformation? = VisualTransformation.None,
keyboardOptions: KeyboardOptions? = KeyboardOptions.Default,
keyboardActions: KeyboardActions? = KeyboardActions.Default,
singleLine: Boolean? = false,
maxLines: Int? = Int.MAX_VALUE,
interactionSource: MutableInteractionSource? = remember { MutableInteractionSource() },
shape: Shape? = MaterialTheme.shapes.small,
colors: TextFieldColors? = TextFieldDefaults.outlinedTextFieldColors()
): Unit
文字入力を反映させる
ここからはOutlinedTextField
を使って説明していきますが、TextField
でも同じです。
実際にOutlinedTextField
を使って文字入力欄を作っていきます。ソースコードはこんな感じです。
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.TopCenter
) {
var text by remember { mutableStateOf("") }
OutlinedTextField(
value = text,
onValueChange = { text = it },
modifier = Modifier.padding(20.dp)
)
}
「ボタンクリックでUIを更新する」の回で、by remember { mutableStateOf() }
で変数を宣言することによって変数の更新をJetpack Composeが監視し、更新を検出するとUIが再構築され、表示に反映されると学びました。TextField
でもやり方は同じです。
文字入力を扱うので、String
型の変数が必要です。mutableStateOf("")
で空の文字列を使って初期化しているので、text
はString
型の変数になります。
OutlinedTextField()
のvalue
変数は表示する文字列を指定する引数です。空文字で初期化したtext
を渡しているので、初期状態では空欄になります。空文字以外で初期化すれば、最初から文字が入力された状態で表示されます。
onValueChange
引数は、ユーザーの文字入力により値が変化したときに呼び出されるコールバック関数です。コールバック関数の引数は変化後の文字列です。text = it
で変化後の文字列をtext
に代入しています。(Kotlinではラムダ式の引数定義を省略した場合、it
で引数にアクセスできます。)するとJetpack Composeがtext
の変化を検出し、UIを再構築し、TextField
を再描画します。この一連の処理の結果、ユーザーが入力した文字が入力欄に表示されます。
カスタマイズ
入力欄の説明(labelとplaceholder)
label
引数は、入力欄の説明です。コンポーザブル関数で指定します。単純な文字列で事足りることがほとんどだと思いますが、その場合はラムダ内にText()
を書けばよいです。labelで指定した文字列は、TextFieldに文字が入力されていない場合は入力欄に表示され、文字が入力されると入力欄の左上に小さく表示されます。
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.TopCenter
) {
var text by remember { mutableStateOf("") }
OutlinedTextField(
value = text,
onValueChange = { text = it },
modifier = Modifier.padding(20.dp),
label = { Text(text = "Label") }
)
}
placeholder
は、TextField
が空欄の時に表示する入力例です。lebel
と同様にコンポーザブル関数を渡しますが、多くの場合はText
でよいと思います。placeholder
の場合はlabel
と違って、文字を入力すると消えます。
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.TopCenter
) {
var text by remember { mutableStateOf("") }
OutlinedTextField(
value = text,
onValueChange = { text = it },
modifier = Modifier.padding(20.dp),
placeholder = { Text(text = "Placeholder") }
)
}
label
とplaceholder
を両方指定すると、TextFieldにフォーカスが当たっていなくて文字が入力されていない場合はlabel
が入力欄に表示され、フォーカスが当たるとlabel
は小さくなってplaceholder
が表示され、文字を入力するとplaceholder
が消えます。個人的にはせわしない感じがしてしまうので、label
かplaceholder
のどちらかを目的に合わせて使うほうがいいかなと思います。
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.TopCenter
) {
var text by remember { mutableStateOf("") }
OutlinedTextField(
value = text,
onValueChange = { text = it },
modifier = Modifier.padding(20.dp),
label = { Text(text = "Label") },
placeholder = { Text(text = "Placeholder")}
)
}
改行の有無(singleLine)
singleLine
引数は、改行を許可するかどうかを指定します。デフォルトではfalse
です。
false
の場合、複数行の入力が可能になります。右端まで到達すると自動で改行されます。また、キーボードに改行キーが表示され、手動で改行することもできます。TextFieldの高さは、modifier
等で指定していない場合は、入力文字の行数に合わせて自動的に調整されます。TextField
のサイズを制限する必要がある場合は、maxLines
引数と組み合わせて使います。ただしmaxLines
引数はTextField
の表示行数を制限するだけで、入力自体は何行でもできてしまいます。maxLines
を指定している場合や、modifier
等で高さを指定している場合で、入力行数が表示可能な行数を超えた場合は、スクロールします。
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.TopCenter
) {
var text by remember { mutableStateOf("one two three four five") }
OutlinedTextField(
value = text,
onValueChange = { text = it },
modifier = Modifier.padding(20.dp).width(200.dp),
singleLine = false,
maxLines = 5
)
}
true
の場合、1行しか入力ができません。右端まで到達すると、スクロールします。キーボードの改行キーは表示されません。maxLines
引数は無効になります。
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.TopCenter
) {
var text by remember { mutableStateOf("one two three four ") }
OutlinedTextField(
value = text,
onValueChange = { text = it },
modifier = Modifier.padding(20.dp).width(200.dp),
singleLine = true
)
}
まとめ
今回はTextField
やOutlinedTextField
を使って文字入力欄を作る方法を説明しました。文字が入力されたことを検出して表示に反映させる方法や、ラベルやプレースホルダーの設定方法、入力欄の行数の設定方法についても説明しました。
Jetpack Compose入門