如何覆盖android webview os 4.1+的默认文本select?

在发布这个问题之前,我已经search了很多,但在这个问题上找不到任何明确的答案。

我必须重写android webview的默认文本select&显示我的自定义文本select对话框选项。 我已经尝试过这个示例代码项目 。

此示例项目适用于以下设备和仿真器:

  • macros碁Iconia a500平板电脑:10英寸:Android操作系统 – 3.0
  • macros基Iconia a500平板电脑:10英寸:Android操作系统 – 3.2
  • 三星Galaxy Tab:10英寸:Android操作系统 – 4.0
  • 三星Galaxy Tab:7英寸:Android操作系统 – 4.0
  • 模拟器:皮肤WVGA800:Android操作系统 – 4.1.2

不适用于以下设备:

  • 三星Galaxy Tab:10英寸:Android操作系统 – 4.1.2
  • 三星Galaxy Tab:7英寸:Android操作系统 – 4.1.2

在Android操作系统版本4.1和4.1+而不是显示我的自定义文本select选项对话框,它显示了Android系统的文本select的默认操作栏。

我在这方面search了很多,很多人build议使用onLongClick()方法的接口

我已经在这个论坛上提出了一个问题,请看这个链接 ,这个问题的答案我可以克隆onClickClick()事件,但我不能停止默认的文本select操作栏。

对于这个场景我有几个问题。

为什么onLongClick()方法停止工作在Android操作系统版本4.1 +上运行的设备?

2.如何停止长时间在webview文本上按默认的文本select操作栏?

这是我自定义的webview类。

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 } @Override@SuppressWarnings("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); } 

}

提前致谢!

我意识到这是一个古老的问题,但没有一个被接受的答案,没有提供的答案有很多票。

我已经通过创build自定义操作模式callback来实现您正在尝试完成的任务。 这允许创build一个自定义上下文操作栏(CAB)时(在WebView的情况下)用户长期点击视图。 注意:这只适用于4.0+,一件只适用于4.4。

创build一个包含自定义菜单布局的新的Android XML文件。 下面是我的(context_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" <!-- 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> 

现在菜单被定义了,为它创build一个callback:

 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(); } } 

一旦这些部分到位,重写startActionMode方法,以便实际上发生在长按一下的callback:

 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); } } 

现在,您有一个自定义菜单,当用户长按WebView时,它将出现并填充。 作为参考,我从Android开发人员教程中find了这些信息,并从这个答案中修改了这个build议。

最后一个注意事项:这种技术覆盖选定文本的本地复制/粘贴菜单。 如果你想保持这个function,你将需要自己实现它。 (这就是为什么我的第一个button是“复制”。)如果你需要这个,请参阅这个Google教程 ,了解更多信息以及实现它的正确方法。

可以使用setOnTouchListener()进行长/短的长按。 并返回true,以免发生任何事情,从而覆盖默认的文本selectfunction。

我已经能够解决这个问题了。 我也遇到了这个问题,在网上找不到任何解决scheme。

所以,如果你设置了一个LongClick监听器,Webview将不再显示select。 深入研究Webview代码之后,我发现它调用了WebView的方法startRunMode并传递了SelectActionCallbackMode类的一个实例。

我简单地扩展了Webview类,并像这样覆盖了startRunMode方法:

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

这迫使Webview显示我的callback,而不是显示Webview的默认值。 这确保select工作和以前一样顺利,每次select时都显示我的CAB。 唯一需要注意的是我必须自己写代码才能解散CAB。

testing4.1,4.2和4.3设备。

希望这可以帮助。

我可以build议一个解决方法。 你可以使用setOnTouchListener ,然后自己实现长按。

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

这样你就可以达到同样的效果。

某些原因,KeyEvent down&up在API LEVEL 16+(Android 4.1+ JELLY_BEAN)中不起作用。 它不会触发WebView的loadUrl。 所以我不得不用dispatchTouchEventreplacedispatchKeyEvent。 代码如下:

 ... 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; ... 

尝试一下..

为了禁止从webview中select文字,试试这个,

 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(); } }); 

你也可以重写View.perLongClick(),它负责调用View.onLongPress()。 你也可以尝试去查看父视图的长按事件。 或者一直到您的活动的Window.Callback(通过Activity.getWindow()。get / setCallback())。

我想知道是否有其他方式的标准select上下文菜单出现除了长按事件,例如也许跟踪球或硬件键盘。

如果有人试图简单地删除默认的文本select,我在Android 4.1.2上的三星Galaxy Tab上有同样的问题,并最终编写我自己的WebView

 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; } } 

并在我的XML中引用它:

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

使用setOnTouchListener()实现长按