Eliminar el subrayado de los enlaces en TextView - Android

93

Estoy usando dos textviewpara mostrar enlaces de la base de datos, logré cambiar los colores de los enlaces pero quiero eliminar el subrayado

email.setText(c.getString(5));
    website.setText(c.getString(6));
    Linkify.addLinks(email, Linkify.ALL);
    Linkify.addLinks(website, Linkify.ALL);

¿Puedo hacer eso desde XML o Code?

Mohamed Ben Dhaou
fuente

Respuestas:

220

Puede hacerlo en código encontrando y reemplazando las URLSpaninstancias con versiones que no subrayan. Después de llamar Linkify.addLinks(), llame a la función stripUnderlines()pegada a continuación en cada uno de sus TextViews:

    private void stripUnderlines(TextView textView) {
        Spannable s = new SpannableString(textView.getText());
        URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class);
        for (URLSpan span: spans) {
            int start = s.getSpanStart(span);
            int end = s.getSpanEnd(span);
            s.removeSpan(span);
            span = new URLSpanNoUnderline(span.getURL());
            s.setSpan(span, start, end, 0);
        }
        textView.setText(s);
    }

Esto requiere una versión personalizada de URLSpan que no habilita la propiedad "subrayado" de TextPaint:

    private class URLSpanNoUnderline extends URLSpan {
        public URLSpanNoUnderline(String url) {
            super(url);
        }
        @Override public void updateDrawState(TextPaint ds) {
            super.updateDrawState(ds);
            ds.setUnderlineText(false);
        }
    }
Reuben Scratton
fuente
9
Esta solución asume que el texto del intervalo es el mismo que la URL, que es el caso de un enlace http: // básico. Sin embargo, Linkify es inteligente y convierte un número de teléfono como (212) 555-1212 en la URL tel:2125551212. La new URLSpanNoUnderlinellamada debe pasarse span.getURL()para retener esta información; de lo contrario, generará enlaces defectuosos que causan excepciones al hacer clic. He colocado esta solución propuesta en la cola de edición para su respuesta, ya que yo mismo no tengo permisos de edición.
Mike Mueller
8
No funciona para mí. Proporciona una excepción de conversión de clase en Line Spannable s = (Spannable) textView.getText ();
Brijesh Thakur
5
Simplemente reemplace esa línea con Spannable s = new SpannableString (textView.getText ());
FOliveira
1
reemplazar con Spannable s = (Spannable) textView.getText()con Spannable s = new SpannableString(textView.getText());no funciona para mí. Si vuelvo a la transmisión, funciona, solo si TextView tiene android:textIsSelectable=true. ¿Alguna idea de por qué?
Shoke
2
¿Hay alguna forma de hacer que esto funcione con el android:autoLinkatributo? De lo contrario, parece que tiene que crear sus propios métodos onclick para la funcionalidad incorporada.
Alkarin
32

Dado un textView y contenido:

TextView textView = (TextView) findViewById(R.id.your_text_view_id);
String content = "your <a href='http://some.url'>html</a> content";

A continuación, se muestra una forma concisa de eliminar los subrayados de los hipervínculos:

Spannable s = (Spannable) Html.fromHtml(content);
for (URLSpan u: s.getSpans(0, s.length(), URLSpan.class)) {
    s.setSpan(new UnderlineSpan() {
        public void updateDrawState(TextPaint tp) {
            tp.setUnderlineText(false);
        }
    }, s.getSpanStart(u), s.getSpanEnd(u), 0);
}
textView.setText(s);

Esto se basa en el enfoque sugerido por robUx4.

Para que se pueda hacer clic en los enlaces, también debe llamar a:

