
前回のボタンクリックに続いて、今回もユーザー操作を受け取って表示を更新する処理を見ていきましょう。今回は文字入力欄を作ります。文字入力欄は、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入門


