Удаление подчеркивания из ссылок в TextView - Android

94

Я использую два textviewдля отображения ссылок из базы данных, мне удалось изменить цвета ссылок, но я хочу удалить подчеркивание

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

Могу ли я сделать это из XML или кода?

Мохамед Бен Дхау
источник

Ответы:

220

Вы можете сделать это в коде, найдя и заменив URLSpanэкземпляры версиями без подчеркивания. После вызова Linkify.addLinks()вызовите функцию, stripUnderlines()вставленную ниже в каждый из ваших 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);
    }

Для этого требуется настроенная версия URLSpan, которая не включает свойство «подчеркивание» 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
Это решение предполагает, что текст диапазона совпадает с URL-адресом, что имеет место для базовой ссылки http: //. Однако Linkify умен и преобразует номер телефона, например (212) 555-1212, в URL-адрес tel:2125551212. new URLSpanNoUnderlineВызов должен быть принят , span.getURL()чтобы сохранить эту информацию, в противном случае вы создаете плохие ссылки , которые вызывают исключения при нажатии. Я поместил это предлагаемое решение в очередь на редактирование вашего ответа, поскольку у меня самого нет прав на редактирование.
Майк Мюллер,
8
Не работает для меня. Это дает исключение Class Cast в строке Spannable s = (Spannable) textView.getText ();
Бриджеш Такур
5
Просто замените эту строку на Spannable s = new SpannableString (textView.getText ());
FOliveira 08
1
заменяя Spannable s = (Spannable) textView.getText()с Spannable s = new SpannableString(textView.getText());не работает для меня. Если я вернусь к кастингу, он будет работать, только если у TextView есть android:textIsSelectable=true. Есть идеи, почему?
b.lit
2
Есть ли способ заставить это работать с android:autoLinkатрибутом? В противном случае кажется, что вам нужно создать свои собственные методы onclick для встроенной функциональности.
Alkarin 09
33

Учитывая textView и контент:

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

Вот краткий способ убрать подчеркивание с гиперссылок:

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

Это основано на подходе, предложенном robUx4.

Для того, чтобы ссылки стали кликабельными, вам также необходимо позвонить:

textView.setMovementMethod(LinkMovementMethod.getInstance());
Адриан Костер
источник
7
это не работает, если вы пытаетесь получить строку из ресурсов, поэтому String content = getResources().getString(R.string.content);содержащая ссылку больше не работает.
Человек дождя,
1
Как это может быть? Строка не знает, откуда она произошла. Должно быть различие в содержимом String.
Адриан Костер,
не уверен, почему, но он не показывает URL-адрес, когда я вызываю строку, из res/values/strings.xmlкоторой содержится то же самое, что и в примере. Можете ли вы проверить в конце концов?
Человек дождя
Я определенно не собираюсь тестировать со своей стороны (- :. Если вы хотите быть уверенным в содержимом строки, зарегистрируйте обе строки вместе с их хэш-кодом. Меня удивит, если вы обнаружите разные результаты при использовании приведенного выше кода с точно такие же струны.
Адриан Костер
1
Если вы хотите, чтобы он работал с получением строки из ресурсов, вам нужно ее закодировать. >= &gt;, <= &lt;и т. д. Например: <string name="link_to_google" >&lt;a href="https://www.google.com/"&gt;Google&lt;/a&gt;</string>см. developer.android.com/guide/topics/resources/string-resource
Micer
11

UnderlineSpan уже существует, но можно установить только подчеркивание.

Другое решение - добавить на каждый существующий интервал без подчеркивания URLSpan. Таким образом, состояние подчеркивания отключается непосредственно перед рисованием. Таким образом вы сохраните свои URLSpan(возможно, пользовательские) классы и все другие стили, установленные в другом месте.

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

    public NoUnderlineSpan(Parcel src) {}

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

Вот как вы установите его, не удаляя существующий объект 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
источник
3

Я реализовал решение, которое, на мой взгляд, более элегантно. Я сделал обычайTextView . Таким образом, вам не нужно выполнять дополнительный код для каждого TextViewс гиперссылками.

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

И код для 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

Вот функция расширения 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
}

Применение:

txtView.removeLinksUnderline()    
sma6871
источник
2

Всякий раз, когда пытайтесь удалить подчеркивание URL-адреса с помощью spannable, я предлагаю только следующие вещи:

1> Создание собственного класса:

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

Для этого требуется настроенная версия URLSpan которая не включает свойство «подчеркивание» TextPaint.

2> setSpan с расширяемым текстом:

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

Здесь spannableText - это объект SpannableString ... !!!

Дхрув Раваль
источник
Это лучшее решение и единственное, что сработало для меня
GuilhE
Это решение для текста с одним URL.
CoolMind 05
1

Если вы используете свойство Autolink Textview и хотите удалить подчеркивание, вы можете использовать его:

Сначала расширьте UnderlineSpan и удалите подчеркивание:

public class NoUnderlineSpan extends UnderlineSpan {

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

Во-вторых, создайте экземпляр NoUnderlineSpan, создайте Spannable из текста String и установите для диапазона 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);
}

Ссылка: http://prog3.com/sbdm/blog/maosidiaoxian/article/details/39156563

Франсиско Мойя
источник
Хорошее решение, но после возврата из приложения «Телефон» (после щелчка по номеру телефона) снова подчеркивается TextView.
CoolMind
1
Да, если ваша деятельность переходит в фоновый режим, вы должны использовать этот код в своей функции активности onResume для сохранения состояния textview без подчеркивания.
Франсиско Мойя
0

Если вам просто нужен текст и вас не беспокоит URL-ссылка

Это STRIP ссылки , но СОХРАНИТЬ текст

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

дополнительных занятий не требуется

String content = "<a href='http://stackoverflow.com'>Stack Overflow</a> Rocks!";
textView.setText(stripLinks(content));
Самуэль
источник
0

Вот мой метод

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

Назовите это так

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

Appcontroller - это мой класс приложения, в котором я поместил этот метод, чтобы получить к нему доступ из любого места

Бхарат Сингх
источник
0

Для пользователей Xamarin, нашедших этот пост, вот как я заставил его работать:

  1. Создайте собственный класс диапазона для удаления подчеркивания.
    class URLSpanNoUnderline : URLSpan {
            public URLSpanNoUnderline (string url) : base (url) {
            }

            public override void UpdateDrawState (TextPaint ds) {
                base.UpdateDrawState (ds);
                ds.UnderlineText = false;
            }
        }
  1. Создайте метод расширения, чтобы найти все диапазоны URL-адресов и заменить их нашими пользовательскими диапазонами.
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);
            }
        }
сандху
источник