Ответ 1
ЕСТЬ ЛУЧШИЙ ПУТЬ! См. Обновление ниже: D
Для полноты, вот как я исправил проблему:
Я следовал предложению в соответствии с этим ответом, с немного большей настройкой, чтобы более точно соответствовать переопределенному коду:
public class MyWebView extends WebView {
private ActionMode mActionMode;
private mActionMode.Callback mActionModeCallback;
@Override
public ActionMode startActionMode(Callback callback) {
ViewParent parent = getParent();
if (parent == null) {
return null;
}
mActionModeCallback = new CustomActionModeCallback();
return parent.startActionModeForChild(this, mActionModeCallback);
}
}
По сути, это заставляет вашу настраиваемую CAB появляться вместо Android CAB. Теперь вам нужно изменить свой обратный вызов, чтобы подсветка текста исчезла вместе с CAB:
public class MyWebView extends WebView {
...
private class CustomActionModeCallback implements ActionMode.Callback {
...
// Everything up to this point is the same as in the question
// Called when the user exits the action mode
@Override
public void onDestroyActionMode(ActionMode mode) {
clearFocus(); // This is the new code to remove the text highlight
mActionMode = null;
}
}
}
Вот и все. Имейте в виду, что до тех пор, пока вы используете MyWebView
с переопределенным startActionMode
, нет НИКАКОГО ПУТЕМ, чтобы получить собственный CAB (меню copy/paste, в случае WebView). Возможно, возможно реализовать такое поведение, но это не так, как работает этот код.
ОБНОВЛЕНИЕ: Существует гораздо более простой способ сделать это! Вышеупомянутое решение работает хорошо, но вот альтернативный, более простой способ.
Это решение обеспечивает меньший контроль над ActionMode
, но для этого требуется гораздо меньше кода, чем приведенное выше решение.
public class MyActivity extends Activity {
private ActionMode mActionMode = null;
@Override
public void onActionModeStarted(ActionMode mode) {
if (mActionMode == null) {
mActionMode = mode;
Menu menu = mode.getMenu();
// Remove the default menu items (select all, copy, paste, search)
menu.clear();
// If you want to keep any of the defaults,
// remove the items you don't want individually:
// menu.removeItem(android.R.id.[id_of_item_to_remove])
// Inflate your own menu items
mode.getMenuInflater().inflate(R.menu.my_custom_menu, menu);
}
super.onActionModeStarted(mode);
}
// This method is what you should set as your item onClick
// <item android:onClick="onContextualMenuItemClicked" />
public void onContextualMenuItemClicked(MenuItem item) {
switch (item.getItemId()) {
case R.id.example_item_1:
// do some stuff
break;
case R.id.example_item_2:
// do some different stuff
break;
default:
// ...
break;
}
// This will likely always be true, but check it anyway, just in case
if (mActionMode != null) {
mActionMode.finish();
}
}
@Override
public void onActionModeFinished(ActionMode mode) {
mActionMode = null;
super.onActionModeFinished(mode);
}
}
Вот пример меню, чтобы вы начали:
<!-- my_custom_menu.xml -->
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/example_item_1"
android:icon="@drawable/ic_menu_example_1"
android:showAsAction="always"
android:onClick="onContextualMenuItemClicked"
android:title="@string/example_1">
</item>
<item
android:id="@+id/example_item_2"
android:icon="@drawable/ic_menu_example_2"
android:showAsAction="ifRoom"
android:onClick="onContextualMenuItemClicked"
android:title="@string/example_2">
</item>
</menu>
Что это! Все готово! Теперь ваше пользовательское меню будет отображаться, вам не нужно беспокоиться о выборе, и вам едва ли придется заниматься жизненным циклом ActionMode
.
Это почти безупречно работает с WebView
, который занимает весь его родительский Activity
. Я не уверен, насколько хорошо он будет работать, если в вашем Activity
есть несколько View
. Вероятно, это потребует некоторой настройки в этом случае.