Intereting Posts

Используйте настраиваемую панель контекстных действий для выбора текста 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 } }