Android 利用Shader墨盒原理渐隐效果

原创
2022/08/20 18:45
阅读数 339

一、需求

弹幕进入时由透明,进入一定区域后变成透明,退出时由不透明变成透明。

看过自定义LoopView源码的都知道,在View上下两侧使用了遮罩(Mask)的去实现划出区域的item隐藏,但是在某些场景下,这种实现由天然的弊端,如果View下方播放视频,由于明亮度不同,会出现明显的反差。

 

二、利用Shader中的Gradient实现

2.1 在使用Gradient之前,我们需要了解Shader是什么?

Shader翻译成中文是"着色器“,很多人对其陌生又熟悉,主要原因没有很好的解释他是如何着色的,工作原理如何?这里我们来总结一下。

  • Shader属于Paint的属性,用于为paint 着色
  • Paint的Color和Shader会取交集,完成着色 
  • Paint 所绘制的图像和Shader形成交集,优先按照Shader的颜色和透明度着色,不产生交集的部分以Color为主

我们可以把Paint Color染色过的图形想象成“凸版印刷板”,上面已经雕刻出了凸版文字,把Shader想象成一个矩形墨盒,魔盒中是具备颜色排列,如线性、放射

     =     Android绘制小糊涂     +     

当然,Shader具备又自己的起点、终点和方向。

 

2.2 Shader 起点与终点

Shader具备起点和终点,和绘制图像时需要文字一样,作为“凸版印刷墨盒” ,可以在墨盒的任意位置开始和结束,不在于Paint绘制几次。

对于弹幕而言,一行出现三句甚至更多弹幕的时候,只需要理解“文字”在墨盒水平和垂直方向的位置对应,进而给文字染色。

举例:

使用同一个Paint,按照三等分平分View,依次从每个等分区域中心绘制A、B、C三个字母(这种情况下我们一般至少drawText三次),另外Shader按照LinearGradient以三等分区域形成出红、绿、蓝墨盒,那么最终结果将是 A被染成红色、B被染成绿色、C被染成蓝色。

 

效果参考全民K歌TV版本的打分条

2.3 Color和Shader

  • 图像和Shader墨盒产生交集,才会对图像染色,如果文字不再染色的区域,那么将以paint Color的形式展示文字,不产生交集的部分以Color为主颜色展示。
  • Shader染色,不在于是否一次绘制和多次绘制,只要和墨盒产生交集,便会染色。
  • 如果有透明度相关的染色,Shader透明度区域需要谨慎使用亮色,Shader亮色可能会叠加,如0x00FFFFFF和0x00000000相比,前者容易出现叠加问题,什么原因暂时未知 
    public boolean isLightColor(int color) {
            double darkness = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255;
            if (darkness < 0.5) {
                return true; // It's a light color
            } else {
                return false; // It's a dark color
            }
        }

 

四、弹幕需求实现

利用Gradient实现,效果如下

代码实现

1、TextView实现两端文字渐隐

   LinearGradient gradient = new LinearGradient(0,0,testTv.getWidth(),0,new int[]{
                        0x66000000,
                        0xff000000,
                        0xff000000,
                        0x66000000
                },new float[]{
                        0.0f,
                        0.2f,
                        0.8f,
                        0.85f

                }, Shader.TileMode.CLAMP);
                testTv.setText("12345678901234567890123456789012345678901234567890");
                testTv.getPaint().setShader(gradient);
                testTv.invalidate();

2、实现底部线条渐渐隐藏

public class GradientView  extends View {

    Paint paint;
    private LinearGradient mGradient;

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

    public GradientView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public GradientView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.BLACK);
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeWidth(20);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if(mGradient==null) {
            mGradient = new LinearGradient(100, 0, getWidth()-100, 0, new int[]{
                    0x33000000,
                    0xff000000,
                    0xff000000,
                    0x33000000
            }, new float[]{
                    0.0f,
                    0.2f,
                    0.8f,
                    1f

            }, Shader.TileMode.CLAMP);
        }
        paint.setShader(mGradient);
        canvas.drawLine(100,20,getWidth()-100,20,paint);
    }
}

 

颜色叠加问题,下面使用白色透明,会产生叠加

private void setPaintLinearFadeGradient(Paint paint,int fadeWith,int fadeHeight) {
        if(paint==null) return;
        if(fadeWith<0 || fadeHeight<0){
            return;
        }
        Shader shader = paint.getShader();
        if(shader!=null) return;
        int color = paint.getColor();
        LinearGradient gradient = new LinearGradient(0,fadeHeight/2,fadeWith,fadeHeight/2,new int[]{
                0x00ffffff
                color,
                color,
                 0x00ffffff
        },new float[]{
                0.0f,
                0.15f,
                0.85f,
                1f
        }, Shader.TileMode.CLAMP);
        paint.setShader(gradient);

    }

 下面改为0x00000000黑色透明之后,不会叠加

private void setPaintLinearFadeGradient(Paint paint,int fadeWith,int fadeHeight) {
        if(paint==null) return;
        if(fadeWith<0 || fadeHeight<0){
            return;
        }
        Shader shader = paint.getShader();
        if(shader!=null) return;
        int color = paint.getColor();
        LinearGradient gradient = new LinearGradient(0,fadeHeight/2,fadeWith,fadeHeight/2,new int[]{
                Color.TRANSPARENT,
                color,
                color,
                Color.TRANSPARENT
        },new float[]{
                0.0f,
                0.15f,
                0.85f,
                1f
        }, Shader.TileMode.CLAMP);
        paint.setShader(gradient);

    }
展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部