最終的に以下のコードで対応しました。
final int MAX_TEXT_LENGTH = 10; final EditText editText = (EditText) findViewById(R.id.edit_text); editText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { if (unfixInput(s)) { return; } final String str = s.toString(); final String adjustedText = adjustText(str); if (!str.equals(adjustedText)) { editText.setText(adjustedText); editText.setSelection(editText.getText().length()); Toast.makeText(getApplicationContext(), String.format("最大%d文字です", MAX_TEXT_LENGTH), Toast.LENGTH_SHORT).show(); return; } // TODO 内容保存処理 } /** * 入力確定前の文字があるときtrue */ private boolean unfixInput(final Editable s) { Object[] spanned = s.getSpans(0, s.length(), Object.class); if (spanned != null) { for (Object obj : spanned) { if ((s.getSpanFlags(obj) & Spanned.SPAN_COMPOSING) == Spanned.SPAN_COMPOSING) { return true; } } } return false; } /** * 文字列の調整 */ private String adjustText(final String str) { if (MAX_TEXT_LENGTH < str.codePointCount(0, str.length())) { // 文字数は、コードポイントで比較 return adjustText(str.substring(0, (str.length() - 1))); } return str; } });
ハマった原因
xmlのEditTextにandroid:maxLength="10"と設定しても、 文字数のカウントがサロゲートの文字が配慮されておらず、絵文字など、文字コードがサロゲートの場合、1文字で2文字と認識されてしまいます。
そのため、最大10文字と設定していても、絵文字を含む文字列だと5〜9文字までしか入力できないEditTextになってしまいます。
対処方法
- EditTextのmaxLengthは使用しない
- 文字数のカウントは、String#codePointCountメソッドを使用する
コードポイントとは
コードポイントとは、Unicodeで1文字分のコードを示す言い方。Javaではコードポイントはint型で表す。(引用元:http://www.ne.jp/asahi/hishidama/home/tech/java/string.html)
他、参考
- Android/EditTextでIMEの未確定文字列が確定された瞬間(のフォーク)
- https://groups.google.com/forum/#!topic/android-group-japan/Aww32JZ28uQ
0 件のコメント:
コメントを投稿