自定义控件

Android自定义view入门-自定义Textview

2017-05-27  本文已影响229人  临窗听雨

一、概述
以前在项目当中很多效果要实现,首先想到的就是去网上找,想自己写又不太懂原理,网上看了几篇文章或者专题都是专门分析源码或者讲解方法的,没有结合项目,对知识是学了又忘。跟着Darren大神学了下,感觉不错。他山之石,可以攻玉。现在记录学习的过程,理清下思路,顺便也可以方便别人。今天要讲的是自己绘制TextView熟悉下自定义view一般的操作流程。
二、效果图

截图.PNG

三、思路分析
3.1写自定义属性,attrs文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="TextView">
        <attr name="lctyText" format="string"></attr>
        <attr name="lctyColor" format="color"></attr>
        <attr name="lctySize" format="dimension"></attr>
    </declare-styleable>
</resources>

name表示属性名,format表示属性格式,这里自定义了三个属性,文本内容,文本颜色,文本尺寸。

3.2写自定义TextView,继承自view,在构造函数中拿出属性,初始化画笔

 private int mTextSize = 15;
    private int mTextColor = Color.BLACK;
    private String mText; //文本
    Paint mPaint;

    public TextView(Context context) {
        this(context,null);
    }

    public TextView(Context context, AttributeSet attrs) {
        this(context,attrs,0);
    }

    //构造函数里拿到自定义属性 初始化画笔
    public TextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.TextView);
        mText = a.getString(R.styleable.TextView_lctyText);
        mTextColor = a.getColor(R.styleable.TextView_lctyColor,mTextColor);
        mTextSize = a.getDimensionPixelSize(R.styleable.TextView_lctySize,sp2px(mTextSize));
        a.recycle();
        mPaint = new Paint();
        //抗锯齿
        mPaint.setAntiAlias(true);
        //文字大小
        mPaint.setTextSize(mTextSize);
        //文字颜色
        mPaint.setColor(mTextColor);
    }

    //sp单位转为px
    private int sp2px(int size) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,size,getResources().getDisplayMetrics());
    }

3.3复写onMeasure方法,获取测绘模式,进行判断,计算宽高。

//onMeasure方法测绘 设置宽高
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //得到测量模式
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        //得到宽高的值
        int height = MeasureSpec.getSize(heightMeasureSpec);

        int width = MeasureSpec.getSize(widthMeasureSpec);

        //判断测量模式
        //如果mode是EXACTLY(match_parent 100dp) 不用管 直接用户是设置多少就是多少
        //如果mode是AT_MOST(wrap_content) 要判断设置宽高
        if (widthMode == MeasureSpec.AT_MOST){
            //用画笔测量文字的宽高 由字体大小和宽高决定
            Rect bunds = new Rect();
            //得到文字的矩形区域
            mPaint.getTextBounds(mText,0,mText.length(),bunds);
            width = getPaddingRight()+ getPaddingLeft() + bunds.width(); //左右间距加上文本宽度
        }

        if (heightMode == MeasureSpec.AT_MOST){
            //用画笔测量文字的宽高 由字体大小和宽高决定
            Rect bunds = new Rect();
            //得到文字的矩形区域
            mPaint.getTextBounds(mText,0,mText.length(),bunds);
            height = getPaddingBottom()+getPaddingTop()+bunds.height(); //上下间距加上文本高度
        }
        //设置宽高
        setMeasuredDimension(width,height);
    }

3.4在ondraw()方法中调用画笔的drawText方法进行绘制

 //onDraw()方法进行文字绘制
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint)
        /*  The text to be drawn 要绘制的文字
         *   The x-coordinate of the origin of the text being drawn 绘制的起始点
         *    The y-coordinate of the baseline of the text being drawn 绘制的基线
         *    The paint used for the text (e.g. color, size, style) 画笔
         *    dy是整个文字的高度的一般和基线之间的增量
         */
        Paint.FontMetricsInt metricsInt =  mPaint.getFontMetricsInt();
        int dy = (metricsInt.bottom - metricsInt.top)/2 - metricsInt.bottom;
        int baseline = getHeight()/2 + dy;
        canvas.drawText(mText,getPaddingLeft(),baseline,mPaint);
    }

四、FontMetrics的理解
Paint.FontMetrics和Paint.FontMetricsInt这两个方法是一样的,只是后者取到的值是一个整形。
top:最高字符到baseline的距离,即ascent的最大值 ascent:字符最高处的距离到baseline的值 descent:下划线到字符最低处的距离 bottom:下划线到最低字符的距离,即descent的最大值 leading:上一行字符的descent到下一行的ascent之间的距离
可以对照着这个图理解:

捕获.PNG

那么baseLine的计算应该就是,整行字符的高度+增量y,增量的计算公式为:

y=(metricsInt.bottom - metricsInt.top)/2 - metricsInt.bottom

分析完毕,源码地址:http://pan.baidu.com/s/1nuRJYI1

上一篇下一篇

猜你喜欢

热点阅读