Webview文本select不清除

我已经为ActionMode.Callback中的自定义文本selectfunction实现了一个ActionMode.Callback 。 我有的问题是select和动作模式状态不匹配。

当我长时间按下时,一切都开始顺利。

长按之后,选择高亮显示以及上下文操作栏。

当我与其中一个button或WebView交互(不包括实际select)时, ActionMode应该被销毁,select应该消失。

选择一个按钮,或触摸选择区域外。CAB应该关闭,选择应该消失。

在Android 4.4,KitKat中,这正是发生的事情。


但是,这并不是4.1.1-4.3中所发生的,果冻豆。 当我点击其中一个button时,select不会被删除。

点击上下文操作栏中的按钮。点击一个按钮后,选择保持不变。

当我select外面时,恰好相反。 select被删除,但上下文操作栏保留在屏幕上。

在选择开始之后点击<code> WebView </ code>。选择被清除,但上下文操作栏保持不变。


这是我的CustomWebView的代码

 public class CustomWebView extends WebView { private ActionMode.Callback mActionModeCallback; @Override public ActionMode startActionMode(Callback callback) { ViewParent parent = getParent(); if (parent == null) { return null; } mActionModeCallback = new CustomActionModeCallback(); return parent.startActionModeForChild(this, 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.contextual_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) { // This method is called when the handlebars are moved. loadJavascript("javascript:getSelectedTextInfo()"); 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.button_1: // do stuff break; ... default: break; } mode.finish(); // Action picked, so close the CAB return true; } // Called when the user exits the action mode @Override public void onDestroyActionMode(ActionMode mode) { // TODO This does not work in Jelly Bean (API 16 - 18; 4.1.1 - 4.3). clearFocus(); // Remove the selection highlight and handles. } } } 

正如上面的评论显示,我相信问题是与clearFocus()方法。 当我删除这个方法时,按下一个button就会把select留在4.4中,就像Jelly Bean中的行为一样。 clearFocus()在4.4中给出了预期的行为,但不会传递给更早的API。 (注意clearFocus()对于KitKat来说不是新的;从API 1开始,它已经在Android中了)

这怎么解决?

Related of "Webview文本select不清除"

经过多次尝试解决这个,我终于明白了!

要实现的重要一点是Android 4.4(KitKat)之前的WebView与典型的浏览器不同。 有几个隐藏的课程开始搞乱事情。 WebViewCore完成所有繁重的工作,实际上产生了结果,而WebViewClassic就是这个问题的罪魁祸首。

该解决scheme是一个半黑客攻击,因为您不必操纵任何底层类,但是您必须抓住问题场景。

WebViewClassic负责截取长按和处理文本select,包括select高亮和select句柄的animation,以及启动填充上下文操作栏(CAB)的ActionMode 。 不幸的是,由于我们想用我们自己的方式覆盖ActionMode ,所以文本select和CAB不同步,因为它们不相互关联。 要解决这个问题,请跟踪您自己的自定义ActionMode.Callback 以及与selectanimation关联的ActionMode.Callback 。 然后,当你的ActionMode.Callback被销毁时,调用select的finish()方法来销毁该ActionMode.Callback

好,说够了。 这是代码。

 public class CustomWebView extends WebView { private ActionMode mActionMode; private ActionMode.Callback mActionModeCallback; // Add this class variable private ActionMode.Callback mSelectActionModeCallback; @Override public ActionMode startActionMode(Callback callback) { /* When running Ice Cream Sandwich (4.0) or Jelly Bean (4.1 - 4.3), there * is a hidden class called 'WebViewClassic' that draws the selection. * In order to clear the selection, save the callback from Classic * so it can be destroyed later. */ // Check the class name because WebViewClassic.SelectActionModeCallback // is not public API. String name = callback.getClass().toString(); if (name.contains("SelectActionModeCallback")) { mSelectActionModeCallback = callback; } mActionModeCallback = new CustomActionModeCallback(); // We haven't actually done anything yet. Send our custom callback // to the superclass so it will be shown on screen. return super.startActionModeForChild(this, 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) { // This is important for part 2. mActionMode = mode; // Inflate a menu resource providing context menu items MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.contextual_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) { // This method is called when the handlebars are moved. loadJavascript("javascript:getSelectedTextInfo()"); 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.button_1: // do stuff break; ... default: break; } mode.finish(); // Action picked, so close the CAB return true; } // Called when the user exits the action mode @Override public void onDestroyActionMode(ActionMode mode) { clearFocus(); // Remove the selection highlight and handles. // Semi-hack in order to clear the selection // when running Android earlier than KitKat. if (mSelectActionModeCallback != null) { mSelectActionModeCallback.onDestroyActionMode(mode); } // Relevant to part 2. mActionMode = null; } } } 


相信与否,我们只完成了一半。 上面的代码负责在CABclosures时删除select。 为了在触摸事件中closuresCAB,我们必须做更多的工作。 这一次更简单。 我使用一个GestureDetector并听一个单击事件。 当我得到这个事件,我打电话给finish()mActionModeclosuresCAB:

 public class CustomWebView extends WebView { private ActionMode mActionMode; private ActionMode.Callback mActionModeCallback; private ActionMode.Callback mSelectActionModeCallback; // Code from above segment ... private class CustomGestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onSingleTapUp(MotionEvent e) { if (mActionMode != null) { mActionMode.finish(); return true; } return false; } } @Override public boolean onTouchEvent(MotionEvent event) { // Send the event to our gesture detector // If it is implemented, there will be a return value this.mDetector.onTouchEvent(event); // If the detected gesture is unimplemented, send it to the superclass return super.onTouchEvent(event); } } 


这应该做到这一点! 我们做到了!

您不会在其他地方findWebViewClassic材质; 这就是为什么我提供了如此详细的事情。 debugging器花了好几个小时才弄清楚发生了什么事情。 幸运的是, GestureDetector类有很好的文档logging,并包含多个教程。 我从Android Developers网站获得了我的信息。 我希望这能帮助那些和我一样挣扎于这个问题的人。 🙂