ลบขีดเส้นใต้จากลิงก์ใน 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 หรือ Code?

คำตอบ:


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 ใน tel:2125551212URL new URLSpanNoUnderlineโทรควรจะผ่านspan.getURL()การรักษาข้อมูลนี้มิฉะนั้นคุณสร้างการเชื่อมโยงที่ไม่ดีที่ข้อยกเว้นสาเหตุเมื่อคลิก ฉันได้วางโซลูชันที่เสนอนี้ไว้ในคิวแก้ไขสำหรับคำตอบของคุณแล้วเนื่องจากฉันไม่มีสิทธิ์แก้ไขด้วยตนเอง
Mike Mueller

8
ไม่ทำงานสำหรับฉัน มันให้ Class Cast Exception ที่ Line Spannable s = (Spannable) textView.getText ();
Brijesh Thakur

5
เพียงแค่แทนที่บรรทัดนั้นด้วย Spannable s = SpannableString ใหม่ (textView.getText ());
FOliveira

1
แทนที่ด้วยSpannable s = (Spannable) textView.getText()กับSpannable s = new SpannableString(textView.getText());ไม่ทำงานสำหรับฉัน ถ้าผมเปลี่ยนกลับไปหล่อแล้วมันไม่ทำงาน แต่ถ้า TextView android:textIsSelectable=trueมี คิดว่าทำไม?
b.lit

2
มีวิธีใดบ้างที่จะทำให้android:autoLinkคุณลักษณะนี้ใช้งานได้ มิฉะนั้นดูเหมือนว่าคุณต้องสร้างเมธอด onclick ของคุณเองเพื่อให้มีฟังก์ชันในตัว
Alkarin

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);ซึ่งรวมถึงลิงก์จะไม่ทำงานอีกต่อไป
Rain Man

1
จะเป็นไปได้อย่างไร? สตริงไม่ทราบว่ามีต้นกำเนิดมาจากที่ใด ต้องมีความแตกต่างในเนื้อหาสตริง
Adriaan Koster

ไม่แน่ใจว่าทำไม แต่มันไม่แสดง url เมื่อฉันเรียกสตริงres/values/strings.xmlที่มีสิ่งเดียวกับตัวอย่าง คุณสามารถทดสอบในตอนท้ายของคุณได้หรือไม่?
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);
}

4

นี่คือฟังก์ชั่นส่วนขยายของ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()    

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

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เป็น Object ของSpannableString ... !!!


นี่เป็นทางออกที่ดีที่สุดและวิธีเดียวที่ใช้ได้ผลสำหรับฉัน
GuilhE

โซลูชันนี้ใช้สำหรับข้อความที่มี URL เดียว
CoolMind

1

หากคุณกำลังใช้คุณสมบัติ Textview autolink และคุณต้องการลบขีดเส้นใต้คุณสามารถใช้ได้:

ขั้นแรกให้ขยาย 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 no ขีดเส้นใต้
Francisco Moya

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);
            }
        }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.