如何在android中覆盖web视图文本选择菜单

如何在android中覆盖web视图文本选择菜单,android,webview,android-menu,Android,Webview,Android Menu,基本android的web文本选择菜单如下图所示。它有复制、共享、全选、网络搜索等选项 我想超越这些菜单,并希望它们成为我自己的菜单列表,如“标记颜色”、“标记为imp”等。我查看了有关堆栈溢出上下文菜单的大多数可用问题。大部分问题与上下文菜单有关,但没有给出预期的结果。我想菜单如下图 当我执行选择时,android监视器会显示一些视图创建表单,如viewRoot D/ViewRootImpl: #1 mView = android.widget.PopupWindow$PopupDecor

基本android的web文本选择菜单如下图所示。它有复制、共享、全选、网络搜索等选项

我想超越这些菜单,并希望它们成为我自己的菜单列表,如“标记颜色”、“标记为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
如何实现这样的实施

我也经历过,但没有得到适当的结果

我做了什么?


我扩展了android的WebView,我想支持最小SDK 19。当我执行长按时,我得到了长按事件,但我无法得到这样的菜单创建api调用。

您需要覆盖活动的操作菜单

您可以阅读更多信息:

如何覆盖:

@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>

我想我能帮你

为了完整起见,以下是我如何解决问题的:

根据这个答案,我遵循了这个建议,进行了更多的调整,以更紧密地匹配覆盖的代码:

公共类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'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);
}
private ActionMode mActionMode=null;
@凌驾
已启动的公共无效操作(操作模式){
if(mActionMode==null){
mActionMode=mode;
Menu Menu=mode.getMenu();
//删除默认菜单项(全选、复制、粘贴、搜索)
menu.clear();
//如果要保留任何默认值,
//分别删除不需要的项目:
//menu.removietem(android.R.id.[要删除的项目的id])
//为自己的菜单项充气
mode.getMenuInflater().充气(R.menu.my\u自定义菜单,菜单);
}
super.OnActionModerArted(模式);
}
//此方法是您应该设置为项目的onClick的方法
// 
已单击上下文菜单项(菜单项)上的公共空白{
开关(item.getItemId()){
案例R.id.示例\u项目\u 1:
//做点什么
打破
案例R.id.示例_项目_2:
//做一些不同的事情
打破
违约:
// ...
打破
}
//这可能永远是真的,但无论如何要检查它,以防万一
if(mActionMode!=null){
mActionMode.finish();
}
}
@凌驾
ActionModeFinished上的公共无效(ActionMode模式){
mActionMode=null;
super.onActionModeFinished(模式);
}
}

下面是一个示例菜单,可以帮助您开始:

<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。我不确定如果您的活动中同时有多个视图,它的工作效果如何。在这种情况下,可能需要进行一些调整。

此解决方案不依赖于活动的操作模式,适用于所有android平台。

我试图给出答案,但它超出了字符限制,因此我添加了一些代码部分

在Web视图上选择参考链接1

制作Web视图标记的参考链接2

以上两个链接都非常重要,都是由一些优秀的开发人员开发的。首先,需要对参考链接1中的TextSelectionSupport类进行一些研究。我在TextSelectionSupport类中自定义了两行代码,以便在selection Listener中获得矩形选择。

从这里克隆示例项目

请参阅CustomWebView的实现和TextSelectionSupport类的使用

这是我在project中的web视图类

像androids智能文本选择一样的自定义弹出菜单XML(Custom_Popup_layout.XML)


输出屏幕截图


您需要的是动作模式,在活动中:

    @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上测试过了,它可以处理动作模式菜单点击和模式。getMenuInflater()。充气(…)不能这样做。

@AshishJohn我已经看过了这个答案,但它没有在第二张图中显示菜单。@YvetteColomb实际上这个问题不需要任何示例,因为它是android的正常web视图特性。明白了。但我已经添加了我想添加的内容。所有菜单覆盖问题都显示不同的菜单结构。我会添加一些额外信息。看看这个:你能告诉我你需要在哪一个android版本上做这件事吗,还有其他的事情活动或压缩活动你可以在这里分享活动快照代码吗
<?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>
    @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);
    }