求助android开发里,如何部分文字超链接

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求助android开发里,如何部分文字超链接相关的知识,希望对你有一定的参考价值。

实现类似微信注册下方的“点击上面的注册按钮,即表示你同意《XXX条约》” 就是只有点击那个条约才会跳转。Spannable对象我看过了,但是我要用的是XML里的textview,不是直接在JAVA里添加的文字。
就是现在我想实现这里的《XXX条款和服务协议》超链接

可以使用html标签的方式来实现,android中的TextView,本身就支持部分的Html格式标签。这其中包括常用的字体大小颜色设置,文本链接等。使用起来也比较方便,只需要使用Html类转换一下即可。比如:

textView.setText(Html.fromHtml(str));


一、实现TextView里的文字有不同颜色
import android.text.Html; 

TextView t3 = (TextView) findViewById(R.id.text3); 
t3.setText(Html.fromHtml( "<b>text3:</b> Text with a " + "<a href="http://www.google.com">link</a> " +"created in the Java source code using HTML.")); 


二、TextView显示html文件中的图片
我们知道要让TextView解析和显示Html代码。可以使用
Spanned text = Html.fromHtml(source); 
tv.setText(text); 
来实现,这个用起来简单方便。 
但是,怎样让TextView也显示Html中<image>节点的图像呢? 
我们可以看到fromHtml还有另一个重构: 
fromHtml(String source, Html.ImageGetter imageGetter, Html.TagHandler tagHandler) 



实现一下ImageGetter就可以让图片显示了:
ImageGetter imgGetter = new Html.ImageGetter()  
@Override 
public Drawable getDrawable(String source)  
Drawable drawable = null; 
drawable = Drawable.createFromPath(source); // Or fetch it from the URL 
// Important 
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable 
.getIntrinsicHeight()); 
return drawable; 
 


三 TextView + HTML的应用代码

我们平常使用TextView的setText()方法传递String参数的时候,其实是调用的public final void setText (CharSequence text)方法

而String类是CharSequence的子类,在CharSequence子类中有一个接口Spanned,即类似html的带标记的文本,我们可以用它来在TextView中显示html。但在源代码上面Android源码注释中有提及TextView does not accept HTML-like formatting。


android.text.Html类共提供了三个方法,可以到Android帮助文档查看。

public static Spanned fromHtml (String source)

public static Spanned fromHtml (String source, Html.ImageGetter imageGetter, Html.TagHandler tagHandler)

public static String toHtml (Spanned text)



通过使用第一个方法,可以将Html显示在TextView中:

public void onCreate(Bundle savedInstanceState)   

        super.onCreate(savedInstanceState);  

        setContentView(R.layout.main);  

  

        TextView tv=(TextView)findViewById(R.id.textView1);  

        String html="<html><head><title>TextView使用HTML</title></head><body><p><strong>强调</strong></p><p><em>斜体</em></p>"  

                +"<p><a href=\\"http://www.dreamdu.com/xhtml/\\">超链接HTML入门</a>学习HTML!</p><p><font color=\\"#aabb00\\">颜色1"  

                +"</p><p><font color=\\"#00bbaa\\">颜色2</p><h1>标题1</h1><h3>标题2</h3><h6>标题3</h6><p>大于>小于<</p><p>" +  

                "下面是网络图片</p><img src=\\"http://avatar.csdn.net/0/3/8/2_zhang957411207.jpg\\"/></body></html>";            

        tv.setMovementMethod(ScrollingMovementMethod.getInstance());//滚动  

        tv.setText(Html.fromHtml(html));      

      


效果: 

可以看出,字体效果是显示出来了,但是图片却没有显示。要实现图片的显示需要使用Html.fromHtml的另外一个重构方法:public static Spanned fromHtml (String source, Html.ImageGetterimageGetter, Html.TagHandler tagHandler)其中Html.ImageGetter是一个接口,我们要实现此接口,在它的getDrawable(String source)方法中返回图片的Drawable对象才可以。

参考技术A text.setText("点击上面的“下一步”按钮,即表示你同意");
text.append(Html.fromHtml("<a href=\""+"http://www.baidu.com"+"\">"+"《XXX条款和服务协议》"+"</a> "));
这样写就可以了追问

您好,点击后没反应 没发生跳转是怎么回事?

追答

这种方法在虚拟机上是点不了的,你可以试试在真机上运行

追问

可以了 加了行代码就OK了!谢谢你!

本回答被提问者采纳

Android如何通过TextView实现超链接的跳转

前段时间在开发群里看到有人问androidTextView该如何自定义超链接的跳转,如:有字符串“使用该软件,即表示您同意该软件的使用条款隐私政策”,现希望当点击“使用条款”或“隐私政策”时可以跳转到相应的说明页面,我还记得当时有一大堆人在讨论然后提了一大堆的方法,比如:用多个TextView组合,给相应的TextView添加点击事件、给TextView添加autoLink属性、通过给相应的内容添加<a></a>标签、借助Spannable类、Linkfy类等等,当然最后提问者采用哪种方法我就不得而知了,我呢也刚好最近几天比较有空,然后翻了下Api文档,于是通过几个晚上的总结形成了今天的这篇博客,内容比较多,还望大家能够耐心点,相信大家看完肯定对TextView的各种超链接的跳转及实现水到渠来。

1autoLink属性

TextView属性比较熟悉的开发者应该都知道TextView有一个叫做autoLink的属性可以将符合指定格式的文本转换为可单击的超链接形式,在帮助文档中也可以发现Android给我们提供了如下几种格式:

1、none:表示不进行任何匹配,默认;

2、Web:表示匹配Web Url,如:内容中的http://www.baidu.com会成为可单击跳转的超链接;

3、Email:表示匹配邮件地址:如:邮件地址为hello@com.cn会成为可单击的超链接;

4、Phone:表示匹配电话号码:如:点击号码10086会跳到拨号界面;

5、Map:表示匹配地图地址;

6、All:表示将会匹配webemailphonemap

为了验证android给我们提供的几种格式,我在布局中添加了几个TextView并且分别设置了autoLink属性及相应的值,运行程序后可以发现,内容中符合格式的都带上了下划线并且有相应的颜色,如下所示:

 

1)拦截超链接

