本文共 5636 字,大约阅读时间需要 18 分钟。
TextView 应该是Android 中使用频率最高的控件之一,其重要性不言而喻
在平时的开发中,对于TextView的使用方法无非就是在layout 中设置一下布局、样式、颜色等,要是需要进行改变,丢到handler里
复杂一点的可以引入字体文件,通过资源进行设置
但是如果要在一定的范围内改变字体的样式怎么解决?拆分String,用两个TextView?
如果要让TextView实现类似于超链接的跳转功能怎么解决?添加监听事件,配合Intent使用?
再牛逼点,如果我要你TextView 显示图片,咋整? 啥?强转会报错?
现在,就正式请出今天的主角,SpannableString和SpannableStringBuilder
先说说二者的区别, SpannableString的长度固定,而SpannableStringBuilder的长度是可以改变的
本文着重就以SpannableString为例,至于SpannableStringBuilder的使用,我相信每个开发人员都懂得触类旁通,就不多介绍了
首先,我们先看下SpannableString的源码
public class SpannableStringextends SpannableStringInternalimplements CharSequence, GetChars, Spannable{ public SpannableString(CharSequence source) { super(source, 0, source.length()); } private SpannableString(CharSequence source, int start, int end) { super(source, start, end); } public static SpannableString valueOf(CharSequence source) { if (source instanceof SpannableString) { return (SpannableString) source; } else { return new SpannableString(source); } } public void setSpan(Object what, int start, int end, int flags) { super.setSpan(what, start, end, flags); } public void removeSpan(Object what) { super.removeSpan(what); } public final CharSequence subSequence(int start, int end) { return new SpannableString(this, start, end); }}继承了抽象类SpannableStringInternal,和三个接口CharSequence, GetChars, Spannable
构造函数
public SpannableString(CharSequence source) {
super(source, 0, source.length()); }参数就不多解释了
再看看setSpan方法
public void setSpan(Object what, int start, int end, int flags) { super.setSpan(what, start, end, flags); }
传入的参数有四个,这里解释下
/*** what 字体设置的格式* start 所设置字体的起始下标* end 所设置结束下标* flags 下标取值标志,取值:* Spanned.SPAN_INCLUSIVE_EXCLUSIVE 从起始下标到结束下标,包括起始下标* Spanned.SPAN_INCLUSIVE_INCLUSIVE 从起始下标到结束下标,同时包括起始下标和结束下标* Spanned.SPAN_EXCLUSIVE_EXCLUSIVE 从起始下标到终了下标,但都不包括起始下标和结束下标* Spanned.SPAN_EXCLUSIVE_INCLUSIVE 从起始下标到结束下标,包括结束下标**/有点拗口,但就是高中数学里交集并集的关系
如果实在不行,就看看我这边的栗子
package com.example.textviewdemo;import android.app.Activity;import android.graphics.Color;import android.os.Bundle;import android.text.Spannable;import android.text.SpannableString;import android.text.style.ForegroundColorSpan;import android.widget.EditText;public class MainActivity extends Activity { /** * what 字体设置的格式 * start 所设置字体的起始下标 * end 所设置结束下标 * flags 下标取值标志,取值: * Spanned.SPAN_INCLUSIVE_EXCLUSIVE 从起始下标到结束下标,包括起始下标 * Spanned.SPAN_INCLUSIVE_INCLUSIVE 从起始下标到结束下标,同时包括起始下标和结束下标 * Spanned.SPAN_EXCLUSIVE_EXCLUSIVE 从起始下标到终了下标,但都不包括起始下标和结束下标 * Spanned.SPAN_EXCLUSIVE_INCLUSIVE 从起始下标到结束下标,包括结束下标 **/ private EditText mEt1,mEt2,mEt3,mEt4; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView(){ mEt1 = (EditText)findViewById(R.id.et1); mEt2 = (EditText)findViewById(R.id.et2); mEt3 = (EditText)findViewById(R.id.et3); mEt4 = (EditText)findViewById(R.id.et4); //构造SpannableString SpannableString spanString = new SpannableString("天王盖地虎宝塔镇河妖"); SpannableString spanString2 = new SpannableString("天王盖地虎宝塔镇河妖"); SpannableString spanString3 = new SpannableString("天王盖地虎宝塔镇河妖"); SpannableString spanString4 = new SpannableString("天王盖地虎宝塔镇河妖"); //用于改变字体颜色的ForegroundColorSpan ForegroundColorSpan span = new ForegroundColorSpan(Color.BLUE); //设定范围,传入不同的flag spanString.setSpan(span, 1, 3, Spannable.SPAN_INCLUSIVE_EXCLUSIVE); spanString2.setSpan(span, 1, 3, Spannable.SPAN_INCLUSIVE_INCLUSIVE); spanString3.setSpan(span, 1, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spanString4.setSpan(span, 1, 3, Spannable.SPAN_EXCLUSIVE_INCLUSIVE); //在不同的EditText中显示 mEt1.setText(spanString); mEt2.setText(spanString2); mEt3.setText(spanString3); mEt4.setText(spanString4); }}然后分别在前后插入字符,效果如下
其他设置
上面的那颗栗子用到了设置颜色的类,但仅仅只能设置颜色,如何装逼?
//改变字体背景色的span BackgroundColorSpan colorSpan = new BackgroundColorSpan(Color.BLUE);
//改变字体大小的span,传入一个int 值 AbsoluteSizeSpan sizeSpan = new AbsoluteSizeSpan(16); //设置文字相对大小的span,传入一个float,以原有字体的大小为基础设置倍数 RelativeSizeSpan rSizeSpan = new RelativeSizeSpan(1.5f); //一些文本标志,以下划线为例 UnderlineSpan lineSpan = new UnderlineSpan();当然,除了这些,还有删除线(StrikethroughSpan) 文本样式(StyleSpan)等其他样式
上例的运行结果如图
介绍完样式使用,接下来隆重介绍两种更有逼格的用法
首先,试试在字段中加入一个超链接吧,代码如下
//超链接文本 SpannableString spanString6 = new SpannableString("天王盖地虎宝塔镇河妖"); URLSpan urlSpan = new URLSpan("http://www.baidu.com"); spanString6.setSpan(urlSpan,1, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); mTv1.setMovementMethod(LinkMovementMethod.getInstance()); mTv1.setHighlightColor(Color.BLUE); mTv1.setText(spanString6);运行效果:
点击后自动跳转页面,不用给TextView 添加监听事件,是不是很酷
你以为就这些功能?
前些天在倒腾聊天页面,要实现图片、文字的发送,文字用TextView 加到Item中即可,但是要在ListView 中显示图片就有些麻烦了。
我最开始的思路是在一个布局里同时存放ImageView 和TextView ,然后根据类型进行判断,将其设置为VISILIABLE 和GONE
但是这种方法使得适配器的代码过于冗长,而且findViewById 的开销有比较大,这才想到了也许可以用SpannableString来结局这个问题
废话少说,上代码
SpannableString spanString7 = new SpannableString("天王盖地虎宝塔镇河妖"); Drawable drawable = getResources().getDrawable(R.drawable.ic_launcher); //设置图片大小 drawable.setBounds(0, 0, 66, 66); ImageSpan imageSpan = new ImageSpan(drawable); spanString7.setSpan(imageSpan, 0, spanString7.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); mTv2.setText(spanString7);
上述所有的例子显示都如下图所示,顺便提一下聊天界面中Item 的思路,将接收到的图片保存至本地后将url保存到List中,首先判断数据的类型,如果是为图片,则直接将TextView 设置成该地址所对应的图片,将其显示出来,怎么样,是不是又方便又有逼格?