¿Seleccionar + copiar texto en un TextView?

106

¿Hay alguna forma de permitir que el usuario seleccione / copie texto en un TextView? Necesito la misma funcionalidad de EditText donde puede mantener presionado el control y obtener las opciones emergentes de seleccionar todo / copiar, pero necesito que el control se vea como un TextView.

Intenté algunas cosas, como hacer que un EditText use la opción editable = "none" o inputType = "none", pero aún conservan el fondo enmarcado de un EditText, que no quiero,

Gracias

------- Actualización ----------------------

Esto es 99% allí, todo lo que quisiera es que el crepúsculo de selección sea visible (la cosa naranja). Aparte de eso, es bueno, podría vivir con esto:

<EditText 
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:editable="false"
  style="?android:attr/textViewStyle"
  android:textColor="@color/white"
  android:textAppearance="@android:style/TextAppearance.Medium"
  android:cursorVisible="false"
  android:background="@null" />

Supongo que se debe a cursorVisible = "false" pero sin eso, el cursor está presente incluso sin que se haya realizado ninguna selección.

user291701
fuente
Una alternativa sería utilizar WebView en lugar de TextView para mostrar el texto.
aleb

Respuestas:

221

android: textIsSelectable funciona (al menos en ICS, aún no he verificado versiones anteriores)

<TextView
    android:id="@+id/deviceIdTV"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textIsSelectable="true"
    android:text="" />
Milind
fuente
15
API nivel 11 y superior únicamente
Thierry-Dimitri Roy
10
¿Pero cómo copiar? Puedo resaltar el texto, pero no apareció ningún menú de copia.
Bagusflyer
1
¿No es esto la causa del bloqueo, cuando juegas con los cursores?
Shubham
1
¿me puedes decir cómo hacer que funcione en listview?
Ramesh Kumar
Hermoso, incluso menú de copia predeterminado creado en la barra de herramientas
Farid
56

La vista de texto debe estar habilitada, enfocable, con un clic largo y textIsSelectable

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text=""
    android:id="@+id/pwTextView"
    android:enabled="true"
    android:textIsSelectable="true"
    android:focusable="true"
    android:longClickable="true" />
skd
fuente
1
Esta es la mejor solución.
Brave
9
¿Por qué textIsSelectableno es suficiente? funciona para mí solo con esta opción
herau
4
O puede usar textview.setTextIsSelectable(true)en el código java code.
berrytchaks
1
Solo usando textIsSelectableishaz el trabajo por mí
crgarridos
1
de alguna manera, textIsSelectablefunciona para algunos casos, pero no para otros. A veces, el mismo diseño no siempre funciona solo con textIsSelectable sino con un texto diferente. Sin embargo, esta solución no parece hacer que funcione mejor, por lo que el problema podría provenir de otra parte.
Simon Ninon
23

Creo que tengo una mejor solución. Solo llama
registerForContextMenu(yourTextView);

y tu TextView estará registrado para recibir eventos del menú contextual.

Luego anule onCreateContextMenuen suActivity

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    //user has long pressed your TextView
    menu.add(0, v.getId(), 0, "text that you want to show in the context menu - I use simply Copy");

    //cast the received View to TextView so that you can get its text
    TextView yourTextView = (TextView) v;

    //place your TextView's text in clipboard
    ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); 
    clipboard.setText(yourTextView.getText());
}

Espero que esto le ayude a usted y a cualquier otra persona que busque una forma de copiar texto de un TextView

