在Android经常看到这种效果:
你还在使用2个TextView来写吗?
那这种情况怎么使用TextView呢?
那就太out了,今天带大家重新认识一下TextView,并封装一下子!
先来看看今天的效果:
来看看gif图效果:
Spannable介绍
Spannable有2个实现类,分别是SpannableString和SpannableStringBuilder,关系如下图
SpannableString 和 SpannableStringBuilder 的区别:
他们的区别类似于String和StringBuilder
SpannableString 和 SpannableStringBuilder使用类似,本篇使用SpannableString
SpannableString的方法:
| SpannableString参数 | 返回值 | 说明 |
|---|---|---|
| charAt(int) | char | 返回指定索引处的char值。 |
| getSpanEnd(Object ) | int | 返回结尾数据,如果无数据则返回-1。 |
| getSpanFlags(Object ) | int | 返回在使用Spannable#setSpan附加指定标记对象时指定的标志,如果尚未附加指定对象,则返回0。 |
| getSpanStart(Object ) | int | 返回文本开头,如果无数据,则返回-1。 |
| removeSpan(Object ) | void | 删除指定位置 |
| setSpan(Object,int,int,int) | void | 将指定的标记对象附加到文本的开始…结束区域,或者如果对象已附加到其他位置,则将其移动到该区域。 |
这里主要使用的是setSpan()方法 参考官方文档
说了这么多理论,现在开始来实践一下吧~
SpannableString简单实用
文字和加载本地图片:
先来看看代码:
这里主要采用的是ImageSpan(),然后通过SpannableString.setSpan()方法设置给TextView
这里在解释一下setSpan()的参数
- 参数一:Object
- 参数二:SpannableString的占位开始位置(这里占位的值<image>的位置)
- 参数三:SpannableString的占位结束位置
- 参数四:图片的位置 (我没看出有什么效果)
更多样式:
文字和加载网络图片:
加载网络图片我采用的是Glide
思路:首先加载一个本地图片,然后等Glide加载好图片之后,通过Glide获取到Drawable然后通过removeSpan()方法将本地图片删除掉,最后通过setSpan()方法将Glide获取到的Drawable设置给TextView即可
来看看代码:
private fun buildImage(url: String, width: Int, height: Int) {
val ss = SpannableStringBuilder(url)
val drawable = getDrawableData()
//设置Drawable图片宽高
drawable.setBounds(5, 5, width, height)
//占位符
val placeholderSpan = ImageSpan(drawable)
ss.setSpan(placeholderSpan, 0, url.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
//添加数据(先占好位置,然后等图片加载出来在删除掉,最后在设置网络图片)
textView.append(ss)
//获取到Text的Spannable
val spannable = textView.text as Spannable
//Glide加载网络图片,获取到Drawable
Glide.with(this)
.asDrawable()
.load(url)
.into(object : SimpleTarget<Drawable>() {
override fun onResourceReady(
resource: Drawable,
transition: Transition<in Drawable>?,
) {
//获取到开始位置
val start = spannable.getSpanStart(placeholderSpan)
//获取到结束位置
val end = spannable.getSpanEnd(placeholderSpan)
//当前图片宽高不为-1
if (start != -1 && end != -1) {
//设置图片宽高
resource.setBounds(0, 0, width, height)
//删除占位符,然后重新设置网络图片
spannable.removeSpan(placeholderSpan)
//设置网络图片
spannable.setSpan(ImageSpan(resource),
start,
end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
})
}
注释很清晰,不懂得记得在评论区留言哦!
通过写这么多代码,发现很多代码都是重复的,而且属性需要一个一个设置,特别麻烦,用起来也不方便,那么接下来咋们就给他封装一下.
通过观察发现,建造者模式非常适合,那就采用建造者模式吧~
建造者模式封装
拿最常用的来举例,剩下的自己下载Demo看哦~
定义建造者模式规范:
public interface RichBuilder {
RichBuilder addText(String msg);//添加文字
RichBuilder setOnClick(RichTextView.onItemClick onClick);//点击事件
RichBuilder build();//确定
}
实现RichBuilder规范:
public class RichTextView extends androidx.appcompat.widget.AppCompatTextView
implements RichBuilder {
//必要构造器
public RichTextView(@NonNull Context context) {
super(context, null);
}
public RichTextView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs, 0);
}
public RichTextView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private final ArrayList<Object> objList = new ArrayList<>();
String text = "text";
@Override
public RichBuilder addText(String msg) {
text = msg;
return this;
}
//点击事件
@Override
public RichBuilder setOnClick(onItemClick onClick) {
objList.add(new ClickableSpan() {
@Override
public void onClick(View widget) {
//接口回调
onClick.click();
}
});
//设置为可点击状态
setMovementMethod(LinkMovementMethod.getInstance());
return this;
}
@Override
public RichBuilder build() {
SpannableString ss = new SpannableString(text);
for (Object o : objList) {
ss.setSpan(o, 0, text.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
append(ss);
//一定要清空objList哦
objList.clear();
return this;
}
//点击事件回调
public interface onItemClick {
void click();
}
}
使用:
richText
.addText("100")
.setOnClick {
toast("点击了100哦")
}
.build()
.addText(" m\n\n")
.build()
.addText("我是构建者模式的数据")
.setOnClick {
toast("我是构建者模式的数据")
}
.build()
效果图:
数学公式
在来看看数学公式是怎么使用的吧:
tvFormula
.addText("(X")
.build()
.addText("1")
.setSubscript() //设置下标
.setSubscriptSize(30) //角标大小
.build()
.addText("+ ")
.build()
.addText("2")
.setSuperscript() //设置上标
.setSubscriptSize(30)
.build()
.addText(")")
.build()
最终结果为:
剩下的下载Demo看吧~
猜你喜欢:
原创不易,您的点赞就是对我最大的支持!