虽然通过设置autoLink属性可以符合格式的文本转换为可单击的超链接形式,但是,有一点需要注意的是,当点击web地址时打开后跳转的是手机自带的浏览器,如果希望点击web地址时可以跳转到应用本身的一个WebView界面,那么此时又该如何实现呢?如果不知道怎么实现的话,我们可以点击TextView进去查看一下TextView的源码看一下autoLink的是如何实现的,通过ctrl+f查找autoLink可以发现如下代码:

case com.android.internal.R.styleable.TextView_autoLink:
    mAutoLinkMask = a.getInt(attr, 0);
    break;
继续通过ctrl+f 查找mAutoLinkMask变量可以发现setText 方法中有如下代码:

if (mAutoLinkMask != 0) 
    Spannable s2;

    if (type == BufferType.EDITABLE || text instanceof Spannable) 
        s2 = (Spannable) text;
     else 
        s2 = mSpannableFactory.newSpannable(text);
    

    if (Linkify.addLinks(s2, mAutoLinkMask)) 
        text = s2;
        type = (type == BufferType.EDITABLE) ? BufferType.EDITABLE : BufferType.SPANNABLE;

        /*
         * We must go ahead and set the text before changing the
         * movement method, because setMovementMethod() may call
         * setText() again to try to upgrade the buffer type.
         */
        mText = text;

        // Do not change the movement method for text that support text selection as it
        // would prevent an arbitrary cursor displacement.
        if (mLinksClickable && !textCanBeSelected()) 
            setMovementMethod(LinkMovementMethod.getInstance());
        
    
在代码中可以看到有一个if (Linkify.addLinks(s2, mAutoLinkMask))的判断,点击进去可以发现Linkify.addLinks方法别有洞天,代码如下所示:

