Remova o sublinhado dos links em TextView - Android

93

Estou usando dois textviewpara exibir links do banco de dados, consegui mudar as cores dos links, mas quero remover o sublinhado

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

Posso fazer isso a partir de XML ou Code?

Mohamed Ben Dhaou
fonte

Respostas:

220

Você pode fazer isso no código, localizando e substituindo as URLSpaninstâncias por versões que não sublinham. Depois de chamar Linkify.addLinks(), chame a função stripUnderlines()colada abaixo em cada um de seus 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);
    }

Isso requer uma versão personalizada de URLSpan que não ativa a propriedade "sublinhado" do 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
fonte
9
Essa solução pressupõe que o texto do intervalo seja igual ao URL, que é o caso de um link http: // básico. No entanto, o Linkify é inteligente e converte um número de telefone como (212) 555-1212 no URL tel:2125551212. A new URLSpanNoUnderlinechamada deve ser passada span.getURL()para reter essas informações, caso contrário, você gerará links ruins que causam exceções quando clicados. Coloquei esta solução proposta na fila de edição para sua resposta, uma vez que não tenho permissão para editar.
Mike Mueller
8
Não está funcionando para mim. Fornece exceção de conversão de classe na linha Spannable s = (Spannable) textView.getText ();
Brijesh Thakur
5
Basta substituir essa linha por Spannable s = new SpannableString (textView.getText ());
FOliveira
1
substituir por Spannable s = (Spannable) textView.getText()por Spannable s = new SpannableString(textView.getText());não funciona para mim. Se eu voltar para a transmissão, ele funcionará, apenas se o TextView tiver funcionado android:textIsSelectable=true. Alguma ideia do porquê?
Shoke
2
Existe alguma maneira de fazer isso funcionar com o android:autoLinkatributo? Caso contrário, parece que você tem que criar seus próprios métodos onclick para a funcionalidade integrada.
Alkarin,
32

Dado um textView e conteúdo:

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

Esta é uma maneira concisa de remover sublinhados de hiperlinks:

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

Isso é baseado na abordagem sugerida por robUx4.

Para tornar os links clicáveis, você também precisa ligar para:

textView.setMovementMethod(LinkMovementMethod.getInstance());
Adriaan Koster
fonte
7
isso não funciona se você tentar obter uma string de recursos, de modo String content = getResources().getString(R.string.content);que inclui um link não funciona mais.
Rain Man
1
Como pode ser? Uma String não sabe de onde se originou. Deve haver uma diferença no conteúdo da String.
Adriaan Koster
não sei por que, mas não mostra o url quando eu chamo a string a partir da res/values/strings.xmlqual contém exatamente a mesma coisa que o exemplo. Você pode testar no seu final?
Rain Man
Definitivamente, não vou testar no meu final (-:. Se você quiser ter certeza sobre o conteúdo da string, registre ambas as strings junto com seu hashCode. Ficaria surpreso se você encontrar resultados diferentes ao usar o código acima com o exatamente as mesmas strings.
Adriaan Koster
1
Se você quiser fazer funcionar com a obtenção de strings de recursos, precisará codificá-la. >= &gt;, <= &lt;etc. Por exemplo: <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 já existe, mas só pode definir o sublinhado.

Outra solução é adicionar uma extensão sem sublinhado em cada existente URLSpan. Assim, o estado sublinhado é desativado antes da pintura. Dessa forma, você mantém suas URLSpanclasses (possivelmente personalizadas) e todos os outros estilos definidos em outro lugar.

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

    public NoUnderlineSpan(Parcel src) {}

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

Veja como você o define sem remover o 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
fonte
3

Implementei uma solução que, na minha opinião, é mais elegante. Eu fiz um costumeTextView . Dessa forma, você não precisa executar código extra para cada um TextViewcom hiperlinks.

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

E o 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
fonte
3

Aqui está a função de extensão 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
fonte
2

Sempre, tente remover o sublinhado do URL com spannable, sugiro apenas estas coisas:

1> Criação de classe personalizada:

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

Isso requer uma versão personalizada de URLSpan que não habilita a propriedade "sublinhado" do TextPaint

2> setSpan com texto expansível:

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

Aqui, spannableText é objeto de SpannableString ... !!!

Dhruv Raval
fonte
Esta é a melhor solução e a única que funcionou para mim
GuilhE
Esta solução é para um texto com um URL.
CoolMind
1

Se você estiver usando a propriedade autolink Textview e quiser remover sublinhados, poderá usá-la:

Primeiro, estenda UnderlineSpan e remova o sublinhado:

public class NoUnderlineSpan extends UnderlineSpan {

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

Em segundo lugar, crie uma instância de NoUnderlineSpan, crie um Spannable a partir do texto String e defina o span como 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);
}

Referência: http://prog3.com/sbdm/blog/maosidiaoxian/article/details/39156563

Francisco Moya
fonte
Boa solução, mas depois de retornar do aplicativo Telefone (depois de clicar no número de telefone), ele novamente sublinha o TextView.
CoolMind
1
Sim, se sua atividade vai para o segundo plano, você deve usar este código em sua função de atividade onResume para manter o estado textview sem sublinhado.
Francisco Moya de
0

Se você quer apenas o texto e não se preocupa com o link da URL

Isso STRIP o link, mas MANTERÁ o 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;
}

nenhuma aula adicional necessária

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

Aqui está o meu 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);
                }
            }
        }

Chame assim

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

Appcontroller é minha classe de aplicativo onde coloco este método para que possa acessá-lo de qualquer lugar

Bharat Singh
fonte
0

Para os usuários do Xamarin que estão encontrando esta postagem, aqui está como eu fiz isso funcionar:

  1. Crie uma classe de extensão personalizada para lidar com a remoção dos sublinhados.
    class URLSpanNoUnderline : URLSpan {
            public URLSpanNoUnderline (string url) : base (url) {
            }

            public override void UpdateDrawState (TextPaint ds) {
                base.UpdateDrawState (ds);
                ds.UnderlineText = false;
            }
        }
  1. Crie um método de extensão para localizar todos os spans de url e substitua-os por nossos spans 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
fonte
-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
fonte