2013-06-10 17 views
46

Trước khi đăng câu hỏi này, tôi đã tìm kiếm rất nhiều nhưng không thể tìm thấy bất kỳ câu trả lời rõ ràng nào về vấn đề này.Cách ghi đè lựa chọn văn bản mặc định của android webview os 4.1+?

Tôi phải ghi đè lựa chọn văn bản mặc định của chế độ xem web android & hiển thị tùy chọn hộp thoại chọn văn bản tùy chỉnh của tôi. Tôi đã thử mã mẫu này project.

dự án mẫu này hoạt động trên các thiết bị sau & giả lập:

  • Acer Iconia A500 máy tính bảng: 10 inch: Android OS - 3,0
  • Acer Iconia A500 máy tính bảng: 10 inch: Android OS - 3.2
  • Samsung Galaxy Tab: 10 inch: Hệ điều hành Android - 4.0
  • Samsung Galaxy Tab: 7 inch: Hệ điều hành Android - 4.0
  • E mulator: Da-WVGA800: Android OS - 4.1.2

Không làm việc trên các thiết bị sau:

  • Samsung Galaxy Tab: 10 inch: Android OS - 4.1.2
  • Samsung Galaxy Tab: 7 inch: Hệ điều hành Android - 4.1.2

Trên phiên bản hệ điều hành Android 4.1 & 4.1+ thay vì hiển thị hộp thoại tùy chọn lựa chọn văn bản tùy chỉnh, nó hiển thị androi d thanh tác vụ mặc định của hệ thống để chọn văn bản.

Tôi đã tìm kiếm rất nhiều về vấn đề này, nhiều gợi ý để sử dụng onLongClick() phương pháp của interface

Tôi đã hỏi một câu hỏi trên diễn đàn này xin vui lòng xem link này, với câu trả lời cho câu hỏi này tôi có thể sao chép sự kiện onLongClick() nhưng tôi không thể dừng thanh tác vụ chọn văn bản mặc định.

Đối với kịch bản này, tôi có một vài câu hỏi.

1.Tại sao phương thức onLongClick() ngừng hoạt động đối với thiết bị chạy trên hệ điều hành Android phiên bản 4.1+?

2.Làm cách nào để dừng thanh tác vụ chọn văn bản mặc định khi nhấn và giữ văn bản từ chế độ xem web?

Đây là lớp xem web tùy chỉnh của tôi.

package com.epubreader.ebook; 
    import org.json.JSONException; 
    import org.json.JSONObject; 
    import android.app.Activity; 
    import android.content.Context; 
    import android.graphics.Rect; 
    import android.graphics.Region; 
    import android.os.Handler; 
    import android.os.Message; 
    import android.util.AttributeSet; 
    import android.util.DisplayMetrics; 
    import android.util.Log; 
    import android.view.ContextMenu; 
    import android.view.Display; 
    import android.view.GestureDetector; 
    import android.view.LayoutInflater; 
    import android.view.MotionEvent; 
    import android.view.View; 
    import android.view.View.OnLongClickListener; 
    import android.view.View.OnTouchListener; 
    import android.view.ViewGroup; 
    import android.view.WindowManager; 
    import android.webkit.WebView; 
    import android.widget.ImageView; 
    import android.widget.LinearLayout; 
    import android.widget.Toast; 

    import com.epubreader.R; 
    import com.epubreader.drag.DragController; 
    import com.epubreader.drag.DragLayer; 
    import com.epubreader.drag.DragListener; 
    import com.epubreader.drag.DragSource; 
    import com.epubreader.drag.MyAbsoluteLayout; 
    import com.epubreader.menu.menuAnimationHelper; 
    import com.epubreader.textselection.WebTextSelectionJSInterface; 
    import com.epubreader.textselectionoverlay.ActionItem; 
    import com.epubreader.textselectionoverlay.QuickAction; 
    import com.epubreader.textselectionoverlay.QuickAction.OnDismissListener; 



