1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Jetpack Compose】TextFieldにタップイベントを設定するときの落とし穴と解決策

Posted at

はじめに

Jetpack ComposeのTextFieldには、デフォルトでタップするとフォーカスを取得し、キーボードを開くためのイベントが設定されています。

キーボード入力ではなく、別のイベント(例:DatePickerDialogを開く)を設定したい場合、

  • readOnly = trueを設定する
  • Modifier.clickableを設定する

ことで対応できるのでは?と思いました。

しかし、実際に実装してみると
タップしても反応しないという問題に遭遇しました。

この記事では、その原因と解決策を整理していきます。

やりたいことと出てきた課題

今回はOutlinedTextFieldを使って、以下のような UI を実現したいと考えていました。

  • 見た目はOutlinedTextField
    • DatePickerDialogで選択した日付を表示する
  • フォームをタップするとDatePickerDialogを起動する
  • キーボードから直接入力はできない

上記を実現するために、次のような実装でいけると思いました。

OutlinedTextField(
    value = value,
    onValueChange = {},
    readOnly = true,
    modifier = Modifier.clickable {
        // DatePickerDialog を起動する処理
        onOpenDialog()
    }
)

しかし、実際にはタップしてもonClick内の処理が呼ばれず、DatePickerDialogが起動しませんでした。

原因を調べると、TextField自体がデフォルトでキーボードを起動するイベントを設定しており、そことイベント設定が競合して無効になっていることがわかりました。

解決策

解決策として、ジェスチャーを低レベルで検出できるModifier.pointerInputを使いました。

pointerInputを使うことで、TextFieldが内部でイベントを処理する前の段階でタップを検知できます。

OutlinedTextField(
    value = value,
    onValueChange = {},
    readOnly = true,
    modifier = Modifier.pointerInput(Unit) {
        // ジェスチャーの処理を監視
        awaitEachGesture {
            // タップ開始(DOWN)
            awaitFirstDown(pass = PointerEventPass.Initial)

            // タップ終了(UP)またはキャンセルを待つ
            val up = waitForUpOrCancellation(pass = PointerEventPass.Initial)

            // 正常にタップされた場合のみ処理
            if (up != null) {
                onOpenDialog()
            }
        }
    }
)

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?