Rimuovi la sottolineatura dai collegamenti in TextView - Android


93

Sto usando due textviewper visualizzare i collegamenti dal database, sono riuscito a cambiare i colori dei collegamenti ma desidero rimuovere la sottolineatura

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

Posso farlo da XML o da codice?

Risposte:


220

Puoi farlo nel codice trovando e sostituendo le URLSpanistanze con versioni che non sono sottolineate. Dopo aver chiamato Linkify.addLinks(), chiama la funzione stripUnderlines()incollata di seguito su ciascuno dei tuoi messaggi 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);
    }

Ciò richiede una versione personalizzata di URLSpan che non abiliti la proprietà "underline" di TextPaint:

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

9
Questa soluzione presuppone che il testo dello span sia lo stesso dell'URL, come nel caso di un collegamento http: // di base. Tuttavia, Linkify è intelligente e converte un numero di telefono come (212) 555-1212 nell'URL tel:2125551212. La new URLSpanNoUnderlinechiamata dovrebbe essere passata span.getURL()per conservare queste informazioni, altrimenti si generano collegamenti non validi che causano eccezioni quando si fa clic. Ho inserito questa soluzione proposta nella coda di modifica per la tua risposta, poiché io stesso non ho le autorizzazioni di modifica.
Mike Mueller

8
Non funziona per me. Fornisce l'eccezione Class Cast a Line Spannable s = (Spannable) textView.getText ();
Brijesh Thakur

5
Basta sostituire quella riga con Spannable s = new SpannableString (textView.getText ());
FOliveira

1
sostituire con Spannable s = (Spannable) textView.getText()con Spannable s = new SpannableString(textView.getText());non funziona per me. Se torno al casting, funziona, solo se TextView ha android:textIsSelectable=true. Qualche idea sul perché?
scatta il

2
C'è un modo per farlo funzionare con l' android:autoLinkattributo? Altrimenti sembra che tu debba creare i tuoi metodi onclick per le funzionalità integrate.
Alkarin

32

Dato un textView e contenuto:

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

Ecco un modo conciso per rimuovere le sottolineature dai collegamenti ipertestuali:

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

Questo si basa sull'approccio suggerito da robUx4.

Per rendere cliccabili i link è necessario chiamare anche:

textView.setMovementMethod(LinkMovementMethod.getInstance());

7
questo non funziona se si tenta di ottenere una stringa dalle risorse, quindi String content = getResources().getString(R.string.content);che include un collegamento non funziona più.
Rain Man

1
Come può essere? Una stringa non sa da dove proviene. Deve esserci una differenza nel contenuto della stringa.
Adriaan Koster

non so perché ma non mostra l'url quando chiamo la stringa da res/values/strings.xmlcui contiene esattamente la stessa cosa dell'esempio. Puoi testare alla tua fine?
Rain Man il

Sicuramente non ho intenzione di testare alla mia fine (- :. Se vuoi essere sicuro del contenuto della stringa, registra entrambe le stringhe insieme al loro hashCode. Mi sorprenderebbe se trovi risultati diversi quando usi il codice sopra con il esattamente le stesse stringhe.
Adriaan Koster il

1
Se vuoi farlo funzionare ottenendo la stringa dalle risorse, devi codificarlo. >= &gt;, <= &lt;ecc. Ad esempio: <string name="link_to_google" >&lt;a href="https://www.google.com/"&gt;Google&lt;/a&gt;</string>vedi developer.android.com/guide/topics/resources/string-resource
Micer

11

UnderlineSpan esiste già, ma può solo impostare la sottolineatura.

Un'altra soluzione è aggiungere un intervallo senza sottolineatura su ogni esistente URLSpan. Quindi lo stato di sottolineatura è disabilitato appena prima di dipingere. In questo modo mantieni le tue URLSpanclassi (possibilmente personalizzate) e tutti gli altri stili impostati altrove.

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

    public NoUnderlineSpan(Parcel src) {}

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

Ecco come impostarlo senza rimuovere l'oggetto URLSpan esistente:

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

3

Ho implementato una soluzione che, a mio avviso, è più elegante. Ho fatto un'abitudineTextView . In questo modo non è necessario eseguire codice aggiuntivo per ogni TextViewcollegamento ipertestuale.

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 il codice per 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);
    }
}

3

Ecco la funzione di estensione di 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
}

Utilizzo:

txtView.removeLinksUnderline()    

2

Ogni volta, prova a rimuovere la sottolineatura dell'URL con spannable, suggerisco solo queste cose:

1> Creazione di una classe personalizzata:

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

Ciò richiede una versione personalizzata di URLSpan che non abiliti la proprietà "underline" di TextPaint

2> setSpan con testo spannabile:

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

Qui, spannableText è Object di SpannableString ... !!!


Questa è la soluzione migliore e l'unica che ha funzionato per me
GuilhE

Questa soluzione è per un testo con un URL.
CoolMind

1

Se stai utilizzando la proprietà di collegamento automatico della visualizzazione di testo e desideri rimuovere le sottolineature, puoi utilizzarla:

Innanzitutto, estendi UnderlineSpan e rimuovi la sottolineatura:

public class NoUnderlineSpan extends UnderlineSpan {

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

In secondo luogo, crea un'istanza di NoUnderlineSpan, crea uno Spannable dal testo String e imposta lo span su 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);
}

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


Bella soluzione, ma dopo il ritorno dall'app Telefono (dopo aver cliccato sul numero di telefono) sottolinea nuovamente TextView.
CoolMind

1
Sì, se la tua attività va in background dovresti usare questo codice nella tua funzione di attività onResume per mantenere la visualizzazione del testo senza stato di sottolineatura.
Francisco Moya

0

Se vuoi solo il testo e non preoccuparti del collegamento URL

Questo rimuoverà il collegamento ma MANTENGONO il testo

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

non sono richieste lezioni aggiuntive

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

0

Ecco il mio metodo

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

Chiamalo così

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

Appcontroller è la mia classe di applicazione in cui inserisco questo metodo in modo che possa accedervi da qualsiasi luogo


0

Per gli utenti Xamarin che trovano questo post, ecco come l'ho fatto funzionare:

  1. Crea una classe span personalizzata per gestire l'eliminazione delle sottolineature.
    class URLSpanNoUnderline : URLSpan {
            public URLSpanNoUnderline (string url) : base (url) {
            }

            public override void UpdateDrawState (TextPaint ds) {
                base.UpdateDrawState (ds);
                ds.UnderlineText = false;
            }
        }
  1. Crea un metodo di estensione per trovare tutti gli intervalli di URL e sostituiscili con i nostri intervalli personalizzati.
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;
            }

-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);
            }
        }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.