public class CustomWebView extends WebView implements WebTextSelectionJSInterface, 
OnTouchListener , OnLongClickListener, OnDismissListener, DragListener{ 

/** The logging tag. */ 
private static final String TAG = "CustomWebView"; 

/** Context. */ 
protected Context ctx; 

/** The context menu. */ 
private QuickAction mContextMenu; 

/** The drag layer for selection. */ 
private DragLayer mSelectionDragLayer; 

/** The drag controller for selection. */ 
private DragController mDragController; 

/** The start selection handle. */ 
private ImageView mStartSelectionHandle; 

/** the end selection handle. */ 
private ImageView mEndSelectionHandle; 

/** The selection bounds. */ 
private Rect mSelectionBounds = null; 

/** The previously selected region. */ 
protected Region lastSelectedRegion = null; 

/** The selected range. */ 
protected String selectedRange = ""; 

/** The selected text. */ 
protected String selectedText = ""; 

/** Javascript interface for catching text selection. */ 


/** Selection mode flag. */ 
protected boolean inSelectionMode = false; 

/** Flag to stop from showing context menu twice. */ 
protected boolean contextMenuVisible = false; 

/** The current content width. */ 
protected int contentWidth = 0; 


/** Identifier for the selection start handle. */ 
private final int SELECTION_START_HANDLE = 0; 

/** Identifier for the selection end handle. */ 
private final int SELECTION_END_HANDLE = 1; 

/** Last touched selection handle. */ 
private int mLastTouchedSelectionHandle = -1; 

/** Variables for Left & Right Menu ***/ 
private View menuView; 
private LinearLayout toiLay; 
private menuAnimationHelper _menuAnimationHelper; 
private TocTranslateAnimation _tocTranslateAnimation; 

private CustomWebView _customWebView; 



public CustomWebView(Context context) { 
    super(context); 

    this.ctx = context; 
    this.setup(context); 
} 

public CustomWebView(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 

    this.ctx = context; 
    this.setup(context); 

} 

public CustomWebView(Context context, AttributeSet attrs) { 
    super(context, attrs); 

    this.ctx = context; 
    this.setup(context); 

} 


//***************************************************** 
//* 
//*  Touch Listeners 
//* 
//***************************************************** 

private boolean mScrolling = false; 
private float mScrollDiffY = 0; 
private float mLastTouchY = 0; 
private float mScrollDiffX = 0; 
private float mLastTouchX = 0; 

@Override 
public boolean onTouch(View v, MotionEvent event) { 


    float xPoint = getDensityIndependentValue(event.getX(), ctx)/getDensityIndependentValue(this.getScale(), ctx); 
    float yPoint = getDensityIndependentValue(event.getY(), ctx)/getDensityIndependentValue(this.getScale(), ctx); 

    // TODO: Need to update this to use this.getScale() as a factor. 

    //Log.d(TAG, "onTouch " + xPoint + " , " + yPoint); 

    closeMenu(); 
    if(event.getAction() == MotionEvent.ACTION_DOWN){ 

     final String startTouchUrl = String.format("javascript:android.selection.startTouch(%f, %f);", 
       xPoint, yPoint); 

     mLastTouchX = xPoint; 
     mLastTouchY = yPoint; 

     ((Activity)this.ctx).runOnUiThread(new Runnable() { 

      @Override 
      public void run() { 
       loadUrl(startTouchUrl); 
      } 
     }); 

     // This two line clones the onLongClick() 
     longClickHandler.removeCallbacks(longClickRunnable); 
     longClickHandler.postDelayed(longClickRunnable,300); 


    } 
    else if(event.getAction() == MotionEvent.ACTION_UP){ 
     // Check for scrolling flag 
     if(!mScrolling){ 
      this.endSelectionMode(); 
     } 

     // This line clones the onLongClick() 
     longClickHandler.removeCallbacks(longClickRunnable); 

     mScrollDiffX = 0; 
     mScrollDiffY = 0; 
     mScrolling = false; 



    }else if(event.getAction() == MotionEvent.ACTION_MOVE){ 

     mScrollDiffX += (xPoint - mLastTouchX); 
     mScrollDiffY += (yPoint - mLastTouchY); 

     mLastTouchX = xPoint; 
     mLastTouchY = yPoint; 


     // Only account for legitimate movement. 
     if(Math.abs(mScrollDiffX) > 10 || Math.abs(mScrollDiffY) > 10){ 
      mScrolling = true; 

     } 
     // This line clones the onLongClick() 
     longClickHandler.removeCallbacks(longClickRunnable); 

    } 

    // If this is in selection mode, then nothing else should handle this touch 
    return false; 
} 

/** 
* Pass References of Left & Right Menu 
*/ 

public void initMenu(LinearLayout _toiLay,View _menuView,menuAnimationHelper menuAnimationHelper, 
     TocTranslateAnimation tocTranslateAnimation){ 
    toiLay = _toiLay; 
    menuView = _menuView; 
    _menuAnimationHelper = menuAnimationHelper; 
    _tocTranslateAnimation = tocTranslateAnimation; 
} 

private void closeMenu(){ 

    if(_menuAnimationHelper != null && _menuAnimationHelper.isMenuOpenBool){ 
     _menuAnimationHelper.close(menuView); 
     _menuAnimationHelper.isMenuOpenBool = false; 
    } 

    if(_tocTranslateAnimation != null && _tocTranslateAnimation.isTocListOpenBool){ 
     _tocTranslateAnimation.close(toiLay); 
     _tocTranslateAnimation.isTocListOpenBool = false; 
    } 
} 

     public void removeOverlay(){ 
    Log.d("JsHandler", "in java removeOverlay" + mScrolling); 


    this.endSelectionMode(); 
    mScrollDiffX = 0; 
    mScrollDiffY = 0; 
    mScrolling = false; 
} 

@Override 
public boolean onLongClick(View v){ 

    Log.d(TAG, "from webView onLongClick "); 
    mScrolling = true; 
    ((Activity)this.ctx).runOnUiThread(new Runnable() { 

     @Override 
     public void run() { 
      loadUrl("javascript:android.selection.longTouch()"); 
     } 
    }); 

    Toast.makeText(ctx, "Long click is clicked ", Toast.LENGTH_LONG).show(); 
    // Don't let the webview handle it 
    return true; 
} 





//***************************************************** 
//* 
//*  Setup 
//* 
//***************************************************** 

ContextMenu.ContextMenuInfo contextMenuInfo; 

/** 
* Setups up the web view. 
* @param context 
*/ 
protected void setup(Context context){ 


    // On Touch Listener 

    this.setOnTouchListener(this); 

    this.setClickable(false); 
    this.setLongClickable(true); 
    this.setOnLongClickListener(this); 

    contextMenuInfo = this.getContextMenuInfo(); 
    // Webview setup 
    this.getSettings().setJavaScriptEnabled(true); 
    this.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); 

    // Create the selection handles 
    createSelectionLayer(context); 

    // Set to the empty region 
    Region region = new Region(); 
    region.setEmpty(); 

    _customWebView = this; 

    this.lastSelectedRegion = region; 


} 

