06自定义View之文字绘制

Posted 清风百草

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了06自定义View之文字绘制相关的知识,希望对你有一定的参考价值。

(1)android绘制文字
(2)文字绘制之认知baseline
(3)文字绘制之测量
(4)文字绘制之渐变绘制
(5)画布裁剪
(6)属性动画
(7)过度绘制

【06】自定义View之文字绘制

文章目录

1.自定义View

(1)extends View

(2)extends ViewGroup

2.文字绘制

(1)绘制

  • extends AppCompatTextView
  • onMeasure():确定控件显示大小
  • onLayout():确定控件摆放位置
  • onDraw():显示什么

(2)画布:canvas
决定绘制什么形状

(3)画笔:paint
用来设置绘制风格

(4)绘制文字重中之重,它是以基准线为中心的。

2.1绘制文字

    /**
     * Draw the text, with origin at (x,y), using the specified paint. The origin is interpreted
     * based on the Align setting in the paint.
     *
     * @param text The text to be drawn
     * //x:表示轴起点
     * @param x The x-coordinate of the origin of the text being drawn
     * //y:表示baseline的值
     * @param y The y-coordinate of the baseline of the text being drawn
     * @param paint The paint used for the text (e.g. color, size, style)
     */
    public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) 
        super.drawText(text, x, y, paint);
    

(1)baseline是什么

  • 红色的线就是baseline,就是说大部分的文字都以这根线为基准对齐的线。
  • baseline,就是无论多少个文字,都能在水平线上确保文字基于这条线对齐
  • 可以超出基准线,文字往上往下都可以

2.1.1文字测量

Paint.FontMetrics

/**
     * Class that describes the various metrics for a font at a given text size.
     * Remember, Y values increase going down, so those values will be positive,
     * and values that measure distances going up will be negative. This class
     * is returned by getFontMetrics().
     */
    public static class FontMetrics 
        /**
        top:表示从baseline基准线到文字最顶端的尺寸
         * The maximum distance above the baseline for the tallest glyph in
         * the font at a given text size.
         */
        public float   top;
        /**
         * The recommended distance above the baseline for singled spaced text.
         */
        public float   ascent;
        /**
         * The recommended distance below the baseline for singled spaced text.
         */
        public float   descent;
        /**
         * The maximum distance below the baseline for the lowest glyph in
         * the font at a given text size.
         */
        public float   bottom;
        /**
         * The recommended additional space to add between lines of text.
         */
        public float   leading;
    

top:表示从baseline基准线到文字最顶端的尺寸
bottom:表示从baseline基准线到文字最底端的尺寸
ascent:表示从baseline到大部分文字最顶端的尺寸。
descent:表示从baseline到大部分文字最底端的尺寸。

top/bottom:无论什么文字,不会超出上界下界。
ascent/descent:正常文字的上界与下界。

文字的高度= top+bottom

如果基准线baseline为0,

top的值往上走,Android值为负(-)
bottom的值往下走,Android值为正(+)

计算文字实际的高度应该是什么样子呢?

  • 文字最大的高度=bottom - top 。
  • 文字正常的高度=descent - ascent。

3.文字颜色渐变绘制

3.1屏幕显示与Canvas的关系

(1)屏幕画布是有很多层叠加到一起的。

(2)如何判断绘制的内容处在同一层级
一层
canvas.save();
…这里边儿的内容处在同一层级
canvas.restore();

一层
canvas.save();
…这里边儿的内容处在同一层级
canvas.restore();

    /**
     * 1.文字画到屏幕中心
     * (1)如何分层
     * canvas.save();
     * canvas.restore();
     * 处在以上代码中的内容,可以理解为它们处在同一个层次
     * 
     * @param canvas
     */
    private void drawCenterText(final Canvas canvas)
        canvas.save();
        Paint paint = new Paint();
        //单位是像素
        paint.setTextSize(80);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.RED);
        paint.setAntiAlias(true);

        /**
         *1.文字绘制在view的中心
         * (1)textAlign只能设置水平方向的,因此该需求不能使用这种方法
         * (2)需要计算文字的高度
         * (3)Paint.FontMetrics是用于文字测量的
         * (4)文字的正常高度:fontMetrics.descent - fontMetrics.ascent
         */
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();

        //确保居中
        //baseline =getHeight()/2+(fontMetrics.descent - fontMetrics.ascent)/2 - fontMetrics.descent;
        //划简的写法
        float baseline = getHeight()/2-(fontMetrics.descent + fontMetrics.ascent)/2;

        //x轴的居中
        paint.setTextAlign(Paint.Align.LEFT);
        float width = paint.measureText(mText);
        float x = getWidth()/2 - width/2;
        canvas.drawText(mText,x,baseline,paint);
        canvas.restore();
    

