为WebView加上复制文本功能
需求描述: ??
长按WebView出现Context menu,显示"复制”菜单点击上述菜单后选择文本,复制到剪贴板概要设计+详细设计:用OnTouchListener实现长按实现(参照android.view.View)实现WebView的Context menu(在Activity实例中实现)实现复制文本功能(兼容多个sdk)?
编码:
?
public class WebViewCopy {private Activity activity;private WebView webview;private static boolean mIsSelectingText;public static final String TAG=WebViewCopy.class.getSimpleName(); public WebViewCopy(final Activity activity, final WebView webView){ this.webview=webView; this.activity=activity; this.activity.registerForContextMenu(this.webview); webView.requestFocus(View.FOCUS_DOWN); webView.setOnTouchListener(new OnTouchListener() { boolean mHasPerformedLongPress; Runnable mPendingCheckForLongPress; @Overridepublic boolean onTouch(final View v, MotionEvent event) {/*webView.getSettings().setBuiltInZoomControls(false);webView.getSettings().setSupportZoom(false);*/Log.d(TAG, "event:" + event.getAction());switch (event.getAction()) { case MotionEvent.ACTION_UP: mIsSelectingText = false; if (!v.hasFocus()) { v.requestFocus(); } if (!mHasPerformedLongPress) { // This is a tap, so remove the longpress check if (mPendingCheckForLongPress != null) { v.removeCallbacks(mPendingCheckForLongPress); } // v.performClick(); } break; case MotionEvent.ACTION_DOWN: if (!v.hasFocus()) { v.requestFocus(); } if( mPendingCheckForLongPress == null) { mPendingCheckForLongPress = new Runnable() { public void run() { //((WebView)v).performLongClick(); if(! mIsSelectingText) { activity.openContextMenu(webview); mHasPerformedLongPress = true; mIsSelectingText = false; } } }; } mHasPerformedLongPress = false; v. postDelayed(mPendingCheckForLongPress, ViewConfiguration.getLongPressTimeout()); break; case MotionEvent.ACTION_MOVE: final int x = (int) event.getX(); final int y = (int) event.getY(); // Be lenient about moving outside of buttons int slop = ViewConfiguration.get(v.getContext()).getScaledTouchSlop(); if ((x < 0 - slop) || (x >= v.getWidth() + slop) || (y < 0 - slop) || (y >= v.getHeight() + slop)) { if (mPendingCheckForLongPress != null) { v. removeCallbacks(mPendingCheckForLongPress); } } break; default: return false;} return false;}}); } public static synchronized void emulateShiftHeld(WebView view) { try { KeyEvent shiftPressEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SHIFT_LEFT, 0, 0); shiftPressEvent.dispatch(view); } catch (Exception e) { Log.e(TAG, "Exception in emulateShiftHeld()", e); } } public synchronized void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo,final int copy,String menuString) { MenuItem menuitem=menu.add(1, copy, Menu.NONE, menuString); menuitem.setOnMenuItemClickListener(new OnMenuItemClickListener() {@Overridepublic boolean onMenuItemClick(MenuItem item) {if(item.getItemId()==copy){//emulateShiftHeld(webview);selectAndCopyText(webview);}return false;}});} public static synchronized void selectAndCopyText(WebView v) { try { mIsSelectingText = true; //Method m = WebView.class.getMethod("emulateShiftHeld", Boolean.TYPE); // m.invoke(v, false); if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.ECLAIR) { Method m = WebView.class.getMethod("emulateShiftHeld", Boolean.TYPE); m.invoke(v, false); } else { Method m = WebView.class.getMethod("emulateShiftHeld"); m.invoke(v); } } catch (Exception e) { // fallback emulateShiftHeld(v); }finally{ //Toast.makeText(activity, "Select text", Toast.LENGTH_SHORT).show(); }}}
?下面的代码在activity中写:
?? ? 1) 在onCreate中生成?WebViewCopy ?实例:?copy = new WebViewCopy(this, _webView);
?? ? 2) 在onCreateContextMenu中注入复制菜单public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) { copy.onCreateContextMenu(menu, v, menuInfo,COPY,getString(R.string.copy)); super.onCreateContextMenu(menu, v, menuInfo); }
?
?
回顾与总结:
?? ? ? ?OnTouchListener可能在一些时候更本不响应,如Zoom Button出现后。这得让WebView重新获取焦点,
这是WebView又一已知的Bug. ?整个难点在于重新获取焦点: ?webview.requestFocus();
参考:?http://code.google.com/p/android/issues/detail?id=7189
?
?
?