ちょっと優しい入力項目
DESCRIPTION
Potatotips#3で発表したAndroidのTips。TRANSCRIPT
![Page 1: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/1.jpg)
ちょっと優しい 入力項目
2014/1/15 @sakebook
http://sakebook.blogspot.com https://github.com/sakebook
![Page 2: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/2.jpg)
こういうときありますよね
enterを押すとどうなるか?
![Page 3: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/3.jpg)
2行になっちゃいます
よくある回避方法・SingleLine属性を設定
<EditText android:id=“@+id/edittext_1" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true" android:hint=“@string/do_not_enter“/>
![Page 4: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/4.jpg)
複数ある場合はどうするか?
・SingleLine属性を設定
⬇
「4」の位置に移動してしまう! 「2」の位置に移動させたい。。
![Page 5: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/5.jpg)
複数ある場合はどうするか?
・SingleLine属性を設定
+
・NextFocusを指定
・OnEditorActionListener を設定
+
![Page 6: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/6.jpg)
複数ある場合はどうするか?
・SingleLine属性を設定・NextFocusDownを指定
<EditText android:id=“@+id/edittext_1" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true" android:nextFocusDown=“@+id/edittext_2” android:hint=“@string/do_not_enter“/>
![Page 7: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/7.jpg)
複数ある場合はどうするか?
・OnEditorActionListener を設定
((EditText)view.findViewById(R.id.edittext_1)).setOnEditorActionListener(new OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { //SingleLineを設定したときはeventがnull if (event == null) { if (actionId == EditorInfo.IME_ACTION_NEXT) { }else if (actionId == EditorInfo.IME_ACTION_DONE) { //対象のViewより下にFocusできる物がなければこちら //「7」「8」「9」 } return false; }else { if (event.getAction() == KeyEvent.ACTION_DOWN) { return false; } } return true; } });
![Page 8: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/8.jpg)
複数ある場合はどうするか?
((EditText)view.findViewById(R.id.edittext_1)).setOnEditorActionListener(new OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { //SingleLineを設定したときはeventがnull if (event == null) { if (actionId == EditorInfo.IME_ACTION_NEXT) { }else if (actionId == EditorInfo.IME_ACTION_DONE) { //対象のViewより下にFocusできる物がなければこちら //「7」「8」「9」 } return false; }else { if (event.getAction() == KeyEvent.ACTION_DOWN) { return false; } } return true; } });
なんでkeyEventがnullになるの? !
onKeyListenerじゃだめなの?
・OnEditorActionListener を設定
![Page 9: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/9.jpg)
private int doKeyDown(int keyCode, KeyEvent event, KeyEvent otherEvent) { if (!isEnabled()) { return 0; } ! switch (keyCode) { case KeyEvent.KEYCODE_ENTER: mEnterKeyIsDown = true; if (event.hasNoModifiers()) { // When mInputContentType is set, we know that we are // running in a "modern" cupcake environment, so don't need // to worry about the application trying to capture // enter key events. if (mInputContentType != null) { // If there is an action listener, given them a // chance to consume the event. if (mInputContentType.onEditorActionListener != null && mInputContentType.onEditorActionListener.onEditorAction( this, EditorInfo.IME_NULL, event)) { mInputContentType.enterDown = true; // We are consuming the enter key for them. return -1; } } ! // If our editor should move focus when enter is pressed, or // this is a generated event from an IME action button, then // don't let it be inserted into the text. if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0 || shouldAdvanceFocusOnEnter()) { if (mOnClickListener != null) { return 0; } return -1; } } break;
TextView.javaOnKeyListener
KeyDown
![Page 10: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/10.jpg)
@Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (!isEnabled()) { return super.onKeyUp(keyCode, event); } ! switch (keyCode) { ~~ case KeyEvent.KEYCODE_ENTER: mEnterKeyIsDown = false; if (event.hasNoModifiers()) { if (mInputContentType != null && mInputContentType.onEditorActionListener != null && mInputContentType.enterDown) { mInputContentType.enterDown = false; if (mInputContentType.onEditorActionListener.onEditorAction( this, EditorInfo.IME_NULL, event)) { return true; } } ! if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0 || shouldAdvanceFocusOnEnter()) { /* * If there is a click listener, just call through to * super, which will invoke it. * * If there isn't a click listener, try to advance focus, * but still call through to super, which will reset the * pressed state and longpress state. (It will also * call performClick(), but that won't do anything in * this case.) */ ~~ } return super.onKeyUp(keyCode, event); } break;
TextView.javaOnKeyListener
onKeyListenerでは EditorActionが2回呼ばれる
Overrideすると、OnEditorActionが呼ばれない
KeyUp
![Page 11: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/11.jpg)
private int doKeyDown(int keyCode, KeyEvent event, KeyEvent otherEvent) { if (!isEnabled()) { return 0; } ! switch (keyCode) { case KeyEvent.KEYCODE_ENTER: mEnterKeyIsDown = true; if (event.hasNoModifiers()) { // When mInputContentType is set, we know that we are // running in a "modern" cupcake environment, so don't need // to worry about the application trying to capture // enter key events. if (mInputContentType != null) { // If there is an action listener, given them a // chance to consume the event. if (mInputContentType.onEditorActionListener != null && mInputContentType.onEditorActionListener.onEditorAction( this, EditorInfo.IME_NULL, event)) { mInputContentType.enterDown = true; // We are consuming the enter key for them. return -1; } } ! // If our editor should move focus when enter is pressed, or // this is a generated event from an IME action button, then // don't let it be inserted into the text. if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0 || shouldAdvanceFocusOnEnter()) { if (mOnClickListener != null) { return 0; } return -1; } } break;
TextView.javaOnKeyListener
KeyDown
![Page 12: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/12.jpg)
private boolean shouldAdvanceFocusOnEnter() { if (mInput == null) { return false; } ! if (mSingleLine) { return true; } ! if ((mInputType & EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) { int variation = mInputType & EditorInfo.TYPE_MASK_VARIATION; if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS || variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_SUBJECT) { return true; } } ! return false; }
TextView.java
SingleLineを 設定しているとtrueを返す
ShouldAdvanceFocusOnEnter
![Page 13: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/13.jpg)
private int doKeyDown(int keyCode, KeyEvent event, KeyEvent otherEvent) { if (!isEnabled()) { return 0; } ! switch (keyCode) { case KeyEvent.KEYCODE_ENTER: mEnterKeyIsDown = true; if (event.hasNoModifiers()) { // When mInputContentType is set, we know that we are // running in a "modern" cupcake environment, so don't need // to worry about the application trying to capture // enter key events. if (mInputContentType != null) { // If there is an action listener, given them a // chance to consume the event. if (mInputContentType.onEditorActionListener != null && mInputContentType.onEditorActionListener.onEditorAction( this, EditorInfo.IME_NULL, event)) { mInputContentType.enterDown = true; // We are consuming the enter key for them. return -1; } } ! // If our editor should move focus when enter is pressed, or // this is a generated event from an IME action button, then // don't let it be inserted into the text. if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0 || shouldAdvanceFocusOnEnter()) { if (mOnClickListener != null) { return 0; } return -1; } } break;
TextView.javaOnKeyListener
enterがreturnされるので eventがnullになる
KeyDown
![Page 14: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/14.jpg)
public void onEditorAction(int actionCode) { final InputContentType ict = mInputContentType; if (ict != null) { if (ict.onEditorActionListener != null) { if (ict.onEditorActionListener.onEditorAction(this, actionCode, null)) { return; } } // This is the handling for some default action. // Note that for backwards compatibility we don't do this // default handling if explicit ime options have not been given, // instead turning this into the normal enter key codes that an // app may be expecting. if (actionCode == EditorInfo.IME_ACTION_NEXT) { View v = focusSearch(FOCUS_FORWARD); if (v != null) { if (!v.requestFocus(FOCUS_FORWARD)) { throw new IllegalStateException("focus search returned a view " + "that wasn't able to take focus!"); } } return; ! } else if (actionCode == EditorInfo.IME_ACTION_PREVIOUS) { View v = focusSearch(FOCUS_BACKWARD); if (v != null) { if (!v.requestFocus(FOCUS_BACKWARD)) { throw new IllegalStateException("focus search returned a view " + "that wasn't able to take focus!"); } } return; ! } else if (actionCode == EditorInfo.IME_ACTION_DONE) { InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null && imm.isActive(this)) { imm.hideSoftInputFromWindow(getWindowToken(), 0); } clearFocus(); return; } }
TextView.java
Focus移動の メソッドを呼ぶ
OnEditorAction
OnEditorActionを 呼ぶことでFocus移動
![Page 15: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/15.jpg)
複数ある場合はどうするか?
((EditText)view.findViewById(R.id.edittext_1)).setOnEditorActionListener(new OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { //SingleLineを設定したときはeventがnull if (event == null) { if (actionId == EditorInfo.IME_ACTION_NEXT) { }else if (actionId == EditorInfo.IME_ACTION_DONE) { //対象のViewより下にFocusできる物がなければこちら //「7」「8」「9」 } return false; }else { if (event.getAction() == KeyEvent.ACTION_DOWN) { return false; } } return true; } });
NextFocusdown
NextFocusForward
・OnEditorActionListener を設定
![Page 16: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/16.jpg)
まとめ• OnKeyListenerでは改行不可およびEnterのハンドリングが実装できる
• テキストボックスを変更したい場合はSingleLine + NextFocus + OnEditorActionを合わせて使おう
• NextFocusは対象のViewの位置によって指定する属性が異なる
• actionIdは対象のViewの位置によって値が異なる。EditorInfoの定数を比較に用いる
![Page 17: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/17.jpg)
こんな感じで、 テキストエリアを
隠さずユーザに入力させる ことができます
ちょっとだけ 優しい!
![Page 18: ちょっと優しい入力項目](https://reader033.vdocuments.pub/reader033/viewer/2022060110/5561533ad8b42a780d8b50ad/html5/thumbnails/18.jpg)
以上