EditText (もしくは TextView で android:textIsSelectable="true" を指定した場合)に文字列をロングタップして起動する ActionMode をカスタマイズすることができます。
TextView の setCustomSelectionActionModeCallback() で ActionMode.Callback を指定することで、既存のメニューを削除したり、新しいメニューを追加したりすることができます。
setCustomSelectionActionModeCallback() で渡した ActionMode.Callback は TextView の mCustomSelectionActionModeCallback で保持されます。
http://tools.oesf.biz/android-4.0.1_r1.0/xref/frameworks/base/core/java/android/widget/TextView.java#10075
1. ActionMode を起動しない
onCreateActionMode() で false を返すと、ロングタップしても ActionMode が起動しなくなります。
TextView の ActionMode である SelectionActionModeCallback の onCreateActionMode() の中で mCustomSelectionActionModeCallback の onCreateActionMode() を呼び出し、その戻り値が false の場合は false を返すようになっているからです。
http://tools.oesf.biz/android-4.0.1_r1.0/xref/frameworks/base/core/java/android/widget/TextView.java#10238
2. 既存のメニュー項目を削除する
デフォルトのメニュー項目のそれぞれの ID は
SelectAll : android.R.id.selectAll
Cut : android.R.id.cut
Copy : android.R.id.copy;
Paste : android.R.id.paste
です。
http://tools.oesf.biz/android-4.0.1_r1.0/xref/frameworks/base/core/java/android/widget/TextView.java#9042 例えば、Cut と Paste 機能を削除したい場合は removeItem() を使います。
3. メニューの機能を置き換える
メニューの項目はそのままで、タップされたときの処理を置き換えるには onActionItemClicked() で true を返します。もともとの処理も行ってほしい場合は false を返します。
例えば、MenuItem の id が android.R.id.selectAll のときに true を返すようにすると、全選択をタップしても何も起こらなくなります。
4. 独自のメニュー項目を追加する
メニュー項目を追加するには onCreateActionMode で Menu.add() を使います。
残念ながら既存のメニュー項目の Order が 0 になっているため、任意の位置に追加することはできないようで、最後の位置に追加されます。さらに、Overflow menu に入ると、展開したときに EditText からフォーカスが外れて ActionMode が終了するという残念なことになります。
もう一つ残念なのが、メニュー項目をタップされたときに ActionMode を終了するための stopSelectionActionMode() というメソッドが private なため外部から呼べません(せめて protected にしてほしい)。
ただし、setText() し直すと選択が解除されるので ActionMode を終了することができます。
選択した文字が全角カナだったら半角カナにして先頭に "シャバドゥビタッチ" *1 をつけるようにしてみました。
(アイコンはがんばってトレースしました。)
R.id.replace は XML で定義しました。追加するメニューの ID は適当な数字ではなく、XML で定義しておくのがいいと思います。More Resource Type - ID
TextView の setCustomSelectionActionModeCallback() で ActionMode.Callback を指定することで、既存のメニューを削除したり、新しいメニューを追加したりすることができます。
- EditText editText = (EditText) findViewById(R.id.editText1);
- editText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
- @Override
- public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public void onDestroyActionMode(ActionMode mode) {
- // TODO Auto-generated method stub
- }
- @Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- // TODO Auto-generated method stub
- return false;
- }
- });
setCustomSelectionActionModeCallback() で渡した ActionMode.Callback は TextView の mCustomSelectionActionModeCallback で保持されます。
http://tools.oesf.biz/android-4.0.1_r1.0/xref/frameworks/base/core/java/android/widget/TextView.java#10075
- 350 private Callback mCustomSelectionActionModeCallback;
- 10075 public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
- 10076 mCustomSelectionActionModeCallback = actionModeCallback;
- 10077 }
- 10078
- 10079 /**
- 10080 * Retrieves the value set in {@link #setCustomSelectionActionModeCallback}. Default is null.
- 10081 *
- 10082 * @return The current custom selection callback.
- 10083 */
- 10084 public ActionMode.Callback getCustomSelectionActionModeCallback() {
- 10085 return mCustomSelectionActionModeCallback;
- 10086 }
1. ActionMode を起動しない
onCreateActionMode() で false を返すと、ロングタップしても ActionMode が起動しなくなります。
- EditText editText = (EditText) findViewById(R.id.editText1);
- editText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
- ...
- @Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- return false;
- }
- });
http://tools.oesf.biz/android-4.0.1_r1.0/xref/frameworks/base/core/java/android/widget/TextView.java#10238
- 10182 private class SelectionActionModeCallback implements ActionMode.Callback {
- 10183
- 10184 @Override
- 10185 public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- ...
- 10237
- 10238 if (mCustomSelectionActionModeCallback != null) {
- 10239 if (!mCustomSelectionActionModeCallback.onCreateActionMode(mode, menu)) {
- 10240 // The custom mode can choose to cancel the action mode
- 10241 return false;
- 10242 }
- 10243 }
- ...
- 10251 }
2. 既存のメニュー項目を削除する
デフォルトのメニュー項目のそれぞれの ID は
SelectAll : android.R.id.selectAll
Cut : android.R.id.cut
Copy : android.R.id.copy;
Paste : android.R.id.paste
です。
http://tools.oesf.biz/android-4.0.1_r1.0/xref/frameworks/base/core/java/android/widget/TextView.java#9042
- 9041 // Selection context mode
- 9042 private static final int ID_SELECT_ALL = android.R.id.selectAll;
- 9043 private static final int ID_CUT = android.R.id.cut;
- 9044 private static final int ID_COPY = android.R.id.copy;
- 9045 private static final int ID_PASTE = android.R.id.paste;
- EditText editText = (EditText) findViewById(R.id.editText1);
- editText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
- ...
- @Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- menu.removeItem(android.R.id.cut);
- menu.removeItem(android.R.id.paste);
- return true;
- }
- });
3. メニューの機能を置き換える
メニューの項目はそのままで、タップされたときの処理を置き換えるには onActionItemClicked() で true を返します。もともとの処理も行ってほしい場合は false を返します。
例えば、MenuItem の id が android.R.id.selectAll のときに true を返すようにすると、全選択をタップしても何も起こらなくなります。
- EditText editText = (EditText) findViewById(R.id.editText1);
- editText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
- ...
- @Override
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- int id = item.getItemId();
- switch(id) {
- case android.R.id.selectAll:
- // 独自の処理
- return true;
- }
- return false;
- }
- });
4. 独自のメニュー項目を追加する
メニュー項目を追加するには onCreateActionMode で Menu.add() を使います。
残念ながら既存のメニュー項目の Order が 0 になっているため、任意の位置に追加することはできないようで、最後の位置に追加されます。さらに、Overflow menu に入ると、展開したときに EditText からフォーカスが外れて ActionMode が終了するという残念なことになります。
もう一つ残念なのが、メニュー項目をタップされたときに ActionMode を終了するための stopSelectionActionMode() というメソッドが private なため外部から呼べません(せめて protected にしてほしい)。
ただし、setText() し直すと選択が解除されるので ActionMode を終了することができます。
選択した文字が全角カナだったら半角カナにして先頭に "シャバドゥビタッチ" *1 をつけるようにしてみました。
(アイコンはがんばってトレースしました。)
R.id.replace は XML で定義しました。追加するメニューの ID は適当な数字ではなく、XML で定義しておくのがいいと思います。More Resource Type - ID
- public class MainActivity extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- final EditText editText = (EditText) findViewById(R.id.editText1);
- editText.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
- @Override
- public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
- return true;
- }
- @Override
- public void onDestroyActionMode(ActionMode mode) {
- }
- @Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- menu.removeItem(android.R.id.paste);
- menu.removeItem(android.R.id.cut);
- menu.removeItem(android.R.id.copy);
- MenuItem item = menu.add(Menu.NONE, R.id.replace, Menu.NONE, "Replace");
- item.setIcon(R.drawable.ic_replace);
- return true;
- }
- @Override
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- CharSequence text = editText.getText();
- int min = 0;
- int max = text.length();
- if (editText.isFocused()) {
- final int selStart = editText.getSelectionStart();
- final int selEnd = editText.getSelectionEnd();
- min = Math.max(0, Math.min(selStart, selEnd));
- max = Math.max(0, Math.max(selStart, selEnd));
- }
- int id = item.getItemId();
- switch (id) {
- case R.id.replace:
- CharSequence sub = text.subSequence(min, max);
- editText.setText(text.subSequence(0, min) + "シャバドゥビタッチ" + convertKanaFull2Half(sub)
- + text.subSequence(max, text.length()));
- return true;
- }
- return false;
- }
- });
- }
- private static final char[] FULL_WIDTH_KANA = { 'ァ', 'ア', 'ィ', 'イ', 'ゥ', 'ウ', 'ェ', 'エ', 'ォ', 'オ', 'カ', 'ガ', 'キ',
- 'ギ', 'ク', 'グ', 'ケ', 'ゲ', 'コ', 'ゴ', 'サ', 'ザ', 'シ', 'ジ', 'ス', 'ズ', 'セ', 'ゼ', 'ソ', 'ゾ', 'タ', 'ダ', 'チ', 'ヂ',
- 'ッ', 'ツ', 'ヅ', 'テ', 'デ', 'ト', 'ド', 'ナ', 'ニ', 'ヌ', 'ネ', 'ノ', 'ハ', 'バ', 'パ', 'ヒ', 'ビ', 'ピ', 'フ', 'ブ', 'プ',
- 'ヘ', 'ベ', 'ペ', 'ホ', 'ボ', 'ポ', 'マ', 'ミ', 'ム', 'メ', 'モ', 'ャ', 'ヤ', 'ュ', 'ユ', 'ョ', 'ヨ', 'ラ', 'リ', 'ル', 'レ',
- 'ロ', 'ヮ', 'ワ', 'ヰ', 'ヱ', 'ヲ', 'ン', 'ヴ', 'ヵ', 'ヶ'};
- private static final String[] HALF_WIDTH_KANA = { "ァ", "ア", "ィ", "イ", "ゥ", "ウ", "ェ", "エ", "ォ", "オ", "カ", "ガ", "キ",
- "ギ", "ク", "グ", "ケ", "ゲ", "コ", "ゴ", "サ", "ザ", "シ", "ジ", "ス", "ズ", "セ", "ゼ", "ソ", "ゾ", "タ", "ダ",
- "チ", "ヂ", "ッ", "ツ", "ヅ", "テ", "デ", "ト", "ド", "ナ", "ニ", "ヌ", "ネ", "ノ", "ハ", "バ", "パ", "ヒ", "ビ", "ピ",
- "フ", "ブ", "プ", "ヘ", "ベ", "ペ", "ホ", "ボ", "ポ", "マ", "ミ", "ム", "メ", "モ", "ャ", "ヤ", "ュ", "ユ", "ョ", "ヨ",
- "ラ", "リ", "ル", "レ", "ロ", "ワ", "ワ", "イ", "エ", "ヲ", "ン", "ヴ", "カ", "ケ"};
- private static final char FULL_WIDTH_FIRST = FULL_WIDTH_KANA[0];
- private static final char FULL_WIDTH_LAST = FULL_WIDTH_KANA[FULL_WIDTH_KANA.length - 1];
- public static String convertKanaFull2Half(char c) {
- if (c >= FULL_WIDTH_FIRST && c <= FULL_WIDTH_LAST) {
- return HALF_WIDTH_KANA[c - FULL_WIDTH_FIRST];
- } else if(c == 'ー') {
- return "-";
- } else {
- return String.valueOf(c);
- }
- }
- public static String convertKanaFull2Half(CharSequence cs) {
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < cs.length(); i++) {
- sb.append(convertKanaFull2Half(cs.charAt(i)));
- }
- return sb.toString();
- }
- }
0 件のコメント:
コメントを投稿