public static final boolean addLinks(Spannable text, int mask) 
    if (mask == 0) 
        return false;
    

    URLSpan[] old = text.getSpans(0, text.length(), URLSpan.class);

    for (int i = old.length - 1; i >= 0; i--) 
        text.removeSpan(old[i]);
    

    ArrayList<LinkSpec> links = new ArrayList<LinkSpec>();

    if ((mask & WEB_URLS) != 0) 
        gatherLinks(links, text, Patterns.WEB_URL,
            new String[]  "http://", "https://", "rtsp://" ,
            sUrlMatchFilter, null);
    
  ......此处省略若干省略若干行代码
    for (LinkSpec link: links) 
        applyLink(link.url, link.start, link.end, text);
    

    return true;
然后我们点击进到 applyLink方法中可以看到有如下实现:

private static final void applyLink(String url, int start, int end, Spannable text) 
    URLSpan span = new URLSpan(url);
    text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
如果大家对里面的其它方法比较感兴趣的话也可以一一点击进去查看相应的实现,我这里就不再一一介绍了,额,貌似有点扯远了,我们回到正题,总之 在经过一系列的翻阅跟TextView 相关的源码和帮助文档后,发现我们可以通过借助 Spannable 来获取 URLSpan 数组然后可以通过遍历获取所有的 url 地址,最后通过给 Spannable 设置自定义的 ClickableSpan 来进行跳转, MainActivity 的主要代码如下所示:

public class MainActivity extends AppCompatActivity 

    private TextView tv_content;
    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_content = (TextView) findViewById(R.id.tv_content);
        interceptHyperLink(tv_content);
    

    /**
     * 拦截超链接
     * @param tv
     */
    private void interceptHyperLink(TextView tv) 
        tv.setMovementMethod(LinkMovementMethod.getInstance());
        CharSequence text = tv.getText();
        if (text instanceof Spannable) 
            int end = text.length();
            Spannable spannable = (Spannable) tv.getText();
            URLSpan[] urlSpans = spannable.getSpans(0, end, URLSpan.class);
            if (urlSpans.length == 0) 
                return;
            

            SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(text);
            // 循环遍历并拦截 所有http://开头的链接
            for (URLSpan uri : urlSpans) 
                String url = uri.getURL();
                if (url.indexOf("http://") == 0) 
                    CustomUrlSpan customUrlSpan = new CustomUrlSpan(this,url);
                    spannableStringBuilder.setSpan(customUrlSpan, spannable.getSpanStart(uri),
                            spannable.getSpanEnd(uri), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
                
            
            tv.setText(spannableStringBuilder);
        
    
自定义ClickableSpan 子类的CustomUrlSpan的主要代码如下所示:

public class CustomUrlSpan extends ClickableSpan 

    private Context context;
    private String url;
    public CustomUrlSpan(Context context,String url)
        this.context = context;
        this.url = url;
    

    @Override
    public void onClick(View widget) 
        // 在这里可以做任何自己想要的处理
        Intent intent = new Intent(context,WebViewActivity.class);
        intent.putExtra(WebViewActivity.WEB_URL,url);
        context.startActivity(intent);
    
在CustomUrlSpan 类的 onClick 方法中进行跳转时用到的WebViewActivity代码这里就不再贴出来,主要就是一个用来加载网页的WebView ,如果有需要的可以在文章末尾下载源码查看;

2)去除超链接的下划线

众所周知,超链接都带有一条下划线表示可点击的,那么如果想去除超链接的下划线又该如何实现呢?既然下划线是用来表示可点击的,那么就说明跟点击事件有关,从上面拦截超链接的实现中知道点击超链接进行跳转是借助ClickableSpan类实现的,进到ClickableSpan类中可以发现该类出奇的简单,如下所示:

 

从源码中可以发现,超链接中的下划线是通过TextPaintsetUnderlineText方法来实现的,也就是说如果我们想去除超链接中的下划线的话可以通过自定义一个继承自ClickableSpan的类然后重写其updateDrawState方法,在该方法中将TextPaintsetUnderlineText方法设为false,最后再将该自定义的ClickableSpan设置到的相应的TextView中即可,原则上来说通过自定义一个继承自ClickableSpan的类是可以去除超链接的下划线,但是,在这里我将使用跟ClickableSpan类似的一个类UnderlineSpan来实现,至于原因想必大家看类名就很容易知道了。