/** 
* To clone OnLongClick Listener because its not responding for version 4.1 
*/ 
public Runnable longClickRunnable = new Runnable() { 
    public void run() { 
     longClickHandler.sendEmptyMessage(0); 

    } 
}; 


public Handler longClickHandler = new Handler(){ 

    public void handleMessage(Message m){ 
     _customWebView.loadUrl("javascript:android.selection.longTouch();"); 
     mScrolling = true; 
    } 
}; 


public WebTextSelectionJSInterface getTextSelectionJsInterface(){ 
    return this; 
} 

//***************************************************** 
//* 
//*  Selection Layer Handling 
//* 
//***************************************************** 

/** 
* Creates the selection layer. 
* 
* @param context 
*/ 
protected void createSelectionLayer(Context context){ 

    LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    this.mSelectionDragLayer = (DragLayer) inflater.inflate(R.layout.selection_drag_layer, null); 


    // Make sure it's filling parent 
    this.mDragController = new DragController(context); 
    this.mDragController.setDragListener(this); 
    this.mDragController.addDropTarget(mSelectionDragLayer); 
    this.mSelectionDragLayer.setDragController(mDragController); 


    this.mStartSelectionHandle = (ImageView) this.mSelectionDragLayer.findViewById(R.id.startHandle); 
    this.mStartSelectionHandle.setTag(new Integer(SELECTION_START_HANDLE)); 
    this.mEndSelectionHandle = (ImageView) this.mSelectionDragLayer.findViewById(R.id.endHandle); 
    this.mEndSelectionHandle.setTag(new Integer(SELECTION_END_HANDLE)); 

    OnTouchListener handleTouchListener = new OnTouchListener(){ 

     @Override 
     public boolean onTouch(View v, MotionEvent event) { 

      boolean handledHere = false; 
      final int action = event.getAction(); 
      // Down event starts drag for handle. 
      if (action == MotionEvent.ACTION_DOWN) { 
       handledHere = startDrag (v); 
       mLastTouchedSelectionHandle = (Integer) v.getTag(); 
      } 
      return handledHere; 
     } 
    }; 

    this.mStartSelectionHandle.setOnTouchListener(handleTouchListener); 
    this.mEndSelectionHandle.setOnTouchListener(handleTouchListener); 


} 

/** 
* Starts selection mode on the UI thread 
*/ 
private Handler startSelectionModeHandler = new Handler(){ 

    public void handleMessage(Message m){ 

     if(mSelectionBounds == null) 
      return; 

     addView(mSelectionDragLayer); 

     drawSelectionHandles(); 


     int contentHeight = (int) Math.ceil(getDensityDependentValue(getContentHeight(), ctx)); 

     // Update Layout Params 
     ViewGroup.LayoutParams layerParams = mSelectionDragLayer.getLayoutParams(); 
     layerParams.height = contentHeight; 
     layerParams.width = contentWidth; 
     mSelectionDragLayer.setLayoutParams(layerParams); 

    } 

}; 

/** 
* Starts selection mode. 
* 
* @param selectionBounds 
*/ 
public void startSelectionMode(){ 

    this.startSelectionModeHandler.sendEmptyMessage(0); 

} 

