Android / Kotlin / Programming

TextFieldのPlaceholderを表示させたい

Android Jetpack Composeでテキスト入力を受け付けるコンポーネントとしてTextFieldをよく使用します
そんな中でもよく使う機能としてPlaceholder(プレースホルダー)があると思います
今回はプレースホルダーを未入力の場合はずっと表示する方法を載せておきます
※厳密にはプレースホルダーではないですが

まず、初期状態の動きを確認します

var textFieldValue by rememberSaveable { mutableStateOf("") }
TextField(
    value = textFieldValue,
    onValueChange = {
        textFieldValue = it
    },
    modifier = Modifier
        .wrapContentSize(),
    textStyle = Typography.bodyMedium,
    label = {
        Text(
            text = "グループ名",
            style = Typography.labelSmall
        )
    },
    placeholder = {
        Text(
            text = "グループ名を入力",
            style = Typography.bodyMedium
        )
    }
)

プレースホルダーが表示されるのはクリックして入力する前のみになっています
クリックする前、入力をすべて消しフォーカスを外した後にもプレースホルダーを表示させる方法を下記でご紹介します

Code

いきなりですがコードと実際の動きはこちらです

var textFieldValue by rememberSaveable { mutableStateOf("グループ名を入力") }
TextField(
    value = textFieldValue,
    onValueChange = {
        textFieldValue = it
    },
    modifier = Modifier
        .wrapContentSize()
        .onFocusChanged {
             if (!it.isFocused) {
                textFieldValue = textFieldValue.ifEmpty { "グループ名を入力" }
            }
            
            if (!it.isFocused || textFieldValue != "グループ名を入力") return@onFocusChanged
            textFieldValue = ""
        }
        .defaultMinSize(
            minWidth = TextFieldDefaults.MinWidth,
            minHeight = TextFieldDefaults.MinHeight
        ),
    textStyle = Typography.bodyMedium,
    label = {
        Text(
            text = "グループ名",
            style = Typography.labelSmall
        )
    },
    placeholder = {
        Text(
            text = "グループ名を入力",
            style = Typography.bodyMedium
        )
    }
)

詳細

クリック前の表示

var textFieldValue by rememberSaveable { mutableStateOf("グループ名を入力") }
TextField(
    value = textFieldValue,
    onValueChange = {
        textFieldValue = it
    },
    modifier = Modifier
        .wrapContentSize()
        .onFocusChanged {
             if (!it.isFocused) {
                textFieldValue = textFieldValue.ifEmpty { "グループ名を入力" }
            }
            
            if (!it.isFocused || textFieldValue != "グループ名を入力") return@onFocusChanged
            textFieldValue = ""
        }

こちらを実現するために、valueの初期値として「グループ名を入力」を設定しています
しかし、このままでは入力を開始した際に初期値が入力欄に存在してしまいます
そこでフォーカスされた際に現状の入力値が初期値と同じである場合にのみ入力欄をクリアしています

入力をすべて消しフォーカスを外した後の表示

var textFieldValue by rememberSaveable { mutableStateOf("グループ名を入力") }
TextField(
    value = textFieldValue,
    onValueChange = {
        textFieldValue = it
    },
    modifier = Modifier
        .wrapContentSize()
        .onFocusChanged {
             if (!it.isFocused) {
                textFieldValue = textFieldValue.ifEmpty { "グループ名を入力" }
            }
            
            if (!it.isFocused || textFieldValue != "グループ名を入力") return@onFocusChanged
            textFieldValue = ""
        }

上記のままでは何も入力していない状態で他のコンポーネントにフォーカスを移すと、プレースホルダーライクが表示されません
これを避けるため、フォーカスされている状態以外のタイミングで入力値が空であれば初期値を入力するように設定しています

おわりに

上記がプレースホルダーライクな表示を出し続ける方法です
問題点として、もしユーザーが初期値と全く同じ値(例の場合は「グループ名を入力」)を入力した場合に、入力し忘れか入力済みかの判定ができません
回避策としては、コンポーネントをクリックした後はプレースホルダーライクを表示しない、入力確認画面を別途用意するなどかなぁと思ってます

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です