3.2绘制渐变

(1)文字本身是没办法只绘制一半的
(2)通过从左往右一点一点的裁剪。

3.2.1Canvas画布的剪裁

(1)clipRect函数是android.graphics.Canvas类下一个用于对画布进行矩形裁剪的方法。
(2)它裁剪了我们想要的绘制区域 , 有点类似ps里面的遮罩效果

    /**
     * 1.文字画到屏幕中心
     * (1)如何分层
     * canvas.save();
     * canvas.restore();
     * 处在以上代码中的内容,可以理解为它们处在同一个层次
     *
     * @param canvas
     */
    private void drawCenterText1(final Canvas canvas)
        canvas.save();
        Paint paint = new Paint();
        //单位是像素
        paint.setTextSize(80);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.BLACK);
        paint.setAntiAlias(true);

        /**
         *1.文字绘制在view的中心
         * (1)textAlign只能设置水平方向的,因此该需求不能使用这种方法
         * (2)需要计算文字的高度
         * (3)Paint.FontMetrics是用于文字测量的
         * (4)文字的正常高度:fontMetrics.descent - fontMetrics.ascent
         * 2.绘制渐变
         * (1)裁剪
         */
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();

        //确保居中
        //baseline =getHeight()/2+(fontMetrics.descent - fontMetrics.ascent)/2 - fontMetrics.descent;
        //划简的写法
        float baseline = getHeight()/2-(fontMetrics.descent + fontMetrics.ascent)/2;

        //x轴的居中
        paint.setTextAlign(Paint.Align.LEFT);
        float width = paint.measureText(mText);
        float left = getWidth()/2 - width/2;

        canvas.drawText(mText,left,baseline,paint);
        canvas.restore();
    
/**
     * 通过裁剪绘制遮罩层
     * @param canvas
     */
    private void drawCenterText2(final Canvas canvas)
        canvas.save();
        Paint paint = new Paint();
        paint.setTextSize(80);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.RED);
        paint.setAntiAlias(true);

        Paint.FontMetrics fontMetrics = paint.getFontMetrics();

        //确保居中
        //baseline =getHeight()/2+(fontMetrics.descent - fontMetrics.ascent)/2 - fontMetrics.descent;
        //划简的写法
        float baseline = getHeight()/2-(fontMetrics.descent + fontMetrics.ascent)/2;

        //x轴的居中
        paint.setTextAlign(Paint.Align.LEFT);
        float width = paint.measureText(mText);
        float left = getWidth()/2 - width/2;
        //裁剪的右边为
        float right = left + width*percent;

        /**
         * 裁剪:右边应该裁剪多少呢?
         *
         */
        Rect rect = new Rect((int)left,0,(int)right,getHeight());
        canvas.clipRect(rect);

        canvas.drawText(mText,left,baseline,paint);
        canvas.restore();
    
 private SimpleColorChangeTextView mView1;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_jrtt_main);
        mView1 = findViewById(R.id.tv_color_change_view);

        //播放属性动画
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() 
            @Override
            public void run() 
                onStartLeft(null);
            
        ,1000);
    

    /**
     * 属性动画
     * @param view
     */
    public void onStartLeft(View view)
        //属性动画,通过属性动画的方式改变自定义View中percent的值,是通过反射改变percent属性的值。
        ObjectAnimator.ofFloat(mView1,"percent",0,1).setDuration(2000).start();
    

3.3补充点

  • invalidate()方法调用时,会导致onDraw()方法重复调用

  • 在onDraw()中创建对象会导致GC,会导致内存抖动,最终导致卡顿,甚至崩溃。

  • 过度绘制

(1)同一个像素点,绘制了多次2次
真彩色:没有过度绘制
蓝色:过度绘制1次
绿色:过度绘制2次
粉色:过度绘制3次
红色:过度绘制4次或更多次

5.打赏鼓励

感谢您的细心阅读,您的鼓励是我写作的不竭动力!!!

5.1微信打赏

5.2支付宝打赏

以上是关于06自定义View之文字绘制的主要内容,如果未能解决你的问题,请参考以下文章

06自定义View之文字绘制

06自定义View之文字绘制

Android自定义view之view显示流程

自定义View_1_关于View,ViewGroup的测量和绘制流程

Android组件体系之视图绘制

转载自定义View学习笔记之详解onMeasure