Usuń podkreślenie z linków w TextView - Android

94

Używam dwóch textviewdo wyświetlania linków z bazy danych, udało mi się zmienić kolory linków, ale chcę usunąć podkreślenie

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

Czy mogę to zrobić z XML lub Code?

Mohamed Ben Dhaou
źródło

Odpowiedzi:

220

Możesz to zrobić w kodzie, znajdując i zastępując URLSpanwystąpienia wersjami, które nie są podkreślane. Po wywołaniu Linkify.addLinks()wywołaj funkcję stripUnderlines()wklejoną poniżej na każdym z twoich TextView:

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

Wymaga to dostosowanej wersji URLSpan, która nie włącza właściwości „underline” w 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
źródło
9
To rozwiązanie zakłada, że ​​tekst zakresu jest taki sam jak adres URL, co ma miejsce w przypadku podstawowego linku http: //. Jednak Linkify jest sprytny i konwertuje numer telefonu, taki jak (212) 555-1212, na adres URL tel:2125551212. new URLSpanNoUnderlinePołączenie powinno być przekazane span.getURL(), aby zachować te informacje, w przeciwnym razie można wygenerować złe linki, które po kliknięciu powodują wyjątki. Umieściłem to proponowane rozwiązanie w kolejce edycji Twojej odpowiedzi, ponieważ sam nie mam uprawnień do edycji.
Mike Mueller
8
Nie działa dla mnie. Daje wyjątek rzutowania klas w wierszu Spannable s = (Spannable) textView.getText ();
Brijesh Thakur
5
Po prostu zamień tę linię na Spannable s = new SpannableString (textView.getText ());
FOliveira 8-14
1
zastąpienie Spannable s = (Spannable) textView.getText()ze Spannable s = new SpannableString(textView.getText());nie działa dla mnie. Jeśli przełączę się z powrotem do przesyłania, to zadziała, tylko jeśli TextView ma android:textIsSelectable=true. Każdy pomysł, dlaczego?
Zapalony
2
Czy istnieje sposób, aby to działało z android:autoLinkatrybutem? W przeciwnym razie wydaje się, że musisz stworzyć własne metody onclick dla wbudowanych funkcji.
Alkarin
33

Biorąc pod uwagę tekst i zawartość:

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

Oto zwięzły sposób usuwania podkreśleń z hiperłączy:

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

Jest to oparte na podejściu sugerowanym przez robUx4.

Aby linki były klikalne, musisz również zadzwonić:

textView.setMovementMethod(LinkMovementMethod.getInstance());
Adriaan Koster
źródło
7
to nie działa, jeśli próbujesz pobrać ciąg z zasobów, więc to, String content = getResources().getString(R.string.content);co zawiera łącze, już nie działa.
Rain Man
1
Jak to możliwe? Ciąg nie wie, skąd się wziął. Musi istnieć różnica w zawartości ciągu.
Adriaan Koster
Nie wiem dlaczego, ale nie pokazuje adresu URL, gdy wywołuję ciąg, z res/values/strings.xmlktórego zawiera dokładnie to samo, co w przykładzie. Czy możesz w końcu przetestować?
Rain Man
Na pewno nie zamierzam testować na moim końcu (- :. Jeśli chcesz mieć pewność co do zawartości ciągu, zaloguj oba ciągi razem z ich hashCode. Zaskoczyłoby mnie, gdybyś znalazł inne wyniki podczas używania powyższego kodu z dokładnie te same struny
Adriaan Koster
1
Jeśli chcesz, aby działało z pobieraniem ciągu znaków z zasobów, musisz go zakodować. >= &gt;, <= &lt;itd. Na przykład: <string name="link_to_google" >&lt;a href="https://www.google.com/"&gt;Google&lt;/a&gt;</string>patrz developer.android.com/guide/topics/resources/string-resource
Micer
11

UnderlineSpan już istnieje, ale może tylko ustawić podkreślenie.

Innym rozwiązaniem jest dodanie zakresu bez podkreślenia do każdego istniejącego URLSpan. Tak więc stan podkreślenia jest wyłączony tuż przed malowaniem. W ten sposób zachowujesz swoje URLSpan(prawdopodobnie niestandardowe) klasy i wszystkie inne style ustawione gdzie indziej.

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

    public NoUnderlineSpan(Parcel src) {}

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

Oto jak to ustawić bez usuwania istniejącego obiektu URLSpan:

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
źródło
4

Oto funkcja rozszerzenia 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
}

Stosowanie:

txtView.removeLinksUnderline()    
sma6871
źródło
3

Wdrożyłem rozwiązanie, które moim zdaniem jest bardziej eleganckie. Zrobiłem zamówienieTextView . W ten sposób nie musisz wykonywać dodatkowego kodu dla każdego TextViewz hiperłączami.

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

I kod dla 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
źródło
2

Zawsze, gdy próbuję usunąć podkreślenie adresu URL za pomocą spannable, sugeruję tylko te rzeczy:

1> Tworzenie klasy niestandardowej:

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

Wymaga to dostosowanej wersji URLSpan, która nie włącza właściwości „underline” w TextPaint

2> setSpan z rozszerzalnym tekstem:

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

Tutaj spannableText jest obiektem SpannableString ... !!!

Dhruv Raval
źródło
To najlepsze rozwiązanie i jedyne, które działało u mnie
GuilhE
To rozwiązanie dotyczy tekstu z jednym adresem URL.
CoolMind
1

Jeśli używasz właściwości automatycznego linku Textview i chcesz usunąć podkreślenia, możesz jej użyć:

Najpierw rozszerz UnderlineSpan i usuń podkreślenie:

public class NoUnderlineSpan extends UnderlineSpan {

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

Po drugie, utwórz i wystąpienie NoUnderlineSpan, utwórz Spannable z tekstu String i ustaw zakres na 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);
}

Źródła: http://prog3.com/sbdm/blog/maosidiaoxian/article/details/39156563

Francisco Moya
źródło
Fajne rozwiązanie, ale po powrocie z aplikacji Telefon (po kliknięciu w numer telefonu) ponownie podkreśla TextView.
CoolMind
1
Tak, jeśli twoja aktywność przechodzi w tło, powinieneś użyć tego kodu w swojej funkcji aktywności onResume, aby zachować stan tekstu bez podkreślenia.
Francisco Moya,
0

Jeśli chcesz tylko tekst i nie przejmuj się linkiem URL

Spowoduje to USUNIĘCIE linku, ale ZACHOWAJ tekst

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

nie są wymagane żadne dodatkowe zajęcia

String content = "<a href='http://stackoverflow.com'>Stack Overflow</a> Rocks!";
textView.setText(stripLinks(content));
Samuel
źródło
0

Oto moja metoda

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

Nazwij to tak

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

Appcontroller to moja klasa aplikacji, w której umieszczam tę metodę, aby mieć do niej dostęp z dowolnego miejsca

Bharat singh
źródło
0

Dla użytkowników platformy Xamarin, którzy znaleźli ten wpis, oto jak to działa:

  1. Utwórz niestandardową klasę span, aby obsłużyć usuwanie podkreśleń.
    class URLSpanNoUnderline : URLSpan {
            public URLSpanNoUnderline (string url) : base (url) {
            }

            public override void UpdateDrawState (TextPaint ds) {
                base.UpdateDrawState (ds);
                ds.UnderlineText = false;
            }
        }
  1. Utwórz metodę rozszerzenia, aby znaleźć wszystkie zakresy adresów URL i zastąpić je naszymi niestandardowymi zakresami.
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
źródło
-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
źródło