美文网首页自定义控件
Android自定义view入门-自定义Textview

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

作者: 临窗听雨 | 来源:发表于2017-05-27 17:31 被阅读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

    相关文章

      网友评论

        本文标题:Android自定义view入门-自定义Textview

        本文链接:https://www.haomeiwen.com/subject/txiqfxtx.html