ユーザー入力を処理する

TextField: ユーザーはテキストを入力、変更できます。このページでは、TextField の実装、TextField 入力のスタイルの設定、その他の TextField オプションの設定(キーボード オプション、ユーザー入力の視覚的な変換など)を行う方法について説明します。

TextField の実装を選択する

TextField の実装には、次の 2 つのレベルがあります。

  1. TextField はマテリアル デザインの実装であり、この実装は、マテリアル デザイン ガイドラインに沿って選択することをおすすめします。
    • デフォルトのスタイル設定は塗りつぶしです。
    • OutlinedTextField は、枠線のスタイル設定バージョンです。
  2. BasicTextField を使用すると、ユーザーはハードウェア キーボードまたはソフトウェア キーボードでテキストを編集できますが、ヒントやプレースホルダなどの装飾は表示されません。

@Composable
fun SimpleFilledTextFieldSample() {
    var text by remember { mutableStateOf("Hello") }

    TextField(
        value = text,
        onValueChange = { text = it },
        label = { Text("Label") }
    )
}

次の単語を含む編集可能なテキスト フィールド

@Composable
fun SimpleOutlinedTextFieldSample() {
    var text by remember { mutableStateOf("") }

    OutlinedTextField(
        value = text,
        onValueChange = { text = it },
        label = { Text("Label") }
    )
}

紫色の枠線とラベルが付いた編集可能なテキスト フィールド。

スタイルTextField

TextFieldBasicTextField は、カスタマイズ用のパラメータを多数共有しています。TextField の完全なリストは、TextField ソースコードにあります。有用なパラメータの一部を以下に示します。

  • singleLine
  • maxLines
  • textStyle

@Composable
fun StyledTextField() {
    var value by remember { mutableStateOf("Hello\nWorld\nInvisible") }

    TextField(
        value = value,
        onValueChange = { value = it },
        label = { Text("Enter text") },
        maxLines = 2,
        textStyle = TextStyle(color = Color.Blue, fontWeight = FontWeight.Bold),
        modifier = Modifier.padding(20.dp)
    )
}

ラベルと 2 つの編集可能な行がある、複数行の TextField

デザインで TextField または OutlineTextField が必要な場合は、BasicTextField ではなく TextField をおすすめします。ただし、マテリアル仕様の装飾を必要としないデザインを作成する場合は、BasicTextField を使用する必要があります。

Brush API による入力のスタイル設定

TextFieldBrush API を使用すると、より高度なスタイル設定が可能です。次のセクションでは、ブラシを使用して TextField 入力にカラー グラデーションを追加する方法について説明します。

Brush API を使用してテキストのスタイルを設定する方法について詳しくは、Brush API で高度なスタイル設定を有効にするをご覧ください。

TextStyle を使用してカラー グラデーションを実装する

TextField 内での入力時にカラー グラデーションを実装するには、使用するブラシを TextFieldTextStyle に設定します。この例では、linearGradient が設定された組み込みのブラシを使用して、TextField にテキストが入力されるときにレインボー グラデーション効果を表示します。

var text by remember { mutableStateOf("") }
val brush = remember {
    Brush.linearGradient(
        colors = rainbowColors
    )
}
TextField(
    value = text, onValueChange = { text = it }, textStyle = TextStyle(brush = brush)
)

buildAnnotatedString と SpanStyle を linearGradient とともに使用して、テキストの一部のみをカスタマイズする。
図 3.buildAnnotatedStringSpanStylelinearGradient とともに使用し、テキストの一部のみをカスタマイズする。

キーボード オプションを設定する

TextField を使用すると、キーボード レイアウトなどのキーボード構成オプションを設定できます。また、キーボードでサポートされている場合は、自動修正を有効にすることも可能です。ソフトウェア キーボードが次に示すオプションに対応していない場合、一部のオプションは保証されない可能性があります。サポートされているキーボード オプションの一覧を次に示します。

  • capitalization
  • autoCorrect
  • keyboardType
  • imeAction

入力をフォーマットする

TextField を使用すると、入力値に VisualTransformation を設定できます。たとえば、パスワードの文字を * で置き換えたり、クレジット カード番号の 4 桁の数字ごとにハイフンを挿入したりできます。

@Composable
fun PasswordTextField() {
    var password by rememberSaveable { mutableStateOf("") }

    TextField(
        value = password,
        onValueChange = { password = it },
        label = { Text("Enter password") },
        visualTransformation = PasswordVisualTransformation(),
        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
    )
}

文字がマスクされたパスワード入力欄

その他の例については、VisualTransformationSamples ソースコードをご覧ください。

クリーンな入力

テキストを編集する場合の一般的なタスクは、先頭の文字列を削除することか、あるいは変更されるたびに入力文字列を変換することです。

一つのモデルとして、onValueChange ごとにキーボードから任意の大幅な編集がなされる場合を考える必要があります。たとえば、ユーザーが自動修正や、単語の絵文字への置き換えなど、高度な編集機能を使用する場合です。これを適切に処理するには、今回 onValueChange に渡されるテキストは、前回または次回 onValueChange に渡される値と無関係であるという前提で、変換ロジックを作成します。

また、先頭のゼロを禁止するテキスト フィールドを実装するには、値が変更されるたびに先頭のゼロをすべて削除します。

@Composable
fun NoLeadingZeroes() {
    var input by rememberSaveable { mutableStateOf("") }
    TextField(
        value = input,
        onValueChange = { newText ->
            input = newText.trimStart { it == '0' }
        }
    )
}

テキストを削除する際にカーソルの位置を制御するには、状態の一部として TextFieldTextFieldValue オーバーロードを使用します。

状態に関するベスト プラクティス

アプリで入力に関する問題を回避するために、TextField の状態を定義して更新するための、一連のおすすめの方法を以下に示します。

  • MutableState を使用して TextField 状態を表現する: StateFlow などのリアクティブ ストリームを使用して TextField 状態を表現しないでください。このような構造では非同期の遅延が発生する可能性があります。

class SignUpViewModel : ViewModel() {

    var username by mutableStateOf("")
        private set

    /* ... */
}

  • 遅延を回避して状態を更新する: onValueChange を呼び出したら、TextField を同期的かつ直ちに更新します。

// SignUpViewModel.kt

class SignUpViewModel(private val userRepository: UserRepository) : ViewModel() {

    var username by mutableStateOf("")
        private set

    fun updateUsername(input: String) {
        username = input
    }
}

// SignUpScreen.kt

@Composable
fun SignUpScreen(/*...*/) {

    OutlinedTextField(
        value = viewModel.username,
        onValueChange = { username -> viewModel.updateUsername(username) }
        /*...*/
    )
}

  • 状態を定義する場所: TextField の状態の入力時にビジネス ロジックの検証が必要な場合は、状態を ViewModel にホイスティングすることをおすすめします。そうでない場合は、コンポーザブルまたは状態ホルダークラスを信頼できる情報源として使用できます。状態をホイスティングする場所の詳細については、状態ホイスティングのドキュメントをご覧ください。