用于EditText的自定义剪切/复制操作栏,显示文本select手柄

我有一个应用程序,我希望能够显示一个TextView(或EditText),允许用户select一些文本,然后按下button来完成一些文本。 在Honeycomb之前的Android版本上实现这个function是没有问题的,但是在Honeycomb上,默认的长按操作之上是显示带有Copy / Cut / Paste选项的操作栏。 我可以拦截长按来显示我自己的操作栏,但是我没有得到显示的文本select句柄。

一旦我开始了自己的ActionMode,我怎样才能显示文本select句柄?

这里是我用来启动ActionMode的代码,除了没有显示文本select句柄外,

public boolean onLongClick(View v) { if(actionMode == null) actionMode = startActionMode(new QuoteCallback()); return true; } class QuoteCallback implements ActionMode.Callback { public boolean onCreateActionMode(ActionMode mode, Menu menu) { MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.quote, menu); return true; } public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch(item.getItemId()) { case R.id.quote: Log.d(TAG, "Selected menu"); mode.finish(); // here is where I would grab the selected text return true; } return false; } public void onDestroyActionMode(ActionMode mode) { actionMode = null; } } 

我想出了自己的问题的答案。 TextView(因此EditText)有一个方法setCustomSelectionActionModeCallback()应该用来代替startActionMode() 。 使用此function可以自定义TextView用于文本select的菜单。 示例代码:

 bodyView.setCustomSelectionActionModeCallback(new StyleCallback()); 

StyleCallback通过删除“全选”并添加一些样式操作来自定义文本select菜单:

 class StyleCallback implements ActionMode.Callback { public boolean onCreateActionMode(ActionMode mode, Menu menu) { Log.d(TAG, "onCreateActionMode"); MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.style, menu); menu.removeItem(android.R.id.selectAll); return true; } public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } public boolean onActionItemClicked(ActionMode mode, MenuItem item) { Log.d(TAG, String.format("onActionItemClicked item=%s/%d", item.toString(), item.getItemId())); CharacterStyle cs; int start = bodyView.getSelectionStart(); int end = bodyView.getSelectionEnd(); SpannableStringBuilder ssb = new SpannableStringBuilder(bodyView.getText()); switch(item.getItemId()) { case R.id.bold: cs = new StyleSpan(Typeface.BOLD); ssb.setSpan(cs, start, end, 1); bodyView.setText(ssb); return true; case R.id.italic: cs = new StyleSpan(Typeface.ITALIC); ssb.setSpan(cs, start, end, 1); bodyView.setText(ssb); return true; case R.id.underline: cs = new UnderlineSpan(); ssb.setSpan(cs, start, end, 1); bodyView.setText(ssb); return true; } return false; } public void onDestroyActionMode(ActionMode mode) { } } 

添加菜单的XML是:

 <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/italic" android:showAsAction="always" android:icon="@drawable/italic" android:title="Italic"/> <item android:id="@+id/bold" android:showAsAction="always" android:icon="@drawable/bold" android:title="Bold"/> <item android:id="@+id/underline" android:showAsAction="always" android:icon="@drawable/underline" android:title="Underline"/> </menu> 

如果您想要自定义操作栏中的选项,上面的解决scheme是很好的。 但如果你想覆盖操作栏复制/粘贴等,下面是代码…

 public class MainActivity extends Activity { EditText editText; private ClipboardManager myClipboard; private ClipData myClip; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myClipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); editText = (EditText) findViewById(R.id.editText3); myClipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); editText = (EditText) findViewById(R.id.editText3); editText.setCustomSelectionActionModeCallback(new Callback() { @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { // TODO Auto-generated method stub return false; } @Override public void onDestroyActionMode(ActionMode mode) { // TODO Auto-generated method stub } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { // TODO Auto-generated method stub return true; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { // TODO Auto-generated method stub switch (item.getItemId()) { case android.R.id.copy: int min = 0; int max = editText.getText().length(); if (editText.isFocused()) { final int selStart = editText.getSelectionStart(); final int selEnd = editText.getSelectionEnd(); min = Math.max(0, Math.min(selStart, selEnd)); max = Math.max(0, Math.max(selStart, selEnd)); } // Perform your definition lookup with the selected text final CharSequence selectedText = editText.getText() .subSequence(min, max); String text = selectedText.toString(); myClip = ClipData.newPlainText("text", text); myClipboard.setPrimaryClip(myClip); Toast.makeText(getApplicationContext(), "Text Copied", Toast.LENGTH_SHORT).show(); // Finish and close the ActionMode mode.finish(); return true; case android.R.id.cut: // add your custom code to get cut functionality according // to your requirement return true; case android.R.id.paste: // add your custom code to get paste functionality according // to your requirement return true; default: break; } return false; } }); } } 

最简单的方法是在AndroidManifestapplication标记中定义的主要主题样式中添加一行。 打开你的主题风格,并添加以下内容:

 <item name="actionModeBackground">@color/your_color</item> 

要么

 <item name="android:actionModeBackground">@color/your_color</item> 

例如:我定义的我的主题风格:

 <style name="AppTheme" parent="AppBaseTheme"> <item name="calendarViewStyle">@style/Widget.Holo.CalendarView</item> <item name="android:actionBarStyle">@style/AppTheme1</item> <!-- below is the line you have to add --> <item name="android:actionModeBackground">@color/black_actionBar</item> </style>