Supprimer le soulignement des liens dans TextView - Android

93

J'utilise deux textviewpour afficher les liens de la base de données, j'ai réussi à changer les couleurs des liens mais je veux supprimer le soulignement

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

Puis-je faire cela à partir de XML ou de code?

Mohamed Ben Dhaou
la source

Réponses:

220

Vous pouvez le faire dans le code en recherchant et en remplaçant les URLSpaninstances par des versions qui ne sont pas soulignées. Après avoir appelé Linkify.addLinks(), appelez la fonction stripUnderlines()collée ci-dessous sur chacun de vos 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);
    }

Cela nécessite une version personnalisée d'URLSpan qui n'active pas la propriété "underline" 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);
        }
    }
Ruben Scratton
la source
9
Cette solution suppose que le texte de la plage est le même que l'URL, ce qui est le cas pour un lien http: // basique. Cependant, Linkify est intelligent et convertit un numéro de téléphone comme (212) 555-1212 en URL tel:2125551212. L' new URLSpanNoUnderlineappel doit être passé span.getURL()pour conserver ces informations, sinon vous générez des liens incorrects qui provoquent des exceptions lorsque vous cliquez dessus. J'ai placé cette solution proposée dans la file d'attente de modification pour votre réponse, car je n'ai pas les autorisations de modification moi-même.
Mike Mueller
8
Ne fonctionne pas pour moi. Il donne une exception de diffusion de classe à la ligne Spannable s = (Spannable) textView.getText ();
Brijesh Thakur
5
Remplacez simplement cette ligne par Spannable s = new SpannableString (textView.getText ());
FOliveira
1
remplacer par Spannable s = (Spannable) textView.getText()des Spannable s = new SpannableString(textView.getText());ne fonctionne pas pour moi. Si je reviens à la diffusion, cela fonctionne, uniquement si TextView a android:textIsSelectable=true. Une idée pourquoi?
shoke le
2
Existe-t-il un moyen de faire fonctionner cela avec l' android:autoLinkattribut? Sinon, il semble que vous deviez créer vos propres méthodes onclick pour les fonctionnalités intégrées.
Alkarin
32

Étant donné un textView et un contenu:

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

Voici un moyen concis de supprimer les soulignements des hyperliens:

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

Ceci est basé sur l'approche suggérée par robUx4.

Afin de rendre les liens cliquables, vous devez également appeler:

textView.setMovementMethod(LinkMovementMethod.getInstance());
Adriaan Koster
la source
7
cela ne fonctionne pas si vous essayez d'obtenir une chaîne à partir des ressources, donc String content = getResources().getString(R.string.content);qui inclut un lien ne fonctionne plus.
Rain Man
1
Comment est-ce possible? Une chaîne ne sait pas d'où elle provient. Il doit y avoir une différence dans le contenu de la chaîne.
Adriaan Koster
Je ne sais pas pourquoi mais il n'affiche pas l'url lorsque j'appelle la chaîne à partir de res/values/strings.xmllaquelle contient exactement la même chose que l'exemple. Pouvez-vous tester à votre fin?
Rain Man
Je ne vais certainement pas tester à ma fin (-:. Si vous voulez être sûr du contenu de la chaîne, enregistrez les deux chaînes avec leur hashCode. Cela me surprendrait si vous trouviez des résultats différents en utilisant le code ci-dessus avec le exactement les mêmes chaînes.
Adriaan Koster
1
Si vous voulez le faire fonctionner en récupérant une chaîne à partir de ressources, vous devez l'encoder. >= &gt;, <= &lt;etc. Par exemple: <string name="link_to_google" >&lt;a href="https://www.google.com/"&gt;Google&lt;/a&gt;</string>voir developer.android.com/guide/topics/resources/string-resource
Micer
11

UnderlineSpan existe déjà, mais ne peut définir que le soulignement.

Une autre solution consiste à ajouter une travée sans soulignement sur chaque élément existant URLSpan. Ainsi, l'état de soulignement est désactivé juste avant la peinture. De cette façon, vous gardez vos URLSpanclasses (éventuellement personnalisées) et tous les autres styles définis ailleurs.

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

    public NoUnderlineSpan(Parcel src) {}

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

Voici comment vous le définissez sans supprimer l'objet URLSpan existant:

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
la source
3

J'ai mis en place une solution qui, à mon avis, est plus élégante. J'ai fait une coutumeTextView . De cette façon, vous n'avez pas besoin d'exécuter du code supplémentaire pour chaque TextViewavec des hyperliens.

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

Et le code pour 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
la source
3

Voici la fonction d'extension 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
}

Usage:

txtView.removeLinksUnderline()    
sma6871
la source
2

À chaque fois, essayez de supprimer le soulignement d'URL avec spannable, je ne suggère que ces choses:

1> Création d'une classe personnalisée:

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

Cela nécessite une version personnalisée d' URLSpan qui n'active pas la propriété "underline" de TextPaint

2> setSpan avec texte spannable:

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

Ici, spannableText est l'objet de SpannableString ... !!!

Dhruv Raval
la source
C'est la meilleure solution et la seule qui a fonctionné pour moi
GuilhE
Cette solution est pour un texte avec une URL.
CoolMind
1

Si vous utilisez la propriété de liaison automatique Textview et que vous souhaitez supprimer les soulignements, vous pouvez l'utiliser:

Tout d'abord, étendez UnderlineSpan et supprimez le soulignement:

public class NoUnderlineSpan extends UnderlineSpan {

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

Deuxièmement, créez une instance de NoUnderlineSpan, créez un Spannable à partir du texte String et définissez l'étendue sur 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éférence: http://prog3.com/sbdm/blog/maosidiaoxian/article/details/39156563

Francisco Moya
la source
Belle solution, mais après le retour de l'application Téléphone (après avoir cliqué sur le numéro de téléphone), elle souligne à nouveau TextView.
CoolMind
1
Oui, si votre activité passe en arrière-plan, vous devez utiliser ce code dans votre fonction d'activité onResume pour conserver l'état de texte sans soulignement.
Francisco Moya
0

Si vous voulez juste le texte et ne vous souciez pas du lien URL

Cela va décoller le lien mais GARDER le texte

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

aucun cours supplémentaire requis

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

Voici ma méthode

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

Appelez ça comme ça

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

Appcontroller est ma classe d'application où je mets cette méthode afin que je puisse y accéder de n'importe où

Bharat Singh
la source
0

Pour les utilisateurs de Xamarin qui trouvent ce message, voici comment je l'ai fait fonctionner:

  1. Créez une classe d'étendue personnalisée pour gérer l'élimination des soulignements.
    class URLSpanNoUnderline : URLSpan {
            public URLSpanNoUnderline (string url) : base (url) {
            }

            public override void UpdateDrawState (TextPaint ds) {
                base.UpdateDrawState (ds);
                ds.UnderlineText = false;
            }
        }
  1. Créez une méthode d'extension pour trouver toutes les étendues d'URL et remplacez-les par nos étendues personnalisées.
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
la source
-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
la source