textView.setMovementMethod(LinkMovementMethod.getInstance());
Adriaan Koster
fuente
7
esto no funciona si intenta obtener una cadena de recursos, por lo String content = getResources().getString(R.string.content);que lo que incluye un enlace ya no funciona.
Rain Man
1
¿Como puede ser? Una cadena no sabe de dónde se originó. Debe haber una diferencia en el contenido de la cadena.
Adriaan Koster
No estoy seguro de por qué, pero no muestra la URL cuando llamo a la cadena res/values/strings.xmlque contiene exactamente lo mismo que el ejemplo. ¿Puedes probar en tu final?
Rain Man
Definitivamente no voy a probar al final (-:. Si desea estar seguro sobre el contenido de la cadena, registre ambas cadenas junto con su código hash. Me sorprendería si encontrara resultados diferentes al usar el código anterior con el Exactamente el mismo cuerdas.
Adriaan Koster
1
Si desea que funcione con la obtención de cadenas de recursos, debe codificarlo. >= &gt;, <= &lt;etc. Por ejemplo: <string name="link_to_google" >&lt;a href="https://www.google.com/"&gt;Google&lt;/a&gt;</string>consulte developer.android.com/guide/topics/resources/string-resource
Micer
11

UnderlineSpan ya existe, pero solo puede establecer el subrayado.

Otra solución es agregar un intervalo sin subrayado en cada uno de los existentes URLSpan. Por tanto, el estado subrayado se desactiva justo antes de pintar. De esta manera, mantiene sus URLSpanclases (posiblemente personalizadas) y todos los demás estilos configurados en otro lugar.

public class NoUnderlineSpan extends UnderlineSpan {
    public NoUnderlineSpan() {}

    public NoUnderlineSpan(Parcel src) {}

    @Override
    public void updateDrawState(TextPaint ds) {
        ds.setUnderlineText(false);
    }
}

Así es como se configura sin eliminar el objeto URLSpan existente:

URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class);
for (URLSpan span: spans) {
    int start = s.getSpanStart(span);
    int end = s.getSpanEnd(span);
    NoUnderlineSpan noUnderline = new NoUnderlineSpan();
    s.setSpan(noUnderline, start, end, 0);
}
robUx4
fuente
3

Implementé una solución que, en mi opinión, es más elegante. He hecho una costumbreTextView . De esta manera, no es necesario ejecutar código adicional para todos los que TextViewtengan hipervínculos.

package com.example.view;

import android.content.Context;
import android.support.v7.widget.AppCompatTextView;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.URLSpan;
import android.util.AttributeSet;

import com.example.utils.UrlSpanNoUnderline;

public class TextViewNoUnderline extends AppCompatTextView {
    public TextViewNoUnderline(Context context) {
        this(context, null);
    }

    public TextViewNoUnderline(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.textViewStyle);
    }

    public TextViewNoUnderline(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setSpannableFactory(Factory.getInstance());
    }

    private static class Factory extends Spannable.Factory {
        private final static Factory sInstance = new Factory();

        public static Factory getInstance() {
            return sInstance;
        }

        @Override
        public Spannable newSpannable(CharSequence source) {
            return new SpannableNoUnderline(source);
        }
    }

    private static class SpannableNoUnderline extends SpannableString {
        public SpannableNoUnderline(CharSequence source) {
            super(source);
        }

        @Override
        public void setSpan(Object what, int start, int end, int flags) {
            if (what instanceof URLSpan) {
                what = new UrlSpanNoUnderline((URLSpan) what);
            }
            super.setSpan(what, start, end, flags);
        }
    }
}

Y código para UrlSpanNoUnderline:

package com.jankstudios.smmagazine.utils;

import android.text.TextPaint;
import android.text.style.URLSpan;

public class UrlSpanNoUnderline extends URLSpan {
    public UrlSpanNoUnderline(URLSpan src) {
        super(src.getURL());
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        super.updateDrawState(ds);
        ds.setUnderlineText(false);
    }
}
Sam Sunson
fuente
3

Aquí está la función de extensión de Kotlin :

fun TextView.removeLinksUnderline() {
    val spannable = SpannableString(text)
    for (u in spannable.getSpans(0, spannable.length, URLSpan::class.java)) {
        spannable.setSpan(object : URLSpan(u.url) {
            override fun updateDrawState(ds: TextPaint) {
                super.updateDrawState(ds)
                ds.isUnderlineText = false
            }
        }, spannable.getSpanStart(u), spannable.getSpanEnd(u), 0)
    }
    text = spannable
}

Uso:

txtView.removeLinksUnderline()    
sma6871
fuente
2

Siempre que, intente eliminar el subrayado de la URL con spannable, sugiero solo estas cosas:

1> Crear clase personalizada:

private class URLSpanNoUnderline extends URLSpan {
            public URLSpanNoUnderline(String url) {
                super(url);
            }
            @Override public void updateDrawState(TextPaint ds) {
                super.updateDrawState(ds);
                ds.setUnderlineText(false);
            }
        }

Esto requiere una versión personalizada de URLSpan que no habilita la propiedad "subrayado" de TextPaint

2> setSpan con texto extensible:

spannableText.setSpan(new URLSpanNoUnderline(UrlText), 0, UrlText.length() , 0);

Aquí, spannableText es un objeto de SpannableString ... !!!

Dhruv Raval
fuente
Esta es la mejor solución y la única que funcionó para mí
GuilhE
Esta solución es para un texto con una URL.
CoolMind
1

Si está utilizando la propiedad de enlace automático de Textview y desea eliminar los subrayados, puede usarla:

Primero, extienda UnderlineSpan y elimine el subrayado:

public class NoUnderlineSpan extends UnderlineSpan {

    @Override
    public void updateDrawState(TextPaint ds) {
        ds.setUnderlineText(false);
    }
}

En segundo lugar, cree una instancia de NoUnderlineSpan, cree un Spannable a partir del texto String y establezca el span en spannable:

NoUnderlineSpan mNoUnderlineSpan = new NoUnderline();
if (yourTextView.getText() instanceof Spannable) {
    Spannable s = (Spannable) yourTextView.getText();
    s.setSpan(mNoUnderlineSpan, 0, s.length(), Spanned.SPAN_MARK_MARK);
}

Referencia: http://prog3.com/sbdm/blog/maosidiaoxian/article/details/39156563

Francisco Moya
fuente
Buena solución, pero después de regresar de la aplicación de teléfono (después de hacer clic en el número de teléfono), nuevamente subraya TextView.
CoolMind
1
Sí, si su actividad pasa a segundo plano, debe usar este código en su función de actividad onResume para mantener el estado de vista de texto sin subrayado.
Francisco Moya
0

Si solo quiere el texto y no se preocupa por el enlace URL

Esto eliminará el enlace pero MANTENER el texto

private Spannable stripLinks(String content) {
    Spannable s = new SpannableString(content);
    URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class);
    for (URLSpan span : spans) {
        s.removeSpan(span);
    }

    return s;
}

no se requieren clases adicionales

String content = "<a href='http://stackoverflow.com'>Stack Overflow</a> Rocks!";
textView.setText(stripLinks(content));
Samuel
fuente
0

Aquí está mi método

 public static void removeUnderlines(Spannable p_Text) {
            if (p_Text != null && p_Text.toString().length() > 0) {
                URLSpan[] spans = p_Text.getSpans(0, p_Text.length(), URLSpan.class);

                for (URLSpan span : spans) {
                    int start = p_Text.getSpanStart(span);
                    int end = p_Text.getSpanEnd(span);
                    p_Text.removeSpan(span);
                    span = new URLSpanNoUnderline(span.getURL());
                    p_Text.setSpan(span, start, end, 0);
                }
            }
        }

Llámalo así

AppController.removeUnderlines((Spannable) eventEmail.getText());

Appcontroller es mi clase de aplicación donde coloco este método para poder acceder a él desde cualquier lugar

Bharat singh
fuente
0

Para los usuarios de Xamarin que encuentren esta publicación, así es como lo hice funcionar:

  1. Cree una clase de tramo personalizada para manejar la eliminación de los subrayados.
    class URLSpanNoUnderline : URLSpan {
            public URLSpanNoUnderline (string url) : base (url) {
            }

            public override void UpdateDrawState (TextPaint ds) {
                base.UpdateDrawState (ds);
                ds.UnderlineText = false;
            }
        }
  1. Cree un método de extensión para encontrar todos los intervalos de URL y reemplácelos con nuestros intervalos personalizados.
public static void StripUnderlinesFromLinks (this TextView textView) {
                var spannable = new SpannableStringBuilder (textView.TextFormatted);
                var spans = spannable.GetSpans (0, spannable.Length (), Java.Lang.Class.FromType (typeof (URLSpan)));
                foreach (URLSpan span in spans) {
                    var start = spannable.GetSpanStart (span);
                    var end = spannable.GetSpanEnd (span);
                    spannable.RemoveSpan(span);
                    var newSpan = new URLSpanNoUnderline (span.URL);
                    spannable.SetSpan(newSpan, start, end, 0);
                }
                textView.TextFormatted = spannable;
            }
Justin
fuente
-1
public void setView()
{
TextView t=(TextView) findViewById(R.id.textView3);
        t.setText(Html.fromHtml("<a href=http://www.urdusms.net > UrduSMS "));
        t.setTextColor(Color.BLACK);
        t.setGravity(Gravity.CENTER);
        t.setMovementMethod(LinkMovementMethod.getInstance());

         Spannable s = (Spannable) t.getText();
            URLSpan[] spans = s.getSpans(0, s.length(), URLSpan.class);
            for (URLSpan span: spans) {
                int start = s.getSpanStart(span);
                int end = s.getSpanEnd(span);
                s.removeSpan(span);
                span = new URLSpanline_none(span.getURL());
                s.setSpan(span, start, end, 0);
            }
        t.setText(s);
 }
//inner class is    
private class URLSpanline_none extends URLSpan {
            public URLSpanline_none(String url) {
                super(url);
            }
            @Override public void updateDrawState(TextPaint ds) {
                super.updateDrawState(ds);
                ds.setUnderlineText(false);
            }
        }
Sandhu
fuente