// Ends selection mode on the UI thread 
private Handler endSelectionModeHandler = new Handler(){ 
    public void handleMessage(Message m){ 

     //Log.d("TableContentsWithDisplay", "in endSelectionModeHandler"); 

     removeView(mSelectionDragLayer); 
     if(getParent() != null && mContextMenu != null && contextMenuVisible){ 
      // This will throw an error if the webview is being redrawn. 
      // No error handling needed, just need to stop the crash. 
      try{ 
       mContextMenu.dismiss(); 
      } 
      catch(Exception e){ 

      } 
     } 
     mSelectionBounds = null; 
     mLastTouchedSelectionHandle = -1; 
     try { 
      ((Activity)ctx).runOnUiThread(new Runnable() { 

       @Override 
       public void run() { 
        loadUrl("javascript: android.selection.clearSelection();"); 
       } 
      }); 

     } catch (Exception e) { 
      // TODO: handle exception 
     } 

    } 
}; 

/** 
* Ends selection mode. 
*/ 
public void endSelectionMode(){ 

    this.endSelectionModeHandler.sendEmptyMessage(0); 

} 

/** 
* Calls the handler for drawing the selection handles. 
*/ 
private void drawSelectionHandles(){ 
    this.drawSelectionHandlesHandler.sendEmptyMessage(0); 
} 

/** 
* Handler for drawing the selection handles on the UI thread. 
*/ 
private Handler drawSelectionHandlesHandler = new Handler(){ 
    public void handleMessage(Message m){ 

     MyAbsoluteLayout.LayoutParams startParams = (com.epubreader.drag.MyAbsoluteLayout.LayoutParams) mStartSelectionHandle.getLayoutParams(); 
     startParams.x = (int) (mSelectionBounds.left - mStartSelectionHandle.getDrawable().getIntrinsicWidth()); 
     startParams.y = (int) (mSelectionBounds.top - mStartSelectionHandle.getDrawable().getIntrinsicHeight()); 

     // Stay on screen. 
     startParams.x = (startParams.x < 0) ? 0 : startParams.x; 
     startParams.y = (startParams.y < 0) ? 0 : startParams.y; 


     mStartSelectionHandle.setLayoutParams(startParams); 

     MyAbsoluteLayout.LayoutParams endParams = (com.epubreader.drag.MyAbsoluteLayout.LayoutParams) mEndSelectionHandle.getLayoutParams(); 
     endParams.x = (int) mSelectionBounds.right; 
     endParams.y = (int) mSelectionBounds.bottom; 
     endParams.x = (endParams.x < 0) ? 0 : endParams.x; 
     endParams.y = (endParams.y < 0) ? 0 : endParams.y; 

     mEndSelectionHandle.setLayoutParams(endParams); 

    } 
}; 

/** 
* Checks to see if this view is in selection mode. 
* @return 
*/ 
public boolean isInSelectionMode(){ 

    return this.mSelectionDragLayer.getParent() != null; 


} 

//***************************************************** 
//* 
//*  DragListener Methods 
//* 
//***************************************************** 

/** 
* Start dragging a view. 
* 
*/  
private boolean startDrag (View v) 
{ 
    // Let the DragController initiate a drag-drop sequence. 
    // I use the dragInfo to pass along the object being dragged. 
    // I'm not sure how the Launcher designers do this. 
    Object dragInfo = v; 
    mDragController.startDrag (v, mSelectionDragLayer, dragInfo, DragController.DRAG_ACTION_MOVE); 
    return true; 
} 


@Override 
public void onDragStart(DragSource source, Object info, int dragAction) { 
    // TODO Auto-generated method stub 

} 

@[email protected]("deprecation") 
public void onDragEnd() { 
    // TODO Auto-generated method stub 

    MyAbsoluteLayout.LayoutParams startHandleParams = (MyAbsoluteLayout.LayoutParams) this.mStartSelectionHandle.getLayoutParams(); 
    MyAbsoluteLayout.LayoutParams endHandleParams = (MyAbsoluteLayout.LayoutParams) this.mEndSelectionHandle.getLayoutParams(); 

    float scale = getDensityIndependentValue(this.getScale(), ctx); 

    float startX = startHandleParams.x - this.getScrollX(); 
    float startY = startHandleParams.y - this.getScrollY(); 
    float endX = endHandleParams.x - this.getScrollX(); 
    float endY = endHandleParams.y - this.getScrollY(); 

    startX = getDensityIndependentValue(startX, ctx)/scale; 
    startY = getDensityIndependentValue(startY, ctx)/scale; 
    endX = getDensityIndependentValue(endX, ctx)/scale; 
    endY = getDensityIndependentValue(endY, ctx)/scale; 


    if(mLastTouchedSelectionHandle == SELECTION_START_HANDLE && startX > 0 && startY > 0){ 
     final String saveStartString = String.format("javascript: android.selection.setStartPos(%f, %f);", startX, startY); 

     ((Activity)ctx).runOnUiThread(new Runnable() { 

      @Override 
      public void run() { 
       loadUrl(saveStartString); 
      } 
     }); 

    } 


    if(mLastTouchedSelectionHandle == SELECTION_END_HANDLE && endX > 0 && endY > 0){ 
     final String saveEndString = String.format("javascript: android.selection.setEndPos(%f, %f);", endX, endY); 

     ((Activity)ctx).runOnUiThread(new Runnable() { 

      @Override 
      public void run() { 
       loadUrl(saveEndString); 
      } 
     }); 

    } 



} 


