`

为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;
	   		
		
		@Override
		public 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() {
					
					@Override
					public 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

 

 

 

2
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics