从TextView中的链接中删除下划线-Android


93

我正在使用两个textview来显示数据库中的链接,我设法更改了链接颜色,但是我想删除下划线

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

我可以从XML或代码中做到这一点吗?

Answers:


220

您可以通过查找URLSpan实例并将实例替换为不带下划线的版本,从而在代码中做到这一点。调用之后Linkify.addLinks()stripUnderlines()在每个上调用下面粘贴的函数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);
    }

这需要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:2125551212new URLSpanNoUnderline应该传递该呼叫span.getURL()以保留此信息,否则,您将生成错误的链接,这些链接会在单击时导致异常。由于我自己没有编辑权限,因此已将这个建议的解决方案放入您的答案的编辑队列中。
Mike Mueller

8
不为我工作。它在Line Spannable s =(Spannable)textView.getText();处给出类强制转换异常。
Brijesh Thakur

5
只需用Spannable s = new SpannableString(textView.getText())替换该行即可;
FOliveira 2014年

1
与更换Spannable s = (Spannable) textView.getText()Spannable s = new SpannableString(textView.getText());不适合我的工作。如果我切换回强制转换,则只有在TextView具有的情况下它才起作用android:textIsSelectable=true。知道为什么吗?
2015年

2
有什么办法可以使该android:autoLink属性起作用?否则,您似乎必须为内置功能创建自己的onclick方法。
Alkarin

32

给定一个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);包含链接的链接将不再起作用。
Rain Man

1
怎么可能?字符串不知道其起源。字符串内容必须有所不同。
Adriaan Koster

不知道为什么,但是当我调用res/values/strings.xml包含与示例完全相同的字符串时,它不显示URL 。可以测试一下吗?
Rain Man

我绝对不会在最后进行测试(-:。如果您想确定字符串的内容,请将两个字符串及其hashCode一起记录。如果将上面的代码与完全一样的琴弦
Adriaan Koster

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

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

2

每当我尝试仅使用以下内容时,尝试使用可扩展性删除URL下划线

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 ... !!!


这是最好的解决方案,也是唯一对我
有用的

该解决方案适用于具有一个URL的文本。
CoolMind

1

如果您正在使用Textview自动链接属性,并且想要删除下划线,则可以使用它:

首先,扩展UnderlineSpan并删除下划线:

public class NoUnderlineSpan extends UnderlineSpan {

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

其次,创建NoUnderlineSpan并实例化,从String文本创建Spannable并将span设置为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的非下划线状态。
Francisco Moya

0

如果您只想输入文字而不必担心URL链接

这将删除链接,但保留文本

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. 创建一个自定义的span类,以处理下划线。
    class URLSpanNoUnderline : URLSpan {
            public URLSpanNoUnderline (string url) : base (url) {
            }

            public override void UpdateDrawState (TextPaint ds) {
                base.UpdateDrawState (ds);
                ds.UnderlineText = false;
            }
        }
  1. 创建一个扩展方法以查找所有网址范围,并将其替换为我们的自定义范围。
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);
            }
        }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.