//***************************************************** 
//* 
//*  Context Menu Creation 
//* 
//***************************************************** 

/** 
* Shows the context menu using the given region as an anchor point. 
* @param region 
*/ 
private void showContextMenu(Rect displayRect){ 

    // Don't show this twice 
    if(this.contextMenuVisible){ 
     return; 
    } 

    // Don't use empty rect 
    //if(displayRect.isEmpty()){ 
    if(displayRect.right <= displayRect.left){ 
     return; 
    } 

    //Copy action item 
    ActionItem buttonOne = new ActionItem(); 

    buttonOne.setTitle("HighLight"); 
    buttonOne.setActionId(1); 
    //buttonOne.setIcon(getResources().getDrawable(R.drawable.menu_search)); 


    //Highlight action item 
    ActionItem buttonTwo = new ActionItem(); 

    buttonTwo.setTitle("Note"); 
    buttonTwo.setActionId(2); 
    //buttonTwo.setIcon(getResources().getDrawable(R.drawable.menu_info)); 

    ActionItem buttonThree = new ActionItem(); 

    buttonThree.setTitle("Help"); 
    buttonThree.setActionId(3); 
    //buttonThree.setIcon(getResources().getDrawable(R.drawable.menu_eraser)); 



    // The action menu 
    mContextMenu = new QuickAction(this.getContext()); 
    mContextMenu.setOnDismissListener(this); 

    // Add buttons 
    mContextMenu.addActionItem(buttonOne); 

    mContextMenu.addActionItem(buttonTwo); 

    mContextMenu.addActionItem(buttonThree); 



    //setup the action item click listener 
    mContextMenu.setOnActionItemClickListener(new QuickAction.OnActionItemClickListener() { 

     @Override 
     public void onItemClick(QuickAction source, int pos, 
      int actionId) { 

      if (actionId == 1) { 

       callHighLight(); 
      } 
      else if (actionId == 2) { 

       callNote(); 
      } 
      else if (actionId == 3) { 
       // Do Button 3 stuff 
       Log.i(TAG, "Hit Button 3"); 
      } 

      contextMenuVisible = false; 

     } 

    }); 

    this.contextMenuVisible = true; 
    mContextMenu.show(this, displayRect); 
} 

private void callHighLight(){ 

    ((Activity)this.ctx).runOnUiThread(new Runnable() { 

     @Override 
     public void run() { 
      loadUrl("javascript:init_txt_selection_event()"); 
      loadUrl("javascript:highlightme_("+0+")"); 
     } 
    }); 

} 

private void callNote(){ 

    ((Activity)this.ctx).runOnUiThread(new Runnable() { 

     @Override 
     public void run() { 
      loadUrl("javascript:init_txt_selection_event()"); 
      loadUrl("javascript:fnGetUserAddedNote('1')"); 
     } 
    }); 

} 


//***************************************************** 
//* 
//*  OnDismiss Listener 
//* 
//***************************************************** 
/** 
* Clears the selection when the context menu is dismissed. 
*/ 
public void onDismiss(){ 
    //clearSelection(); 
    this.contextMenuVisible = false; 
} 

//***************************************************** 
//* 
//*  Text Selection Javascript Interface Listener 
//* 
//***************************************************** 
/** 
* The user has started dragging the selection handles. 
*/ 
public void tsjiStartSelectionMode(){ 

    this.startSelectionMode(); 


} 

/** 
* The user has stopped dragging the selection handles. 
*/ 
public void tsjiEndSelectionMode(){ 

    this.endSelectionMode(); 
} 

