Как переопределить меню выбора текста веб-представления в android
Основное меню выбора текста в веб-браузере показано на рисунке ниже. Он имеет такие опции, как копирование, общий доступ, выбор всех, веб-поиск.
![введите описание изображения здесь]()
Я хочу переместить это меню и хочу, чтобы они были в моем списке меню, например "mark color", "mark as imp" и т.д. Я просматриваю большинство вопросов, доступных о контекстном меню при переполнении стека. Большая часть вопроса связана с контекстным меню, но не дает результата, как ожидалось. Я хочу меню, как показано ниже.
![введите описание изображения здесь]()
Когда я выполняю выбор монитора Android, отображается форма представления вида viewRoot, например
D/ViewRootImpl: #1 mView = android.widget.PopupWindow$PopupDecorView{648898f V.E...... ......I. 0,0-0,0}
D/ViewRootImpl: #1 mView = android.widget.PopupWindow$PopupDecorView{a66541c V.E...... ......I. 0,0-0,0}
D/ViewRootImpl: MSG_RESIZED_REPORT: ci=Rect(0, 0 - 0, 0) vi=Rect(0, 0 - 0, 0) or=1
D/ViewRootImpl: MSG_RESIZED_REPORT: ci=Rect(0, 0 - 0, 0) vi=Rect(0, 0 - 0, 0) or=1
Как добиться такой реализации?
Я также прошел https://github.com/naoak/WebViewMarker, но не получал надлежащего результата.
Что я еще сделал?
Я расширяю WebView android, и я хочу поддерживать минимальный SDK 19. Когда я выполняю длинное нажатие, я получил длинное событие, но я не могу получить такие вызовы api для создания меню.
Ответы
Ответ 1
Это решение не зависит от режима действия Activity и работы для всех платформ Android.
Я попытался дать ответ, но он превышает пределы символов, поэтому я помещаю часть кода
Ссылка Ссылка 1 для выбора в веб-представлении
https://github.com/btate/BTAndroidWebViewSelection
Ссылка 2 для создания маркера веб-представления
https://github.com/liufsd/WebViewMarker
Оба вышеупомянутых канала действительно играют важную роль и разрабатываются некоторыми удивительными разработчиками. Прежде всего, нужно некоторое исследование по классу TextSelectionSupport из ссылки Ссылка 1. Я настроил две строки кода в классе TextSelectionSupport, чтобы получить прямоугольник выбора в Selection Listener здесь.
Клонировать пример проекта отсюда https://github.com/ab-cse-2014/WebViewSelection.git
См. Реализация класса CustomWebView и использования класса TextSelectionSupport.
Это мой класс веб-представления в проекте
import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.webkit.WebView;
import android.widget.PopupWindow;
import android.widget.Toast;
import com.cse.webviewtextselection.R;
import com.cse.webviewtextselection.webviewmaker.TextSelectionSupport;
public class CustomWebView extends WebView {
private final String TAG = this.getClass().getSimpleName();
private Context mContext;
private TextSelectionSupport mTextSelectionSupport;
private PopupWindow mPopupWindow;
private int currentTop;
public CustomWebView(Context context) {
super(context);
mContext = context;
initSetUp();
preparePopupWindow();
}
public CustomWebView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
initSetUp();
preparePopupWindow();
}
public CustomWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
initSetUp();
preparePopupWindow();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public CustomWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mContext = context;
initSetUp();
preparePopupWindow();
}
private void initSetUp() {
mTextSelectionSupport = TextSelectionSupport.support((AppCompatActivity) mContext, this);
mTextSelectionSupport.setSelectionListener(new TextSelectionSupport.SelectionListener() {
@Override
public void startSelection() {
}
@Override
public void selectionChanged(String text, Rect rect) {
Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();
showPopAtLocation(mPopupWindow, rect.left, rect.top);
}
@Override
public void endSelection() {
if (mPopupWindow != null) {
mPopupWindow.dismiss();
}
}
});
}
private void preparePopupWindow() {
LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View customPopupView = layoutInflater.inflate(R.layout.custom_popup_layout, null);
mPopupWindow = new PopupWindow(customPopupView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, true);
mPopupWindow.setAnimationStyle(android.R.style.Animation_Dialog);
}
private void showPopAtLocation(PopupWindow mPopupWindow, int x, int y) {
if (mPopupWindow != null) {
if (currentTop != 0 || currentTop > ((AppCompatActivity)mContext).getWindow().getDecorView().getHeight()) {
if (y > currentTop) {
y -= currentTop;
}
}
Log.d("Current Top : ", String.valueOf(currentTop));
Log.d("Y : ", String.valueOf(y));
//mPopupWindow.showAtLocation(((AppCompatActivity)mContext).findViewById(R.id.parentRelativeLayout), Gravity.NO_GRAVITY, x, y);
mPopupWindow.showAtLocation(((AppCompatActivity)mContext).getWindow().getDecorView(), Gravity.NO_GRAVITY, x, y);
}
}
@Override
protected void onScrollChanged(int newLeft, int newTop, int oldLeft, int oldTop) {
currentTop = newTop;
super.onScrollChanged(newLeft, newTop, oldLeft, oldTop);
}
}
Пользовательское всплывающее меню XML, например, выбор интеллектуального текста androids (custom_popup_layout.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/myCustomMenuLinearLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@android:color/transparent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@android:color/white"
android:elevation="5dp"
android:layout_margin="12dp">
<TextView
android:id="@+id/menuOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Mark With Color"
android:textColor="@android:color/black"
android:padding="10dp"
android:maxLines="1"/>
<TextView
android:id="@+id/menuTwo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Mark As Important"
android:textColor="@android:color/black"
android:padding="10dp"
android:maxLines="1"/>
<TextView
android:id="@+id/menuThree"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show More"
android:textColor="@android:color/black"
android:padding="10dp"
android:maxLines="1"/>
</LinearLayout>
</LinearLayout>
Экранные снимки экрана
![Выбор один]()
![Выбор два]()
![Выбор три]()
Ответ 2
Вам нужно перезаписать меню действий
больше информации вы можете прочитать:https://developer.android.com/guide/topics/ui/menus.html
КАК ПЕРЕЗАПИСАТЬ:
@Override
public void onActionModeStarted(android.view.ActionMode mode) {
mode.getMenu().clear();
Menu menus = mode.getMenu();
mode.getMenuInflater().inflate(R.menu.highlight,menus);
super.onActionModeStarted(mode);
}
выделить
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/impclick"
android:title="Mark As Important"
/>
<item android:id="@+id/colorclick"
android:title="Mark with color" />
</menu>
Ответ 3
вам нужен режим действия, в действии:
@Override
public void onActionModeStarted(ActionMode mode) {
Menu menu = mode.getMenu();
// you can remove original menu: copy, cut, select all, share ... or not
menu.clear();
// here i will get text selection by user
menu.add(R.string.action_menu_preview_card)
.setEnabled(true)
.setVisible(true)
.setOnMenuItemClickListener(item -> {
if (mWebview != null) {
mWebview.evaluateJavascript("window.getSelection().toString()", value -> {
value = StringUtil.trimToNull(value);
if (value != null) {
// do something about user select
}
});
}
// Post a delayed runnable to avoid a race condition
// between evaluateScript() result and mode.finish()
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mode.finish();
}
}, 200);
return true;
});
super.onActionModeStarted(mode);
}
Я тестировал его выше Android 21, это может обработать щелчок меню режима действий, а mode.getMenuInflater(). inflate (...) не может этого сделать.
Ответ 4
Я думаю, здесь может вам помочь.
Для полноты, вот как я исправил проблему:
Я следовал предложению в соответствии с этим ответом, с немного большей настройкой, чтобы более точно соответствовать переопределенному коду:
Открытый класс MyWebView расширяет 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:
Открытый класс MyWebView расширяет WebView { ... частный класс CustomActionModeCallback реализует ActionMode.Callback { ... // Все до этой точки такое же, как в вопросе
// 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 (меню копирования/вставки в случае WebView). Возможно, возможно реализовать такое поведение, но это не так, как работает этот код.
ОБНОВЛЕНИЕ: есть намного более простой способ сделать это! Вышеупомянутое решение работает хорошо, но вот альтернативный, более простой способ.
Это решение обеспечивает меньший контроль над ActionMode, но для этого требуется гораздо меньше кода, чем указанное выше решение.
Открытый класс MyActivity расширяет действие {
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);
}
}
Вот пример меню, чтобы вы начали:
<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>
Что это! Все готово! Теперь ваше пользовательское меню появится, вам не нужно беспокоиться о выборе, и вам едва ли придется заботиться о жизненном цикле ActionMode.
Это почти безупречно работает с WebView, который занимает всю свою родительскую активность. Я не уверен, насколько хорошо он будет работать, если в вашей деятельности одновременно будет несколько просмотров. Вероятно, это потребует некоторой настройки в этом случае.