1、简介
本篇博客用来记录在日常的开发中TextView的诸多使用技巧,用以日后再次遇到后更加熟练的进行使用。
2、TextView技巧使用明细
2.1 TextView 带图标显示
a. 很常见的如: android:drawableLeft = " ",即实现右边是文字左边的是图标的显示效果
b. setCompoundDrawables 的使用技巧
该API的功能就是设置Drawable在TextView控件的显示位置,可以在Java代码段很轻易的实现图标的切换和图标位置的变换。
以下为案例1 实现图标的切换:
public static void modifyTextViewDrawable(TextView v, Drawable drawable, int index) {
drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
//index 0:左 1:上 2:右 3:下
if (index == 0) {
v.setCompoundDrawables(drawable, null, null, null);
} else if (index == 1) {
v.setCompoundDrawables(null, drawable, null, null);
} else if (index == 2) {
v.setCompoundDrawables(null, null, drawable, null);
} else {
v.setCompoundDrawables(null, null, null, drawable);
}
}
解释: drawable.setBounds( )设置drawable将绘制在矩形的那个区域内,绘制点为该canvas的左上角
案例2其实差不多,贴出来
Drawable drawableLeft = UIUtils.getDrawable(context, ResourceProvider.getIconId(item.weatherStatus));
drawableLeft.setBounds(0, 0, UIUtils.dipToPx(context, R.dimen.common_dimension_16),
UIUtils.dipToPx(context, R.dimen.common_dimension_16));
mTv_status.setCompoundDrawables(drawableLeft,null,null,null);
mTv_status.setText(item.weatherStatus);
这里是没封装的,可以自由调整你所插入的图标的大小,这些都是OK的。
2.2 TextView字体显示和选中事件
SpannableStringBuilder 本小节的重点
解释: 这是一个内容和标记都可以更改的文本类。
SpannableStringBuilder 和 SpannableString通过 setSpan( )来改变文本样式。其方法如下:
public void setSpan(Object what, int start, int end, int flags) {
super.setSpan(what, start, end, flags);
}
flag 取值:
Spannable.SPAN_EXCLUSIVE_INCLUSIVE
:在 Span前面输入的字符不应用 Span的效果,在后面输入的字符应用Span效果。Spannable.SPAN_INCLUSIVE_EXCLUSIVE
:在 Span前面输入的字符应用 Span 的效果,在后面输入的字符不应用Span效果。Spannable.SPAN_INCUJSIVE_INCLUSIVE
:在 Span前后输入的字符都应用 Span 的效果。Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
:前后都不包括。
what: 对应的各种Span,不同的Span对应不同的样式。实现不同的文字样式的重点就是在这里哦。已知的可用类有:
BackgroundColorSpan
: 文本背景色ForegroundColorSpan
: 文本颜色MaskFilterSpan
: 修饰效果,如模糊(BlurMaskFilter)浮雕RasterizerSpan
: 光栅效果StrikethroughSpan
: 删除线SuggestionSpan
: 相当于占位符UnderlineSpan
: 下划线AbsoluteSizeSpan
: 文本字体(绝对大小)DynamicDrawableSpan
: 设置图片,基于文本基线或底部对齐。ImageSpan
: 图片RelativeSizeSpan
: 相对大小(文本字体)ScaleXSpan
: 基于x轴缩放StyleSpan
: 字体样式:粗体、斜体等SubscriptSpan
: 下标(数学公式会用到)SuperscriptSpan
: 上标(数学公式会用到)TextAppearanceSpan
: 文本外貌(包括字体、大小、样式和颜色)TypefaceSpan
: 文本字体URLSpan
: 文本超链接ClickableSpan
: 点击事件
案例1. 打印出美元符号并且字体颜色和后面不一致
/**
* @author zxl on 2018/8/15.
* discription: CharacterStyle是字体的基类,后面像
* 什么点击事件,背景啊 啥的都继承自该基类
*/
public class SpannableBg extends CharacterStyle {
/**
* 更新绘制的状态
* 可以添加颜色下划线之列
* @param ds
*/
@Override
public void updateDrawState(TextPaint ds) {
ds.setColor(Color.parseColor("#ff0000"));
// 这里的尺寸是 px 后面这里需要转换的
ds.setTextSize(38);
// 是否添加下划线
ds.setUnderlineText(false);
ds.clearShadowLayer();
}
}
SpannableString dollars = new SpannableString("$6000");
dollars.setSpan(new SpannableBg(),
0,
1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mTvColor.setText(dollars);
案例2: 带删除线的
private void setSpannableStyle() {
SpannableString dollars = new SpannableString("$6000");
dollars.setSpan(new SpannableBg(),
0,
1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
dollars.setSpan(new StrikethroughSpan(),1,dollars.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mTvColor.setText(dollars);
}
案例3: 点击事件( 这个有点难度的)
public interface ISpanClick {
void onClick(int position);
}
public class NameClickListener implements ISpanClick {
private String name;
public NameClickListener(String name) {
this.name = name;
}
@Override
public void onClick(int position) {
Log.e("数据","第几个: "+position+" "+name);
}
}
public class TextClickSpan extends ClickableSpan {
private ISpanClick mISpanClick;
private int mPosition;
public TextClickSpan(ISpanClick ISpanClick, int posiotion) {
mISpanClick = ISpanClick;
mPosition = posiotion;
}
@Override
public void onClick(View widget) {
mISpanClick.onClick(mPosition);
}
@Override
public void updateDrawState(TextPaint ds) {
// 这里继承的话 那么会重叠之前你的属性,所以在这
// 里不做操作
}
}
private void setSpannableStyle() {
SpannableString dollars = new SpannableString("$6000");
dollars.setSpan(new SpannableBg(),
0,
1,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
dollars.setSpan(new StrikethroughSpan(),1,dollars.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mTvColor.setText(dollars);
dollars.setSpan(new TextClickSpan(new NameClickListener(
"我牛逼"), 0),
1,dollars.length()
,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mTvColor.setText(dollars);
/* 这句话才是重点吖,不加根本没法点击 背景是这个LinkMovementMethod在起作用*/
mTvColor.setMovementMethod(LinkMovementMethod.getInstance());
}
// mydairytestproject E/数据: 第几个: 0 我牛逼
运行结果如下,但是不好的是,点击了之后那么一直高亮显示,这个就应该是LinkMovementMethod的弊端吧,故而有必要去重写一个MovementMethod。来达到特定的效果。
案例3究极版,自定义了事件传递
mTvColor.setMovementMethod(new CircleMovementMethod(R.color.transparent));
public class CircleMovementMethod extends BaseMovementMethod {
/**
* 默认颜色
*/
public final static int DEFAULT_COLOR = R.color.transparent;
/**
* 文本背景颜色
*/
private int mTextViewBgColorId ;
/**
* 图片背景颜色
*/
private int mClickableSpanBgClorId;
/**
* 背景颜色深的Span类
*/
private BackgroundColorSpan mBgSpan;
/**
* 点击的数组
*/
private ClickableSpan[] mClickLinks;
/**
* 响应时间 ----- 是响应Textd的还是响应内部的
*/
private boolean isPassToTv = true;
/**
* true:响应textview的点击事件, false:响应设置的clickableSpan事件
*/
public boolean isPassToTv() {
return isPassToTv;
}
private void setPassToTv(boolean isPassToTv){
this.isPassToTv = isPassToTv;
}
public CircleMovementMethod(){
mTextViewBgColorId = DEFAULT_COLOR;
mClickableSpanBgClorId = DEFAULT_COLOR;
}
public CircleMovementMethod(int clickableSpanBgClorId){
mClickableSpanBgClorId = clickableSpanBgClorId;
mTextViewBgColorId = DEFAULT_COLOR;
}
public CircleMovementMethod(int clickableSpanBgClorId, int textViewBgColorId){
mClickableSpanBgClorId = clickableSpanBgClorId;
mTextViewBgColorId = textViewBgColorId;
}
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer,
MotionEvent event) {
int action = event.getAction();
if(action == MotionEvent.ACTION_DOWN){
// 获得触摸点距离该控件左上角的坐标
int x = (int) event.getX();
int y = (int) event.getY();
// 减去Padding值
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
// 加上控件滑动的值
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
mClickLinks = buffer.getSpans(off, off, ClickableSpan.class);
if(mClickLinks.length > 0){
// 点击的是Span区域,不要把点击事件传递
setPassToTv(false);
Selection.setSelection(buffer,
buffer.getSpanStart(mClickLinks[0]),
buffer.getSpanEnd(mClickLinks[0]));
//设置点击区域的背景色
mBgSpan = new BackgroundColorSpan(UiUtils.getColor(mClickableSpanBgClorId));
buffer.setSpan(mBgSpan,
buffer.getSpanStart(mClickLinks[0]),
buffer.getSpanEnd(mClickLinks[0]),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}else{
setPassToTv(true);
// textview选中效果
widget.setBackgroundResource(mTextViewBgColorId);
}
}else if(action == MotionEvent.ACTION_UP){
if(mClickLinks.length > 0){
mClickLinks[0].onClick(widget);
if(mBgSpan != null){
buffer.removeSpan(mBgSpan);
}
}else{
if(mBgSpan != null){
buffer.removeSpan(mBgSpan);
}
}
Selection.removeSelection(buffer);
widget.setBackgroundResource(DEFAULT_COLOR);
}else if(action == MotionEvent.ACTION_MOVE){
}else{
if(mBgSpan != null){
buffer.removeSpan(mBgSpan);
}
widget.setBackgroundResource(DEFAULT_COLOR);
}
return Touch.onTouchEvent(widget, buffer, event);
}
}
这篇文章可以学习下:【Android】强大的SpannableStringBuilder
2.3 TextView行间距
通常显示大幅文本的时候,设置行间距也是有必要熟练运用的,下面就整理下行间距的设置。这里和word 是一样的,也是有设置在原有1倍行距的基础上增加固定值行距和设置行距的倍数。
android:lineSpacingExtra: 设置额外的行距
android:lineSpacingMultiplier: 设置 x倍行距