Barra de acción de corte / copia personalizada para EditText que muestra las manijas de selección de texto

Tengo una aplicación donde quiero poder mostrar un TextView (o EditText) que permite al usuario seleccionar un texto, luego presione un botón para hacer algo con ese texto. La implementación de esto en versiones de Android antes de Honeycomb no es un problema, pero en Honeycomb y por encima de la acción predeterminada de larga presion es mostrar una barra de acción con opciones de Copiar / Cortar / Pegar. Puedo interceptar la prensa larga para mostrar mi propia barra de acción, pero entonces no consigo las manijas de la selección del texto exhibidas.

Una vez que he iniciado mi propio ActionMode ¿cómo puedo obtener los controladores de selección de texto que se muestran?

Aquí está el código que estoy usando para iniciar el ActionMode, que funciona, excepto que no hay control de selección de texto mostrado:

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

Me di cuenta de la respuesta a mi propia pregunta; TextView (y por lo tanto EditText) tiene un método setCustomSelectionActionModeCallback() que se debe utilizar en lugar de startActionMode() . El uso de esta opción permite personalizar el menú utilizado por TextView para la selección de texto. Código de muestra:

 bodyView.setCustomSelectionActionModeCallback(new StyleCallback()); 

Donde StyleCallback personaliza el menú de selección de texto eliminando Seleccionar todo y añadiendo algunas acciones de estilo:

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

El XML para las adiciones de menú es:

 <?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> 

La solución anterior es buena si quieres personalizar las opciones en la barra de acción. Pero si desea anular la barra de acción copiar / Pegar etc, a continuación se muestra el código …

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

La forma más fácil de hacerlo es agregar una línea en el estilo de tema principal que haya definido en la etiqueta de application de AndroidManifest . Abra su estilo de tema y agregue lo siguiente:

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

O

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

Por ejemplo: Mi estilo de tema que he definido:

 <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> 
  • Modo de Acción Contextual no filtrar toques
  • ¿Cómo manejar correctamente el modo de acción "hecho" botón?
  • Anulación de la barra de acciones contextuales predeterminada para la selección de texto (en WebView) en Android
  • Barra de acción contextual fuerza el desbordamiento
  • Ocultar / mostrar la barra de acción contextual mediante programación
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.