Android:如何从 webview 中选择文本

Posted

技术标签:

【中文标题】Android:如何从 webview 中选择文本【英文标题】:Android: how to select texts from webview 【发布时间】:2011-08-28 20:48:27 【问题描述】:

我希望允许用户从 webview 中选择一些文本,并且它需要作为文本消息发送。请想办法选择文本并复制到剪贴板并从剪贴板中提取。我看到了很多例子,但没有什么真正帮助我......TIA

编辑 使用 @orangmoney52 的链接中提供的代码。有以下变化

getmethod的第二个参数和invoke方法的第二个参数。如果我给 null 会有警告..哪一个是正确的?

 public void selectAndCopyText() 
     try 
         Method m = WebView.class.getMethod("emulateShiftHeld", Boolean.TYPE); 
            m.invoke(BookView.mWebView, false); 
         catch (Exception e) 
            e.printStackTrace();
            // fallback
            KeyEvent shiftPressEvent = new KeyEvent(0,0,
                 KeyEvent.ACTION_DOWN,KeyEvent.KEYCODE_SHIFT_LEFT,0,0);
            shiftPressEvent.dispatch(this);
        


得到这个错误:

 05-26 16:41:01.121: WARN/System.err(1096): java.lang.NoSuchMethodException: emulateShiftHeld  

【问题讨论】:

请添加完整的sn-p 【参考方案1】:

上面的答案看起来非常好,您在选择文本时似乎遗漏了一些东西。因此,您需要仔细检查代码并找到您覆盖的 webview 的任何 TouchEvent

我尝试了下面的代码,它工作正常......

功能是

 private void emulateShiftHeld(WebView view)
    
        try
        
            KeyEvent shiftPressEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
                                                    KeyEvent.KEYCODE_SHIFT_LEFT, 0, 0);
            shiftPressEvent.dispatch(view);
            Toast.makeText(this, "select_text_now", Toast.LENGTH_SHORT).show();
        
        catch (Exception e)
        
            Log.e("dd", "Exception in emulateShiftHeld()", e);
        
    

在任何你想要的地方调用Above方法(你可以放置一个按钮并在它的点击事件中调用这个方法):emulateShiftHeld(mWebView);

【讨论】:

android 4+ 上不起作用。 ***.com/questions/21101181/… 我什至不明白这个答案想说什么。 请在此处添加整个sn-p,以便新手可以轻松使用它 我将它添加到一个项目中并通过一个按钮 onClick 调用它,但没有任何反应。【参考方案2】:

步数:1 创建自定义 WebView 类。 此类将在长按 webview 文本时覆盖本机操作栏。 它还处理不同版本 android 的选择案例(在 4.0 及以上测试) 此代码使用 javascript 获取所选文本。

public class CustomWebView extends WebView 
private Context context;
// override all other constructor to avoid crash
public CustomWebView(Context context) 
    super(context);
    this.context = context;
    WebSettings webviewSettings = getSettings();
    webviewSettings.setJavaScriptEnabled(true);
    // add JavaScript interface for copy
    addJavascriptInterface(new WebAppInterface(context), "JSInterface");


// setting custom action bar
private ActionMode mActionMode;
private ActionMode.Callback mSelectActionModeCallback;
private GestureDetector mDetector;

// this will over ride the default action bar on long press
@Override
public ActionMode startActionMode(Callback callback) 
    ViewParent parent = getParent();
    if (parent == null) 
        return null;
    
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) 
        String name = callback.getClass().toString();
        if (name.contains("SelectActionModeCallback")) 
            mSelectActionModeCallback = callback;
            mDetector = new GestureDetector(context,
                    new CustomGestureListener());
        
    
    CustomActionModeCallback mActionModeCallback = new CustomActionModeCallback();
    return parent.startActionModeForChild(this, mActionModeCallback);


private class CustomActionModeCallback implements ActionMode.Callback 

    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) 
        mActionMode = mode;
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.menu, menu);
        return true;
    

    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) 
        return false; 
    

    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) 

        switch (item.getItemId()) 
        case R.id.copy:
            getSelectedData();
            mode.finish(); 
            return true;
        case R.id.share:
            mode.finish();
            return true;
        default:
            mode.finish();
            return false;
        
    
    @Override
    public void onDestroyActionMode(ActionMode mode) 
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
            clearFocus();
        else
             if (mSelectActionModeCallback != null) 
                 mSelectActionModeCallback.onDestroyActionMode(mode);
             
             mActionMode = null;
        
    

private void getSelectedData()

    String js= "(function getSelectedText() "+
            "var txt;"+
            "if (window.getSelection) "+
                "txt = window.getSelection().toString();"+
            " else if (window.document.getSelection) "+
                "txt = window.document.getSelection().toString();"+
            " else if (window.document.selection) "+
                "txt = window.document.selection.createRange().text;"+
            ""+
            "JSInterface.getText(txt);"+
          ")()";
    // calling the js function
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) 
        evaluateJavascript("javascript:"+js, null);
    else
        loadUrl("javascript:"+js);
    