/** 
* The selection has changed 
* @param range 
* @param text 
* @param handleBounds 
* @param menuBounds 
* @param showHighlight 
* @param showUnHighlight 
*/@SuppressWarnings("deprecation") 
public void tsjiSelectionChanged(String range, String text, String handleBounds, String menuBounds){ 
    try { 

     //Log.d(TAG, "tsjiSelectionChanged :- handleBounds " + handleBounds); 
     JSONObject selectionBoundsObject = new JSONObject(handleBounds); 

     float scale = getDensityIndependentValue(this.getScale(), ctx); 

     Rect handleRect = new Rect(); 
     handleRect.left = (int) (getDensityDependentValue(selectionBoundsObject.getInt("left"), getContext()) * scale); 
     handleRect.top = (int) (getDensityDependentValue(selectionBoundsObject.getInt("top"), getContext()) * scale); 
     handleRect.right = (int) (getDensityDependentValue(selectionBoundsObject.getInt("right"), getContext()) * scale); 
     handleRect.bottom = (int) (getDensityDependentValue(selectionBoundsObject.getInt("bottom"), getContext()) * scale); 

     this.mSelectionBounds = handleRect; 
     this.selectedRange = range; 
     this.selectedText = text; 

     JSONObject menuBoundsObject = new JSONObject(menuBounds); 

     Rect displayRect = new Rect(); 
     displayRect.left = (int) (getDensityDependentValue(menuBoundsObject.getInt("left"), getContext()) * scale); 
     displayRect.top = (int) (getDensityDependentValue(menuBoundsObject.getInt("top") - 25, getContext()) * scale); 
     displayRect.right = (int) (getDensityDependentValue(menuBoundsObject.getInt("right"), getContext()) * scale); 
     displayRect.bottom = (int) (getDensityDependentValue(menuBoundsObject.getInt("bottom") + 25, getContext()) * scale); 

     if(!this.isInSelectionMode()){ 
      this.startSelectionMode(); 
     } 

     // This will send the menu rect 
     this.showContextMenu(displayRect); 

     drawSelectionHandles(); 


    } catch (JSONException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 


} 


/** 
* Receives the content width for the page. 
*/ 
public void tsjiSetContentWidth(float contentWidth){ 
    this.contentWidth = (int) this.getDensityDependentValue(contentWidth, ctx); 
} 


//***************************************************** 
//* 
//*  Density Conversion 
//* 
//***************************************************** 
/** 
* Returns the density dependent value of the given float 
* @param val 
* @param ctx 
* @return 
*/ 
public float getDensityDependentValue(float val, Context ctx){ 
    // Get display from context 
    Display display = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 
    // Calculate min bound based on metrics 
    DisplayMetrics metrics = new DisplayMetrics(); 
    display.getMetrics(metrics); 
    return val * (metrics.densityDpi/160f); 
} 

/** 
* Returns the density independent value of the given float 
* @param val 
* @param ctx 
* @return 
*/ 
public float getDensityIndependentValue(float val, Context ctx){ 

    // Get display from context 
    Display display = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); 
    // Calculate min bound based on metrics 
    DisplayMetrics metrics = new DisplayMetrics(); 
    display.getMetrics(metrics); 
    return val/(metrics.densityDpi/160f); 
} 

}

cảm ơn trước!

+1

Bạn có thể vui lòng đăng cách bạn triển khai onLongClick() không? Trên GalaxyS3 của tôi (OS 4.1.2) nó chạy với không có vấn đề và tôi thành công overriden nó vì vậy tôi không hiển thị các chế độ hành động. – gunar

+0

@gunar Tôi đã chỉnh sửa câu hỏi của mình bằng cách thêm mã webview tùy chỉnh, mã này có cả phương thức onLongClick cũng như bản sao của onLongClick sử dụng longClickRunnable, longClickHandler, phần còn lại của mã và lớp hỗ trợ cho Drag & Drop là cùng một dự án mẫu từ https : //github.com/btate/BTAndroidWebViewSelection – sachin003

+0

@gunar Tôi đã thử nghiệm cùng một mã trên GalaxyS3 OS 4.1.2 nó hoạt động tốt, ngăn chế độ chọn văn bản của webview và hiển thị tùy chọn lựa chọn văn bản mặc định của tôi, nhưng cùng một mã không làm việc trên Samsung Tablet 10 inch với hệ điều hành 4.1.2 – sachin003

Trả lời

0

Tôi có thể đề xuất giải pháp cho việc này. Bạn có thể sử dụng setOnTouchListener và sau đó tự mình thực hiện báo chí dài.

onTouch -- 

case MotionEvent.ACTION_DOWN: 
        mHanlder.removeCallbacks(startActionBar); 
        mHandler.postDelayed(startActionBar,1000); 

Bằng cách này bạn có thể đạt được cùng một điểm.

+0

Phần này là ok nhưng nó cũng hiển thị Thanh tác vụ theo ngữ cảnh mặc định (CAB) và thay đổi kích thước chế độ xem web, trong trường hợp của tôi, tôi muốn tránh CAB mặc định. – sachin003

+0

Cũng vô hiệu hóa nhấp chuột dài cho chế độ xem web. 'this.setLongClickable (false);' – blganesh101

+0

@ blganesh101 nó có thể hoạt động trên hầu hết các thiết bị nhưng không phải trên Samsung Galaxy Tab trên Android 4.1.2 như được chỉ định trong câu hỏi – Guillaume

0

