使用自定义上下文操作栏进行 WebView 文本选择 [英] Use a custom contextual action bar for WebView text selection

查看:18
本文介绍了使用自定义上下文操作栏进行 WebView 文本选择的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用了 Google 的本指南本教程以生成我自己的上下文操作栏.

I have used this guide from Google and this tutorial to produce my own contextual action bar.

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;
    }
};

此菜单旨在在用户选择文本时出现,因此它会覆盖本地复制/粘贴菜单.现在我要解决我的问题了.

This menu is designed to appear when the user selects text, so it overrides the native copy/paste menu. Now I get to my issue.

因为我要覆盖文本选择的函数,所以我还向 WebView 添加了一个 LongClickListener 并实现了 onLongClick(View v) 方法所以我可以检测用户何时进行选择.

Because I am overriding functions for text selection, I also added a LongClickListener to a WebView and implemented the onLongClick(View v) method so I can detect when users make the selection.

    myWebView.setOnLongClickListener(new View.OnLongClickListener() {

        @Override
        public boolean onLongClick(View v) {
            if (mActionMode != null) {
                return false;
            }

            mActionMode = startActionMode(mActionModeCallback);
            v.setSelected(true);
            return true;
        }
    });

当我长按时,我看到我的自定义菜单出现,但没有突出显示文本.
我需要有文本选择功能;没有它,我的菜单毫无意义.

When I long click, I see my custom menu appear, but no text is highlighted.
I need to have the text selection functionality; without it, my menu is pointless.

如何覆盖 onLongClick(View v),但保持 Android 提供的文本选择?
如果这不可能,我可以调用 startActionMode(mActionModeCallback)) 其他地方,这样文本将被正常选择,但我的自定义菜单也会出现?
如果这两个都不可能...帮助.

How do I override onLongClick(View v), but maintain the text selection provided by Android?
If that is not possible, can I make the call to startActionMode(mActionModeCallback) somewhere else so that text will be selected as normal, but my custom menu will also appear?
If neither of those are possible... help.

推荐答案

有更简单的方法!请参阅下面的更新:D<小时>为了完整起见,以下是我解决问题的方法:

THERE IS AN EASIER WAY! See update below :D


For the sake of completeness, here is how I fixed the problem:

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

I followed the suggestion according to this answer, with a little more tweaking to more closely match the overridden code:

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 一起消失:

Essentially, this forces your customized CAB to appear instead of the Android CAB. Now you have to modify your callback so that the text highlight will go away along with the 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(复制/粘贴菜单,如果是 WebView).实现这种行为是可能的,但这不是这段代码的工作方式.<小时>更新: 有一种更简单的方法可以做到这一点!上述解决方案效果很好,但这里有一个更简单的替代方法.

That's all there is to it. Be aware that as long as you are using MyWebView with the overridden startActionMode there is NO WAY to get the native CAB (the copy/paste menu, in the case of a WebView). It may be possible to implement that sort of behavior, but that is not the way this code works.


UPDATE: There is a much easier way to do this! The above solution works well, but here is an alternative, easier way.

此解决方案对 ActionMode 的控制较少,但与上述解决方案相比,它需要的代码要少得多.

This solution provides less control over the ActionMode, but it requires far less code than the above solution.

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);
    }
}

这是一个让您入门的示例菜单:

Here is an example Menu to get you started:

<!-- 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 生命周期.

That's it! You're done! Now your custom menu will show up, you don't have to worry about the selection, and you barely have to concern yourself with the ActionMode lifecycle.

这与占据其整个父 ActivityWebView 几乎完美无缺.如果您的 Activity 中同时有多个 View ,我不确定它的效果如何.在这种情况下,可能需要进行一些调整.

This works nearly flawlessly with a WebView that occupies its entire parent Activity. I am not sure how well it will work if there are multiple Views within your Activity at one time. It will likely require some tweaking in that case.

这篇关于使用自定义上下文操作栏进行 WebView 文本选择的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