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,Viewv,
    			             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