private class CustomGestureListener extends GestureDetector.SimpleOnGestureListener 
    @Override
    public boolean onSingleTapUp(MotionEvent e) 
        if (mActionMode != null) 
            mActionMode.finish();
            return true;
        
        return false;
    


@Override
public boolean onTouchEvent(MotionEvent event) 
    // Send the event to our gesture detector
    // If it is implemented, there will be a return value
    if(mDetector !=null)
        mDetector.onTouchEvent(event);
    // If the detected gesture is unimplemented, send it to the superclass
    return super.onTouchEvent(event);

第 2 步: 为 WebView 界面创建单独的类。 一旦javascript代码被执行,这个类就会监听事件

public class WebAppInterface 
Context mContext;

WebAppInterface(Context c) 
    mContext = c;


@JavascriptInterface
public void getText(String text) 
    // put selected text into clipdata
    ClipboardManager clipboard = (ClipboardManager)
            mContext.getSystemService(Context.CLIPBOARD_SERVICE);
    ClipData clip = ClipData.newPlainText("simple text",text);
    clipboard.setPrimaryClip(clip);
    // gives the toast for selected text
    Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();


第 3 步: 在 res > menu 文件夹中为自定义菜单添加 menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
    android:id="@+id/copy"
    android:icon="@drawable/ic_action_copy"
    android:showAsAction="always" 
    android:title="copy">
</item>
<item
    android:id="@+id/share"
    android:icon="@drawable/ic_action_share"
    android:showAsAction="always" 
    android:title="share">
</item>

我借助下面列出的几个链接来实现这一点: 谢谢你们。

如何在 webview 上使用 javascript http://developer.android.com/guide/webapps/webview.html#UsingJavaScript

用于注入 javascript Why can't I inject this javascript in the webview on android?

用于覆盖默认操作栏 How to override default text selection of android webview os 4.1+?

适用于 4.0 版。 to 4.3 文本选择 Webview text selection not clearing

【讨论】:

如何在长按 webview 时启用选择?请帮帮我:)【参考方案3】:

最简单的方法,虽然不像每个制造商实现的复制/粘贴功能那样漂亮,但如下:

https://bugzilla.wikimedia.org/show_bug.cgi?id=31484

基本上,如果您通过webview.setWebChromeClient(...) 设置自己的WebChromeClient,则默认情况下会禁用文本选择。要启用它,您的 WebChromeClient 需要实现以下方法:

//@Override
/**
* Tell the client that the selection has been initiated.
*/
public void onSelectionStart(WebView view) 
    // Parent class aborts the selection, which seems like a terrible default.
    //Log.i("DroidGap", "onSelectionStart called");

【讨论】:

在我的情况下它也不起作用。我正在覆盖 onTouch() 但它返回 false。真正的问题是什么,您是否覆盖了触摸事件? 我的建议是不要覆盖 onTouch()。您是在设置自己的自定义 WebChromeClient 吗? 你在说什么?根据developer.android.com/reference/android/webkit/…,WebChromeClient 没有“onSelectionStart”。尽管 Eclipse 警告我这个函数在任何地方都没有使用(而且它不在 API 中),但它是如何工作的(实际上是!) 它有那个方法,它只是没有暴露(隐藏)如果你好奇的话,看看WebChromeClient中的源代码。基本上它是隐藏的,但这并不能阻止你覆盖它。现在这一切都不那么相关了,因为从 Android 4.4 开始有一个新的 WebView 看来这个答案不适用于 Android >= KitKat 4.4 (API 19)。【参考方案4】:

@vnshetty,使用来自@orangmoney52 的链接中提供的代码,几个月前我能够完成这个问题。您可以在菜单中创建一个按钮来复制文本。然后,在 onOptionsItemSelected 中,可以有这样的子句:

    case R.id.select_and_copy: 
        Toast.makeText(getApplicationContext(), "Select Text", Toast.LENGTH_SHORT).show();
        selectAndCopyText();
        return true;
    

【讨论】:

是的 显示吐司后,我按下了 shift 键并尝试使用鼠标选择 webview 内容,但没有选择任何内容?我错过了什么吗? 无需按shift键。只需在 toast 消息显示后选择文本即可。

以上是关于Android:如何从 webview 中选择文本的主要内容,如果未能解决你的问题,请参考以下文章

在Android的WebView中选择文本时如何覆盖上下文操作栏?

android webview 如何实现选择文本功能

在失焦时隐藏文本选择句柄:Android -Webview

如何从可以在新 PDF 中选择文本的 WebView 导出 PDF

在 Android WebView 中选择并突出显示文本

如何在 Android 的 web 视图中禁用文本选择?