Android UI之TextView常用技巧整理

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倍行距

2.5 自定义组合TextView

2.6 一些不错的关于TextViiew的框架 

猜你喜欢

转载自blog.csdn.net/crazyZhangxl/article/details/81672073
今日推荐