android中TextView的Spnnable使用

Posted 小向光

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android中TextView的Spnnable使用相关的知识,希望对你有一定的参考价值。

项目中设计出的效果,我立即想到要使用SpannableString做出此效果。但我对SpannableString只是有基本的了解,下面我就记录下自己收集以及尝试的效果。

ApiDemo 源码至 com.example.android.apis.text.Link 类,可以看到text的不同效果。


一、自动应用效果,使用 android:autolink ="email|phone|web|map|all"属性

<!-- text1 automatically linkifies things like URLs and phone numbers. -->
      <TextView android:id="@+id/text1"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingBottom="8dp"
                android:autoLink="all"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:text="@string/link_text_auto"
                />

点击数字,就会进入拨号页面;点击网址,就会在浏览器打开对应的网址;点击邮箱就进入发邮箱的功能;


二、在文本中使用 <a> 标签

 <string name="link_text_manual"><b>text2: Explicit links using <a> markup.</b>
      This has markup for a <a href="http://www.google.com">link</a> specified
      via an <a> tag.  Use a \\"tel:\\" URL
      to <a href="tel:4155551212">dial a phone number</a>.
    </string>

 <!-- text2 uses a string resource containing explicit <a> tags to
           specify links. -->
      <TextView android:id="@+id/text2"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:paddingTop="8dp"
                android:paddingBottom="8dp"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:text="@string/link_text_manual"
                />

    // text2 has links specified by putting <a> tags in the string
        // resource.  By default these links will appear but not
        // respond to user input.  To make them active, you need to
        // call setMovementMethod() on the TextView object.

        TextView t2 = (TextView) findViewById(R.id.text2);
        t2.setMovementMethod(LinkMovementMethod.getInstance());


三、第三种和第二种其实是一样的,只不过将文本改在 JAVA 代码中

 // text3 shows creating text with links from html in the Java
        // code, rather than from a string resource.  Note that for a
        // fixed string, using a (localizable) resource as shown above
        // is usually a better way to go; this example is intended to
        // illustrate how you might display text that came from a
        // dynamic source (eg, the network).

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

四、通过创建 SpanableString 字符串,并在之上创 建一个或多个 Span 来实现丰富的效果。

SpannableString的定义:

This is the class for text whose content is immutable but to which markup objects can be attached and detached. For mutable text, see SpannableStringBuilder.
<span style="color:#FF0000;"><strong>翻译:SpannableString</strong>是文本内容不可改变,但标记对象可以绑定和解绑的类。</span>

官方文档中前半句话好理解,后半句就不怎么好理解了。问题就来了:

  • 什么是标记对象呢(markup objects)?
  • 绑定和解绑(attached and detached)又是什么意思呢?
标记对象

标记语言(也称置标语言、标记语言、标志语言、标识语言)是一种将文本(Text)以及文本相关的其他信息结合起来,展现出关于文档结构和数据处理细节的计算机文字编码。至于标记对象则是和标记语言一个意思,就是能设置文本的各种样式的方法。


例子如下:

link_color的写法如下:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_pressed="true"
          android:color="#ffff00"/> <!-- pressed -->
    <item android:state_focused="true"
          android:color="#ffff00"/> <!-- focused -->
    <item android:color="#ff0000"/> <!-- default -->

</selector>

java代码如下:

