web-dev-qa-db-ja.com

Android:Webビューからテキストを選択する方法

ユーザーがウェブビューからいくつかのテキストを選択できるようにしたいのですが、テキストメッセージとして送信する必要があります。 plsは、テキストを選択してクリップボードにコピーし、クリップボードから抽出する方法を見つけます。私は多くの例を見ましたが、何も私を本当に助けませんでした... TIA

編集
@ orangmoney52からのリンクで提供されているコードを使用します。以下の変更を加えて

getmethodの2番目のパラメーターとinvokeメソッドの2番目のパラメーター。 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  
14
vnshetty

上記の答えは完全にうまく見え、テキストを選択しているときに何かが足りないようです。したがって、コードを再確認して、オーバーライドされたWebビューの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);
        }
    }

どこでも上記のメソッドを呼び出します(ボタンを配置して、クリックイベントでこのメソッドを呼び出すことができます):emulateShiftHeld(mWebView);

13
vnshetty

手順:1カスタムWebViewクラスを作成します。このクラスは、Webビューテキストを長押しするとネイティブアクションバーを上書きします。また、異なるバージョンの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を挿入するために なぜAndroidのWebビューにこのjavascriptを挿入できないのですか?

デフォルトのアクションバーをオーバーライドする場合 Android webview os 4.1 +? のデフォルトのテキスト選択をオーバーライドする方法

バージョン4.0の場合。 4.3テキスト選択へ Webviewテキスト選択がクリアされない

8
vikoo

最も簡単な方法は、メーカーごとに実装されたコピー/貼り付け機能ほどきれいではありませんが、次のとおりです。

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");
}
5
Leo K

@ vnshetty、@ orangmoney52からのリンクで提供されているコードを使用して、私は数か月前にこの問題を完了することができました。メニューに、テキストをコピーできるボタンを作成できます。次に、onOptionsItemSelectedに、次のような句を含めることができます。

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