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;
}
});
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
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;
例えば、Cut と Paste 機能を削除したい場合は removeItem() を使います。
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();
}
}
*1 仮面ライダーウィザードでぐぐってください。
0 件のコメント:
コメントを投稿