Intereting Posts
Android SlidingDrawer не отключает кнопки «под» ящиком Что означает OAT? Ошибка: ANDROID_HOME не установлен, а команда «android» не находится в вашем PATH. Вы должны выполнить хотя бы одно из этих условий Архетип maven для проекта Android Отключить прокрутку в списке Android Как сделать вызов, который включает «#» или «p» в циферблате? Как центрировать предметы recyclerview? Почему элементы исчезают, когда я просматриваю listView? Невозможно извлечь скрытый показатель для Android KeyStore RecyclerView – обратный вызов, когда вид больше не отображается Платеж для Android в приложении: не удается запустить асинхронную работу, поскольку выполняется другая операция async (выполняется) Вращающееся изображение. Анимационный список или анимированный поворот? (Android) Как настроить proguard для интерфейса javascript? Android.support.design.widget.FloatingActionButton implenetation FAB уменьшает размер изображения Есть ли безопасный способ управления ключами API?

Используйте настраиваемую панель контекстных действий для выбора текста WebView.

Я использовал это руководство от Google и этого учебника для создания собственной контекстной панели действий.

private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() { // Called when the action mode is created; startActionMode() was called @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { // Inflate a menu resource providing context menu items MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.annotation_menu, menu); return true; } // Called each time the action mode is shown. // Always called after onCreateActionMode, but // may be called multiple times if the mode is invalidated. @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; // Return false if nothing is done } // Called when the user selects a contextual menu item @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.custom_button: // do some stuff break; case R.id.custom_button2: // do some other stuff break; default: // This essentially acts as a catch statement // If none of the other cases are true, return false // because the action was not handled return false; } finish(); // An action was handled, so close the CAB return true; } // Called when the user exits the action mode @Override public void onDestroyActionMode(ActionMode mode) { mActionMode = null; } }; 

Это меню предназначено для отображения, когда пользователь выбирает текст, поэтому он переопределяет собственное меню копирования / вставки. Теперь я доберусь до своей проблемы.

Поскольку я переопределяю функции для выбора текста, я также добавил LongClickListener в WebView и реализовал метод onLongClick(View v) чтобы я мог обнаружить, когда пользователи делают выбор.

  myWebView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { if (mActionMode != null) { return false; } mActionMode = startActionMode(mActionModeCallback); v.setSelected(true); return true; } }); 

Когда я долгое время нажимаю, я вижу свое пользовательское меню, но текст не выделяется.
Мне нужно иметь функцию выбора текста; Без него мое меню бессмысленно.

Как переопределить onLongClick(View v) , но сохранить выбор текста, предоставляемый Android?
Если это невозможно, могу ли я сделать вызов startActionMode(mActionModeCallback) где-то в другом месте, чтобы текст был выбран как обычный, но также появится собственное меню?
Если ни одна из них не возможна … помогите.

Solutions Collecting From Web of "Используйте настраиваемую панель контекстных действий для выбора текста WebView."

ЕСТЬ ЛУЧШИЙ ПУТЬ! См. Обновление ниже: 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 нет НИКАКИХ startActionMode получить собственный CAB (меню копирования / вставки в случае 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's 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 . Вероятно, это потребует некоторой настройки в этом случае.

То, как я делал что-то подобное, было только переопределить onTouchListener и вызвать GestureDetector, чтобы обнаружить, когда WebView был долго нажат и делать то, что я хотел оттуда. Вот пример кода, который позволяет вам захватывать события с длинным нажатием, не жертвуя текстовым выбором в WebView. Надеюсь, это поможет.

 @Override protected void onCreate(Bundle savedInstanceState) { WebView mWebView = (WebView) findViewById(R.id.myWebView); GestureDetector mGestureDetector = new GestureDetector(this, new CustomGestureListener()); mWebView.setOnTouchListener(new OnTouchListener(){ @Override public boolean onTouch(View view, MotionEvent arg1) { //Suggestion #1 - this just lets the touch to be handled by the system but allows you to detect long presses mGestureDetector.onTouchEvent(arg1); return false; //Suggestion #2 - this code will only let the touch be handled by the system if you don't detect a long press return mGestureDetector.onTouchEvent(arg1); } }); } private class CustomGestureListener extends SimpleOnGestureListener { @Override public void onLongPress(MotionEvent e) { //do stuff } }