textView =(TextView) findViewById(R.id.textview);
		//使用setSpan(Object what, int start, int end, int flags)方法设置标记对象,其中长度是end-start。
	    //使用removeSpan()解绑标记对象
	    //public void setSpan (Object what, int start, int end, int flags)
	    //绑定特定的标记对象(Object what)到起始为start,终止为end的text对象上(若已绑定标记对象则先移除)
	    //设置字体TypefaceSpan()
	    //设置字体大小(绝对值)AbsoluteSizeSpan()
	    //设置字体大小(相对值)RelativeSizeSpan()
	    //设置字体大小(相对值,默认字体宽度的倍数)ScaleXSpan()
	    //设置字体的前景色ForegroundColorSpan()
	    //设置字体的背景色BackgroundColorSpan()
	    //设置字体的样式StyleSpan()
	    //设置下划线UnderlineSpan()
	    //删除线StrikethroughSpan()
	    //上标SuperscriptSpan()
	    //下标SubscriptSpan()
	    //链接URLSpan()-->需要添加setMovementMethod方法附加响应
	    //字体外观设置(依次包括字体名称,字体大小,字体样式,字体颜色,链接颜色)TextAppearanceSpan()
	    //项目符号BulletSpan()
	    //图片ImageSpan()
		//android.text.style.XXX 获取各种span的Parcel属性

		  //创建一个 SpannableString对象  
        msp = new SpannableString("字体测试字体大小一半两倍前景色背景色正常粗体斜体粗斜体下划线删除线x1x2电话邮件网站短信彩信地图X轴综合/bot"); 
        
        //设置字体(default,default-bold,monospace,serif,sans-serif)
        msp.setSpan(new TypefaceSpan("monospace"), 0, 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        msp.setSpan(new TypefaceSpan("serif"), 2, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        
        //设置字体大小(绝对值,单位:像素) 
        msp.setSpan(new AbsoluteSizeSpan(20), 4, 6, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
       //第二个参数boolean dip,如果为true,表示前面的字体大小单位为dip,否则为像素,同上。
        msp.setSpan(new AbsoluteSizeSpan(20,true), 6, 8, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);  
        
        //设置字体大小(相对值,单位:像素) 参数表示为默认字体大小的多少倍
        msp.setSpan(new RelativeSizeSpan(0.5f), 8, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);  //0.5f表示默认字体大小的一半
        msp.setSpan(new RelativeSizeSpan(2.0f), 10, 12, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);  //2.0f表示默认字体大小的两倍
        
        //设置字体前景色
        msp.setSpan(new ForegroundColorSpan(Color.MAGENTA), 12, 15, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);  //设置前景色为洋红色
        
        //设置字体背景色
        msp.setSpan(new BackgroundColorSpan(Color.GREEN), 15, 18, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);  //设置背景色为青色
     
        //设置字体样式正常,粗体,斜体,粗斜体
        msp.setSpan(new StyleSpan(android.graphics.Typeface.NORMAL), 18, 20, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);  //正常
        msp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 20, 22, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);  //粗体
        msp.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 22, 24, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);  //斜体
        msp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD_ITALIC), 24, 27, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);  //粗斜体
        
        //设置下划线
        msp.setSpan(new UnderlineSpan(), 27, 30, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        //设置删除线
        msp.setSpan(new StrikethroughSpan(), 30, 33, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        
        //设置上下标
        msp.setSpan(new SubscriptSpan(), 34, 35, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);     //下标   
        msp.setSpan(new SuperscriptSpan(), 36, 37, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);   //上标            
        
        //超级链接(需要添加setMovementMethod方法附加响应)
        msp.setSpan(new URLSpan("tel:4155551212"), 37, 39, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);     //电话   
        msp.setSpan(new URLSpan("mailto:webmaster@google.com"), 39, 41, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);     //邮件   
        msp.setSpan(new URLSpan("http://www.baidu.com"), 41, 43, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);     //网络   
        msp.setSpan(new URLSpan("sms:4155551212"), 43, 45, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);     //短信   使用sms:或者smsto:
        msp.setSpan(new URLSpan("mms:4155551212"), 45, 47, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);     //彩信   使用mms:或者mmsto:
        msp.setSpan(new URLSpan("geo:38.899533,-77.036476"), 47, 49, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);     //地图   
        
        //设置字体大小(相对值,单位:像素) 参数表示为默认字体宽度的多少倍
      //2.0f表示默认字体宽度的两倍,即X轴方向放大为默认字体的两倍,而高度不变
        msp.setSpan(new ScaleXSpan(2.0f), 49, 51, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 
        
        //设置字体(依次包括字体名称,字体大小,字体样式,字体颜色,链接颜色)
        ColorStateList csllink = null;
        ColorStateList csl = null;
        XmlResourceParser xppcolor=getResources().getXml(R.drawable.link_color);
        try {
        	csl= ColorStateList.createFromXml(getResources(),xppcolor);
        	csllink= ColorStateList.createFromXml(getResources(),xppcolor);
        }catch(XmlPullParserException e){
        	e.printStackTrace();    	
        }catch(IOException e){
        	e.printStackTrace();    	
        }
        msp.setSpan(new TextAppearanceSpan("monospace",android.graphics.Typeface.BOLD_ITALIC, 30, csl, csllink), 51, 53, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 
        
        //设置项目符号
        msp.setSpan(new BulletSpan(android.text.style.BulletSpan.CONTENTS_FILE_DESCRIPTOR,Color.RED), 0 ,msp.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //第一个参数表示项目符号占用的宽度,第二个参数为项目符号的颜色

        //设置图片
        Drawable drawable = getResources().getDrawable(R.drawable.ic_launcher); 
        drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());  
        msp.setSpan(new ImageSpan(drawable), 53, 57, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        
        textView.setText(msp);
        textView.setMovementMethod(LinkMovementMethod.getInstance()); 

效果如下:



最后有几个点要说明:

1)许多span都有XXXSpan(Parcel src)的构造方法,在android.text.style.XXX.XXX中获取各种span的Parcel属性

 2) setSpan(Object what, int start, int end, int flags)中的flag有几个值:

SPAN_INCLUSIVE_EXCLUSIVE(前后都包括): [0,5]

SPAN_INCLUSIVE_INCLUSIVE(前面包括,后面不包括):[0,5)

SPAN_EXCLUSIVE_EXCLUSIVE(前后都不包括):(0,5)

SPAN_EXCLUSIVE_INCLUSIVE(前面不包括,后面包括):(0,5]

3)使用TextAppearanceSpan时,color必须是selector类型。

/**
     * Makes text be drawn with the specified typeface, size, style,
     * and colors.
     */
    public TextAppearanceSpan(String family, int style, int size,
                              ColorStateList color, ColorStateList linkColor) {
        mTypeface = family;
        mStyle = style;
        mTextSize = size;
        mTextColor = color;
        mTextColorLink = linkColor;
    }


以上是关于android中TextView的Spnnable使用的主要内容,如果未能解决你的问题,请参考以下文章

Android textView中划线

Android中用TextView显示大量文字的方法

Android中TextView的TextAppearance属性

android中textview的圆角

Android中TextView的水平和垂直居中文本

Android从零单排系列六《Android视图控件——TextView》