pandre
fuente
¿Dónde permite esto al usuario seleccionar qué fragmentos de texto se copian? ¿No copia todo, que no es la pregunta original?
James Moore
4
Probablemente sea bueno tener en cuenta que esto hace que el texto se copie inmediatamente, independientemente de si seleccionan "Copiar" en el menú. Para copiar solo cuando se seleccionó el elemento apropiado, también deberá anular onContextItemSelected () o agregar un controlador de clic al elemento del menú.
Faisal
ClipboardManager.setText(CharSequence text)quedó obsoleto en el nivel de API 11. Use en su setPrimaryClip(ClipData)lugar. Esto crea un ClippedItem que contiene el texto dado y lo establece como el clip principal. No tiene etiqueta ni icono. Buena lectura sobre copiar y pegar: enlace
Marilia
Quiero abrir el diálogo después de la selección de texto. Entonces, ¿puede darnos alguna sugerencia al respecto?
Anand Savjani
9
textview1.setTextIsSelectable(true);

Esto permitirá al usuario seleccionar y copiar texto con un clic prolongado o como hacemos habitualmente.

Amitoj
fuente
6

Estoy tratando de implementar lo mismo, y su pregunta me ayudó a configurar correctamente el diseño de mi texto de edición. ¡Así que gracias! :)

Entonces me di cuenta de que el resaltado será visible si el cursor está encendido. Pero me gusta que no quiera ver un cursor antes de hacer clic en el texto, por lo que oculto el cursor en el archivo layout.xml como usted, y agregué un detector de eventos para hacer clic largo y mostrar el cursor solo cuando comienza una selección .

Así que agrega el oyente en tu Actividad en la sección onCreate:

public TextView htmltextview;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    ...

    htmltextview.setOnLongClickListener(new OnLongClickListener(){

        public boolean onLongClick(View v) {
            htmltextview.setCursorVisible(true);
            return false;
        }
    });

}

Y voilá, no hay cursor al principio, y si hace clic largo, el cursor aparece con los límites de selección.

Espero poder ayudar.

Saludos, fm

fmarton
fuente
5

También estaba tratando de hacer algo similar, pero aún necesitaba un enfoque personalizado con la manipulación del resaltado del texto en TextView. Activé el resaltado y la copia en LongClickacción.

Así es como me las arreglé usando SpannableString:

SpannableString highlightString = new SpannableString(textView.getText());
highlightString.setSpan(new BackgroundColorSpan(ContextCompat.getColor(getActivity(), R.color.gray))
            , 0, textView.getText().length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
textView.setText(highlightString);
copyToClipboard(urlToShare);

y la función de copia:

public void copyToClipboard(String copyText) {
    ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
    ClipData clip = ClipData.newPlainText("url", copyText);
    clipboard.setPrimaryClip(clip);
    Toast toast = Toast.makeText(getActivity(), "Link is copied", Toast.LENGTH_SHORT);
    toast.show();
}

Espero que sea útil para alguien que termine con esta pregunta :)

Wahib Ul Haq
fuente
4

Uso de Kotlin mediante programación (copia manual)

button.setTextIsSelectable(true)

O agregue una extensión de propiedad de Kotlin

var TextView.selectable
    get() = isTextSelectable
    set(value) = setTextIsSelectable(value)

Luego llame

textview.selectable = true
// or
if (textview.selectable) { ...

Uso de Kotlin mediante programación (copia automática)

Si desea realizar una copia automática cuando el usuario presiona prolongadamente la vista, este es el código base requerido:

myView.setOnLongClickListener {  
    val clipboardManager = context.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
    val clip = ClipData.newPlainText("Copied String", myString)
    clipboardManager.setPrimaryClip(clip)
    true // Or false if not consumed
}

Es posible que desee agregar un Toastpara confirmar que sucedió

O agregue una función de extensión de Kotlin

myView.copyOnHold() // pass custom string to not use view contents

fun TextView.copyOnHold(customText: String? = null) {
    setOnLongClickListener {
        val clipboardManager = context.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
        val clip = ClipData.newPlainText("Copied String", customText ?: text)
        clipboardManager.setPrimaryClip(clip)
        true // Or false if not consumed
    }
}

Uso de XML (copia manual)

Agrega esto a tu <TextView>

android:textIsSelectable="true"

NOTA: Todos estos requieren android:enabled="true"y android:focusable="true", que son los valores predeterminados para a TextView.

Gibolt
fuente