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?
- Selección de texto de Webview no borrada
- Los identificadores de selección no aparecen en WebView (Android 4.0-4.3)
- Barra de Acción Contextual de Selección de Texto que desaparece en autoscroll
- Cambiar el color de la barra de estado al ingresar al modo de acción contextual
- ¿Cómo seleccionar un elemento ListView después de un clic largo?
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; } }
- ¿Cómo se puede implementar multi-selección y Contextual ActionMode en ActionBarSherlock?
- Estilo personalizado del menú de desbordamiento CAB
- Error en startActionMode, appcompat
- Cómo iniciar la barra de acción contextual para ver el texto de forma programática con opions por defecto copiar y seleccionar todo?
- Barra de acción contextual comportamiento extraño para el elemento de menú
- Comportamiento personalizado Modo de acción contextual
- ¿Cómo hacer que la barra Contextual ActionMode se superponga a la barra de herramientas appcompat-v7 pero no al cajón de navegación?
- Abrir cuadro de diálogo personalizado en la selección de texto de la vista web
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>