文字绘制 – 滚动歌词效果

android中其实挺多功能需要渐变文字,图形效果的。
比如滚动歌词、今日头条tab滑动时,文字有一个渐变的过程

之前面试还被问过这个裁剪的波形图咋做。
image.png

今天做了这个滚动歌词,思路应该都差不多。

ABF100126C68DEDE38B400548D3F0EF3.gif

将文字居中显示

image.png

画辅助线

canvas.drawLine()是画线的方法

参数:顾名思义
image.png

没啥好说的
image.png

文字居中

canvas.drawText()是画文字的方法

看似没啥好说的,但是y点为啥叫baseline呢???
这里有个大坑,文字绘制不是根据文字的左下角而来的,是根据这个baseline来绘制的。

image.png

11.png

baseline

上图红线就是baseline,文字的绘制是根据baseline而来的,它保证大部分文字都是对齐的,就像拼音格子里的横线。
因为android坐标系是向下的,所以baseline往下是 +(正值),往上是 – (负值)

top与bottom

所有文字、符号的上下边界。top是负值,bottom是正值。原因是根据baseline为坐标系

ascent与desecnt

大部分文字的上下边界(排除特殊文字、符号,部分藏文、拉丁文等)。ascent是- (负值),desecnt是+(正值),因为是根据baseline为坐标系的

所以要居中应该是 (desecnt与ascent的差值/2) 即 (desecnt+ascent)/2
解释:文字高度: (desecnt – ascent) 直接除是不对的,因为绘制的时候还是要根据baseline的

这些文字的信息,在Paint.FontMetrics这个类

   /** 绘制中间的文字 */
    Paint paintText;
    private void drawText(final Canvas canvas){
        canvas.save();
        if (paintText == null){
            paintText = new Paint();
            paintText.setTextSize(100);
            paintText.setColor(Color.BLACK);
            paintText.setAntiAlias(true);
        }
        //想要绘制文字真正居中
        //宽直接屏幕/2 + Paint.Align.CENTER就行  或者 text的宽度的一半
        int xCenter = (int) (getWidth()/2 - paintText.measureText(text)/2);
        paintText.setTextAlign(Paint.Align.LEFT);

        //高得 减去 baseline的上下差值/2
        Paint.FontMetrics fontMetrics = paintText.getFontMetrics();
        int yCenter = (int) (getHeight()/2 - (fontMetrics.ascent + fontMetrics.descent)/2);
        canvas.drawText(text,xCenter,yCenter,paintText);
        canvas.restore();
    }
复制代码

绘制裁剪渐变色的文字

canvas.save(),canvas.restore() 这两是成对出现的,不然restore()如果没有save的话会报错。
他两用来保存、恢复。
可以想象成PS的图层,一组就是一个图层。

canvas.clipRect(rect);裁剪,可以裁剪画布,可以想象成PS的裁剪

思路:

下面用黑色的文字绘制一层,上面一层图层绘制彩色的文字,然后裁剪上面的图层,只显示需要展示的百分比的图像。

  /** 绘制裁剪红色的文字 */
    Paint paintText1;
    private void drawText1(final Canvas canvas){
        canvas.save();
        int withText = (int) paintText.measureText(text);
        int xCenter = (int) (getWidth()/2 - withText/2);

        if (paintText1 == null){
            paintText1 = new Paint();
            paintText1.setTextSize(100);
            paintText1.setTextAlign(Paint.Align.LEFT);
            
            //设置渐变色
            int [] colors = {Color.RED,Color.GREEN, Color.BLUE};
            float[] position = {0f, 0.7f, 1.0f};
            LinearGradient linearGradient = new LinearGradient(xCenter,0,xCenter+withText,0,colors,position, Shader.TileMode.CLAMP);
            //设置着色器
            paintText1.setShader(linearGradient);

            paintText1.setAntiAlias(true);
        }

        Paint.FontMetrics fontMetrics = paintText1.getFontMetrics();
        int yCenter = (int) (getHeight()/2 - (fontMetrics.ascent + fontMetrics.descent)/2);
        
        //裁剪需要显示的部分  percentage是百分比,activity里传入float 0.0 - 1.0
        Rect rect = new Rect(xCenter,0, (int) (xCenter + percentage * withText),getHeight());
        canvas.clipRect(rect);
        canvas.drawText(text,xCenter,yCenter,paintText1);
        canvas.restore();
    }

复制代码

invalidate()重绘,draw()

每次传入不同百分比的时候,需要重绘

  public void changeColor(float percentage){
        this.percentage=percentage;
        invalidate();
    }
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享