我已使用this guide from Google和this tutorial来制作我自己的上下文操作栏。
private ActionMode.Callback mActionModeCallback = new 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.annotation_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) {
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.custom_button:
// do some stuff
break;
case R.id.custom_button2:
// do some other stuff
break;
default:
// This essentially acts as a catch statement
// If none of the other cases are true, return false
// because the action was not handled
return false;
}
finish(); // An action was handled, so close the CAB
return true;
}
// Called when the user exits the action mode
@Override
public void onDestroyActionMode(ActionMode mode) {
mActionMode = null;
}
};
此菜单旨在在用户选择文本时显示,因此它会覆盖本机复制/粘贴菜单。现在我谈到我的问题。
由于我正在覆盖文本选择功能,因此我还向LongClickListener
添加了WebView
并实施了onLongClick(View v)
方法,以便我可以检测用户何时进行选择。
myWebView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mActionMode != null) {
return false;
}
mActionMode = startActionMode(mActionModeCallback);
v.setSelected(true);
return true;
}
});
当我长按时,我看到我的自定义菜单出现,但没有突出显示文字。
我需要有文本选择功能;没有它,我的菜单毫无意义。
如何覆盖onLongClick(View v)
,但保留Android提供的文字选择?
如果无法做到这一点,我是否可以在其他地方拨打startActionMode(mActionModeCallback)
电话,以便文字显示正常选择,但我的自定义菜单也会出现?
如果这些都不可能......帮助。
答案 0 :(得分:34)
有一个更简单的方法!请参阅以下更新:D
<小时/> 为了完整起见,以下是我解决问题的方法:
我按照this answer的建议进行了调整,稍加调整以更接近地匹配被覆盖的代码:
public class MyWebView extends WebView {
private ActionMode mActionMode;
private mActionMode.Callback mActionModeCallback;
@Override
public ActionMode startActionMode(Callback callback) {
ViewParent parent = getParent();
if (parent == null) {
return null;
}
mActionModeCallback = new CustomActionModeCallback();
return parent.startActionModeForChild(this, mActionModeCallback);
}
}
基本上,这会强制您的自定义CAB显示而不是Android CAB。现在你必须修改你的回调,以便文本高亮显示将与CAB一起消失:
public class MyWebView extends WebView {
...
private class CustomActionModeCallback implements ActionMode.Callback {
...
// Everything up to this point is the same as in the question
// Called when the user exits the action mode
@Override
public void onDestroyActionMode(ActionMode mode) {
clearFocus(); // This is the new code to remove the text highlight
mActionMode = null;
}
}
}
这就是它的全部。请注意,只要您将MyWebView
与被覆盖的startActionMode
一起使用,就无法获得本机CAB(复制/粘贴菜单,如果是WebView)。有可能实现这种行为,但这不是这段代码的工作方式。
此解决方案对ActionMode
的控制较少,但它需要的代码远少于上述解决方案。
public class MyActivity extends Activity {
private ActionMode mActionMode = null;
@Override
public void onActionModeStarted(ActionMode mode) {
if (mActionMode == null) {
mActionMode = mode;
Menu menu = mode.getMenu();
// Remove the default menu items (select all, copy, paste, search)
menu.clear();
// If you want to keep any of the defaults,
// remove the items you don't want individually:
// menu.removeItem(android.R.id.[id_of_item_to_remove])
// Inflate your own menu items
mode.getMenuInflater().inflate(R.menu.my_custom_menu, menu);
}
super.onActionModeStarted(mode);
}
// This method is what you should set as your item's onClick
// <item android:onClick="onContextualMenuItemClicked" />
public void onContextualMenuItemClicked(MenuItem item) {
switch (item.getItemId()) {
case R.id.example_item_1:
// do some stuff
break;
case R.id.example_item_2:
// do some different stuff
break;
default:
// ...
break;
}
// This will likely always be true, but check it anyway, just in case
if (mActionMode != null) {
mActionMode.finish();
}
}
@Override
public void onActionModeFinished(ActionMode mode) {
mActionMode = null;
super.onActionModeFinished(mode);
}
}
以下是一个示例菜单,可帮助您入门:
<!-- my_custom_menu.xml -->
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/example_item_1"
android:icon="@drawable/ic_menu_example_1"
android:showAsAction="always"
android:onClick="onContextualMenuItemClicked"
android:title="@string/example_1">
</item>
<item
android:id="@+id/example_item_2"
android:icon="@drawable/ic_menu_example_2"
android:showAsAction="ifRoom"
android:onClick="onContextualMenuItemClicked"
android:title="@string/example_2">
</item>
</menu>
就是这样!你完成了!现在您的自定义菜单将显示,您不必担心选择,您几乎不必关心ActionMode
生命周期。
这种方法几乎完美无缺,WebView
占据了整个父Activity
。如果您的View
内同时有多个Activity
,我不确定它的效果如何。在这种情况下,可能需要进行一些调整。
答案 1 :(得分:0)
我做类似事情的方式是只覆盖onTouchListener并调用GestureDetector来检测WebView被长按的时间并从那里做我想做的事情。这里有一些示例代码,可以让您在不牺牲WebView中的文本选择的情况下捕获长按事件。希望这会有所帮助。
@Override
protected void onCreate(Bundle savedInstanceState) {
WebView mWebView = (WebView) findViewById(R.id.myWebView);
GestureDetector mGestureDetector = new GestureDetector(this, new CustomGestureListener());
mWebView.setOnTouchListener(new OnTouchListener(){
@Override
public boolean onTouch(View view, MotionEvent arg1) {
//Suggestion #1 - this just lets the touch to be handled by the system but allows you to detect long presses
mGestureDetector.onTouchEvent(arg1);
return false;
//Suggestion #2 - this code will only let the touch be handled by the system if you don't detect a long press
return mGestureDetector.onTouchEvent(arg1);
}
});
}
private class CustomGestureListener extends SimpleOnGestureListener {
@Override
public void onLongPress(MotionEvent e) {
//do stuff
}
}