1)首先自定义一个继承自UnderlineSpan类的NoUnderlineSpan类并重写父类的updateDrawState方法,然后在该方法中将TextPaintsetUnderlineText方法设为false,主要代码如下:

public class NoUnderlineSpan extends UnderlineSpan 

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

 
2 )在需要去除超链接下划线的 Activity 中的相应 TextView 后设置如下内容:

private void removeHyperLinkUnderline(TextView tv) 
    CharSequence text = tv.getText();
    if(text instanceof Spannable)
        Log.i("test","true");
        Spannable spannable = (Spannable) tv.getText();
        NoUnderlineSpan noUnderlineSpan = new NoUnderlineSpan();
        spannable.setSpan(noUnderlineSpan,0,text.length(), Spanned.SPAN_MARK_MARK);
    
运行后效果如下所示:


2)自定义链接

除了以上通过添加autoLink属性并设置web值实现超链接以外,android还给我们提供了一个Linkify类来自定义超链接,并且从帮助文档中可以看出Linkify还提供了一大堆添加自定义模式的方法,如下所示:


这里为了方便,暂且用有3个参数的构造方法即最后一个,其中第一个参数TextView即需要自定义模式的对象,第二个参数Pattern表示自己定义的用来匹配第一个参数TextView中内容的正则表达式,最后一个参数Scheme我理解为当点击自定义链接时跳转的界面,如:在布局文件中新增一个TextView并设置一些默认的内容,然后在代码如下通过如下方式设置自定义链接:

TextView  tv_customHyperLink = (TextView) findViewById(R.id.tv_customHyperLink);
//配置的正则表达式
Pattern p = Pattern.compile("abc://\\\\S*");
Linkify.addLinks(tv_customHyperLink, p, "abc");
为了当点击自定义链接时点击能够响应,在这里我新建了一个TargetActivity 类专门用来处理响应,但是有一点需要注意是需要在 AndroidManifest 清单文件中相应的 activity 节点下添加如下代码:

<activity android:name=".TargetActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <!--隐式调用时,必须声明类别-->
        <category android:name="android.intent.category.DEFAULT"/>
        <!--必须和代码中设置scheme一样-->
        <data android:scheme="abc"/>
    </intent-filter>
</activity>
此时,运行程序,当点击自定义链接时便会跳转到能够响应的scheme 为“ abc ”的界面中:


点击链接跳转后的页面为:


当然,我们也可以通过这种方法实现上面所实现的拦截超链接的功能,这里就不再详细说明了,另外,当一个TextView即需要使用内置模式又需要使用自定义模式时必须先声明内置模式然后再声明自定义模式,并且经测试发现:不能在xml布局文件中通过autoLink属性来声明内置模式,否则自定义模式不起作用,据说是因为:在设置内置模式时会先删除已有的模式,那么此时就只能通过在代码中设置了,主要代码如下所示:

//多种模式
TextView  tv_multiHyperLink = (TextView) findViewById(R.id.tv_multiHyperLink);
Linkify.addLinks(tv_multiHyperLink,Linkify.PHONE_NUMBERS);
Pattern pattern = Pattern.compile("abc://\\\\S*");
Linkify.addLinks(tv_multiHyperLink, pattern, "abc");

运行程序,结果如下所示:


3)借助Html实现文字的超链接

细心的你们也许会发现以上都是对一些链接进行的操作,当然你们也许会说可以通过自定义链接的形式对指定的文字进行正则匹配来实现,但是通过正则匹配中文的话应该比较难实现吧,所以,我们可以通过类似于html中超链接(即a标签)的方式来实现,考虑到字符串的来源及格式,于是总结出了比较常用的以下3种,主要代码如下所示:

