読者です 読者をやめる 読者になる 読者になる

ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

OnEditorActionListener を使って EditText への Enter キー入力やアクション入力をハンドルする

Android アプリ プラクティス

EditText への Enter キー入力を検知して何か処理をしたい、ということを調べてみると、TextView.OnEditorActionListenerTextView#setOnEditorActionListener メソッド で設定すればよいというようなブログ記事がいくつか見つかる。

editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        // ... 処理 ...
        return false;
    }
});

ただ、ここら辺の記事を読んでも (一番下の記事以外は) onEditorAction メソッドの第 2 引数 actionId が何であるかや、第 3 引数 eventnull になりうることについての言及がなかったりして情報として不十分だったので、調べたことを書き残しておく。

TextView#setOnEditorActionListener メソッドとは

Javadoc には次のように書かれている。

Set a special listener to be called when an action is performed on the text view. This will be called when the enter key is pressed, or when an action supplied to the IME is selected by the user.

TextView | Android Developers

すなわち、Enter キーが入力されたときや IME に提供されているアクションが選択されたときに呼ばれるコールバック処理を設定するものである。 アクションについては後述する。 コールバック処理は TextView.OnEditorActionListener#onEditorAction(TextView v, int actionId, KeyEvent event) メソッド として記述される。

引数の actionId は、選択されたアクションを識別するための ID である。 Enter キー入力の場合は EditorInfo.IME_NULL になる。

第 3 引数 event には、Enter キー入力の場合にのみ null でない値が渡される。

また、Enter キー入力の場合には、キーダウン時とキーアップ時の 2 回 onEditorAction メソッドが呼ばれるようである。

アクションとは

IME に提供されるアクションについては、次のドキュメントに書かれている。

EditText複数行を受け付けない場合に、多くのソフトウェアキーボードでは Enter キーの代わりにアクションボタンが表示されるようである。 デフォルトでは 「Next」 や 「Done」 が表示される。 EditText 要素の android:imeOptions 属性を使って、「Next」 や 「Done」 ではなく 「Go」 や検索ボタンを表示させることもできる。

上で説明した TextView#setOnEditorActionListener メソッドを使うことで、次のような感じでアクションをハンドルできる。

editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        boolean handled = false;
        if (actionId == EditorInfo.IME_ACTION_DONE) {
            // ... なんかの処理 ...
            handled = true;
        }
        return handled; // このメソッド中でアクションを消化したら true を返す。
    }
});

IME については詳しくないのでわからないのだけれど、『Most soft input methods provide a user action button in the bottom corner』 って書かれているので、おそらく IME の実装次第ではアクションボタンが提供されないこともある気がする。

あと、当然ながらハードウェアキーボードしかない場合はユーザーがアクションを実行することはできない。

OnEditorActionListener#onEditorAction メソッドについてのプラクティス

  • Enter キー入力以外では、第 3 引数 eventnull になるので、気を付ける必要がある。
    • アプリケーション側でアクションを指定していなくても (例えば android:imeOptions="actionNone" を指定していても)、IME の実装によっては勝手にアクションをユーザーに提供することもある *1 ので、eventnull になり得ないつもりでコードを書いてはいけない。
  • ソフトウェアキーボードの Enter キー入力では OnEditorActionListener#onEditorAction メソッドが呼ばれないことがある。
  • 結論として、「EditText での Enter 入力時に (改行させずに) 何か処理をするようにしたい」 という場合、次のようにすべきだと思われる。 *3
    • EditText 要素の android:inputType 属性を設定し、複数行入力をできないようにする。
    • EditText 要素の android:imeOptions 属性に actionNone 以外の値を設定し、IME にアクションを提供する。 (あるいは独自のアクションを指定するとか。)
    • onEditorAction メソッドでは、アクションを受け取った場合の処理 (ソフトウェアキーボード用) と Enter キー入力を受け取った場合 (ハードウェアキーボード用) の両方の処理を書いておく。
      • このとき、Enter キー入力については onEditorAction メソッドが 2 回 (action=ACTION_DOWN と action=ACTION_UP) 呼ばれる可能性を考慮してコードを書いた方が良さそう。 (どういう条件でそうなるかはわかってないけど、1 回しか呼ばれないこともあれば 2 回呼ばれることもあるっぽい。)
    • IME の実装次第ではアクションボタンが表示されず、Enter キー入力では onEditorAction メソッドが呼ばれないということもありうると思うので、onEditorAction メソッドが呼ばれなくても次に進むための方法をユーザーに与えておくべき。 (「検索」 ボタンを配置しておく、とか。)

挙動については確証がない部分もあるけど、上のような感じで実装すれば問題はないはず。

Android Pattern Cookbook マーケットで埋もれないための差別化戦略

Android Pattern Cookbook マーケットで埋もれないための差別化戦略

*1:Nexus 7 (2013 年版) の 「英語 (米国) Google キーボード」 で確認した。

*2:Nexus 7 (2013 年版) の 「英語 (米国) Google キーボード」 を使っている場合、Enter キー入力ではコールバックメソッドが呼ばれないことを確認した。

*3:以下ではレイアウト XML 中に属性として記述する方法を書いているが、Java 上で同様のことをするようにしても良い。