một số lý do khiến KeyEvent giảm xuống & không hoạt động trong API LEVEL 16+ (Android 4.1+ JELLY_BEAN). Nó không kích hoạt loadUrl của WebView. Vì vậy, tôi đã phải thay thế dispatchKeyEvent bằng dispatchTouchEvent. Dưới đây là các mã:

... 
MotionEvent touchDown = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, touchX, touchY, 0); 
webView.dispatchTouchEvent(touchDown); 
touchDown.recycle(); 

MotionEvent touchUp = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, touchX, touchY, 0); 
webView.dispatchTouchEvent(touchUp); 
touchUp.recycle(); 

String url = mUrl; 
... 

thử nó ..

0

Đối với việc vô hiệu hóa văn bản đã chọn từ webview thử này,

webView.setWebChromeClient(new WebChromeClient(){ 

    [.... other overrides....] 

    // @Override 
    // https://bugzilla.wikimedia.org/show_bug.cgi?id=31484 
    // If you DO NOT want to start selection by long click, 
    // the remove this function 
    // (All this is undocumented stuff...) 
    public void onSelectionStart(WebView view) { 
     // By default we cancel the selection again, thus disabling 
     // text selection unless the chrome client supports it. 
     // view.notifySelectDialogDismissed(); 
    } 

}); 
+1

Tôi đã cố gắng ghi đè phương pháp onSelectionStart nhưng không có phương pháp ghi đè nào , Tôi sử dụng copy-pase & eclipse mang lại cho tôi "Phương thức onSelectionStart (WebView) từ loại WebChromeClient mới() {} không bao giờ được sử dụng cục bộ" – sachin003

0

Bạn cũng có thể thử trọng View.performLongClick(), có trách nhiệm để gọi View.onLongPress(). Bạn cũng có thể thử đi tới các sự kiện báo chí dài của Chế độ xem của phụ huynh. Hoặc tất cả các con đường lên đến Window.Callback cho hoạt động của bạn (thông qua Activity.getWindow(). Get/setCallback()).

Tôi tự hỏi liệu có cách nào khác để menu ngữ cảnh lựa chọn chuẩn xuất hiện bên cạnh sự kiện báo chí dài, ví dụ như với bàn phím trackball hoặc phần cứng.

0

trong trường hợp ai đó đang cố gắng để chỉ cần loại bỏ các lựa chọn văn bản mặc định, tôi đã cùng một vấn đề trên Samsung Galaxy Tab trên Android 4.1.2 và kết thúc bằng văn bản riêng WebView tôi:

public class CustomWebView extends WebView { 

    public CustomWebView(Context context) { 
    super(context); 
    this.setUp(context); 
    } 

    public CustomWebView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    this.setUp(context); 
    } 

    public CustomWebView(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
    this.setUp(context); 
    } 

    private void setUp(Context context) { 
    this.setOnLongClickListener(new OnLongClickListener() { 
     @Override 
     public boolean onLongClick(View v) { 
     return true; 
     } 
    }); 
    this.setLongClickable(false); 
    } 

    @Override 
    public boolean performLongClick() { 
    return true; 
    } 

} 

và giới thiệu nó trong xml của tôi:

<com...CustomWebView 
    android:id="@+id/webview" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" /> 
0

Sử dụng setOnTouchListener() thực hiện báo chí dài

2

Sử dụng có thể các setOnTouchListener() lâu dài/ngắn nhấn. và trả về true để không có gì xảy ra do đó sẽ ghi đè tính năng chọn văn bản mặc định.

1

Tôi đã có thể giải quyết vấn đề này. Tôi cũng phải đối mặt với vấn đề này và không thể tìm thấy bất kỳ giải pháp nào trên web.

Vì vậy, nếu bạn thiết lập trình nghe LongClick, thì Webview sẽ ngừng hiển thị lựa chọn. Sau khi đào sâu vào mã Webview, tôi thấy rằng nó đang gọi phương thức startRunMode của WebView và truyền một thể hiện của lớp SelectActionCallbackMode.

Tôi chỉ đơn giản là mở rộng các lớp Webview và overrided phương pháp startRunMode như thế này:

public ActionMode startActionMode(ActionMode.Callback callback) 
{ 
    actionModeCallback = new CustomizedSelectActionModeCallback(); 
    return super.startActionMode(actionModeCallback); 
} 

Điều này buộc WebView để hiển thị Callback của tôi thay vì hiển thị mặc định một Webview của. Điều này đảm bảo rằng lựa chọn hoạt động trơn tru như trước và CAB của tôi được hiển thị mỗi lần lựa chọn được thực hiện. Chỉ cần báo trước là tôi phải viết mã để loại bỏ bản thân CAB.

Thử nghiệm trên các thiết bị 4.1, 4.2 và 4.3.

Hy vọng điều này sẽ hữu ích.

4

Tôi nhận thấy đây là một câu hỏi cũ, nhưng không có câu trả lời được chấp nhận và không có câu trả lời nào được cung cấp có nhiều phiếu bầu.