//通过html的形式实现超链接
String csdnLink1 = "<a href=\\"http://blog.csdn.net/zhangjinhuang\\">我的CSDN博客</a>";
TextView  tv_html1 = (TextView) findViewById(R.id.tv_html1);
tv_html1.setText(Html.fromHtml(csdnLink1));
//设置超链接可点击
tv_html1.setMovementMethod(LinkMovementMethod.getInstance());

String csdnLink2 = "http://blog.csdn.net/zhangjinhuang我的CSDN博客";
TextView  tv_html2 = (TextView) findViewById(R.id.tv_html2);
tv_html2.setText(Html.fromHtml(csdnLink2));
//设置超链接可点击
tv_html2.setMovementMethod(LinkMovementMethod.getInstance());

String csdnLink3 = getResources().getString(R.string.csdn);
TextView  tv_html3 = (TextView) findViewById(R.id.tv_html3);
tv_html3.setText(Html.fromHtml(csdnLink3));
//设置超链接可点击
tv_html3.setMovementMethod(LinkMovementMethod.getInstance());
运行程序后可以发现只有第一种的写法才能被Html fromHtml 方法格式化为超链接,如下所示:


4)借助SpannableString定制超链接的跳转

在上面我们通过Html类的fromHtml方法来格式化a标签中的内容从而实现文字的超链接,但是依旧还是跟web地址关联在一起,也就是说如果只是单纯的点击某个文字然后跳转到指定某个界面的话还是无法实现的,因此,在这里我将通过SpannableString类来实现类似文章开头谈到的 当点击“使用该软件,即表示您同意该软件的使用条款隐私政策”,中的“使用条款”或“隐私政策”时可以跳转到相应的说明页面的功能。相信很多人都对SpannableString并不陌生,因为当想让一个字符串中的指定字符变大或者改变颜色再或者设置下划线等时都需要借助该类来实现,其实在一开始讲解“拦截超链接”时就已经使用了相应的功能了,但是在这里还是通过代码来着重的实现一下,首先对相应的TextView进行如下设置:

//借助SpannableString类实现超链接文字
tv_customMultiHyperLink = (TextView) findViewById(R.id.tv_customMultiHyperLink);
tv_customMultiHyperLink.setText(getClickableSpan());
//设置超链接可点击
tv_customMultiHyperLink.setMovementMethod(LinkMovementMethod.getInstance());
 
其中getClickableSpan 方法的主要代码如下所示:

/**
 * 获取可点击的SpannableString
 * @return
 */
private SpannableString getClickableSpan() 
    SpannableString spannableString = new SpannableString("使用该软件,即表示您同意该软件的使用条款和隐私政策");
    //设置下划线文字
    spannableString.setSpan(new UnderlineSpan(), 16, 20, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    //设置文字的单击事件
    spannableString.setSpan(new ClickableSpan() 
        @Override
        public void onClick(View widget) 
            Toast.makeText(MainActivity.this,"使用条款",Toast.LENGTH_SHORT).show();
        
    , 16, 20, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    //设置文字的前景色
    spannableString.setSpan(new ForegroundColorSpan(Color.RED), 16, 20, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

    //设置下划线文字
    spannableString.setSpan(new UnderlineSpan(), 21, 25, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    //设置文字的单击事件
    spannableString.setSpan(new ClickableSpan() 
        @Override
        public void onClick(View widget) 
            Toast.makeText(MainActivity.this,"隐私政策",Toast.LENGTH_SHORT).show();
        
    , 21, 25, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    //设置文字的前景色
    spannableString.setSpan(new ForegroundColorSpan(Color.RED), 21, 25, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
    return spannableString;

 
运行程序,可以看到想要实现的文字超链接已经实现了,为了方便,这里当点击相应的文字时通过弹出相应的提示来说明,如下所示:



源码下载


以上是关于求助android开发里,如何部分文字超链接的主要内容,如果未能解决你的问题,请参考以下文章

Android TextView中文字通过SpannableString来设置超链接颜色字体等属性

求助,如何在listview里addheadview-Android开发问答

超链接文字隐藏

Android消息推送能推送图片吗?还是只能推送文字信息?

Android如何通过TextView实现超链接的跳转

Android如何通过TextView实现超链接的跳转