Tôi đã đạt được những gì bạn đang cố gắng thực hiện bằng cách tạo gọi lại chế độ hành động tùy chỉnh. Điều này cho phép tạo thanh tác vụ theo ngữ cảnh tùy chỉnh (CAB) khi (trong trường hợp là WebView) người dùng nhấp chuột lâu vào chế độ xem. LƯU Ý: Điều này chỉ hoạt động ở 4.0+ và một phần chỉ hoạt động ở 4.4.

Tạo tệp XML Android mới chứa bố cục cho trình đơn tùy chỉnh của bạn. Đây là mỏ (context_menu.xml) là một ví dụ:

<?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" <!-- Forces this button to be shown --> 
     android:title="@string/copy"> 
    </item> 
    <item 
     android:id="@+id/button2" 
     android:icon="@drawable/menu_button2icon" 
     android:showAsAction="ifRoom" <!-- Show if there is room on the screen--> 
     android:title="@string/button2"> 
    </item> 
    <!-- Add as many more items as you want. 
     Note that if you use "ifRoom", an overflow menu will populate 
     to hold the action items that did not fit in the action bar. --> 

</menu> 

Bây giờ menu được định nghĩa, tạo ra một cuộc gọi lại cho nó:

public class CustomWebView extends WebView { 

    private ActionMode.Callback mActionModeCallback; 

    private class CustomActionModeCallback implements ActionMode.Callback { 

     // Called when the action mode is created; startActionMode() was called 
     @Override 
     public boolean onCreateActionMode(ActionMode mode, Menu menu) { 
      // Inflate a menu resource providing context menu items 
      MenuInflater inflater = mode.getMenuInflater(); 
      inflater.inflate(R.menu.context_menu, menu); 
      return true; 
     } 

     // Called each time the action mode is shown. 
     // Always called after onCreateActionMode, but 
     // may be called multiple times if the mode is invalidated. 
     @Override 
     public boolean onPrepareActionMode(ActionMode mode, Menu menu) { 
      // Note: This is called every time the selection handlebars move. 
      return false; // Return false if nothing is done 
     } 

     // Called when the user selects a contextual menu item 
     @Override 
     public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 

      switch (item.getItemId()) { 
       case R.id.copy: 
       // Do some stuff for this button 
        mode.finish(); // Action picked, so close the CAB 
        return true; 
       case R.id.button2: 
       // Do some stuff for this button 
        mode.finish(); 
        return true; 
       // Create a case for every item 
       ... 
       default: 
        mode.finish(); 
        return false; 
      } 
     } 

     // Called when the user exits the action mode 
     @Override 
     public void onDestroyActionMode(ActionMode mode) { 
      // This will clear the selection highlight and handlebars. 
      // However, it only works in 4.4; I am still investigating 
      // how to reliably clear the selection in 4.3 and earlier 
      clearFocus(); 
     } 
} 

Một khi những mảnh được đưa ra, ghi đè lên các phương pháp startActionMode để gọi lại thực sự sẽ xảy ra trên một chặng đường dài-click:

public class CustomWebView extends WebView { 
    @Override 
    public ActionMode startActionMode(Callback callback) { 
     ViewParent parent = getParent(); 
     if (parent == null) { 
     return null; 
     } 
     mActionModeCallback = new CustomActionModeCallback(); 
     return parent.startActionModeForChild(this, mActionModeCallback); 
    } 
} 

Bây giờ bạn có một menu tùy chỉnh sẽ được xuất hiện và cư khi người dùng nhấp chuột dàicủa bạn. Để tham khảo, tôi tìm thấy thông tin này từ một số Android Developer tutorial và sửa đổi đề xuất từ ​​this answer.

Lưu ý cuối cùng: Kỹ thuật này ghi đè trình đơn bản sao/dán gốc cho văn bản đã chọn. Nếu bạn muốn duy trì chức năng đó, bạn sẽ cần phải thực hiện nó cho mình. (Đó là lý do tại sao nút đầu tiên của tôi là 'sao chép'.) Nếu bạn cần, hãy tham khảo this Google tutorial để biết thêm thông tin và cách thích hợp để triển khai.

+0

Giải pháp tuyệt vời! Sau vài ngày tôi tìm thấy bài đăng của bạn. Cảm ơn +1 –

+0

Tôi đã thực hiện một giải pháp tương tự, nhưng có một vấn đề. Tôi có 7 mục tùy chỉnh, nhưng 3 trong số chúng không thể xem được vì chúng nằm ngoài tầm nhìn. Có thể cuộn trong menu chọn văn bản không? @SciJoker – Muddz

+0

Làm cách nào để mở cửa sổ bật lên tùy chỉnh nếu người dùng sao chép văn bản từ chế độ xem web? hãy giúp tôi ra cho rằng :) –