zoukankan      html  css  js  c++  java
  • Shader渲染动画

    一、概述

    先看一下Shader类的介绍:

    /**
     * Shader is the based class for objects that return horizontal spans of colors during drawing. 
    * A subclass of Shader is installed in a Paint calling paint.setShader(shader).
    * After that any object (other than a bitmap) that is drawn with that paint will get its color(s) from the shader.
    */

    Shader起初是为Bitmap着色的,但其作用并不限于此,任何通过设置了Shader的Paint画出来的东西都会获得想要的颜色。换句话说,Paint是画笔,Shader就是颜料,Shader需要通过Paint才能起作用。设置Shader的过程就是调制颜料的过程,有了Shader的加持,Paint不再只是简单地画出“白纸黑字”,也能画出五彩缤纷的世界了。
    那么,我们究竟有哪些种类的颜料和涂抹方式呢?

    (1)Shader的子类

     Shader有如下5个子类:

    BitmapShader是图像渲染,LinearGradient是线性渲染,RadialGradient是放射渲染,SweepGradient是梯度渲染,ComposeShader是组合渲染。后面我们会简单介绍各个渲染的用法。

    (2)Shader的渲染方式

    每种渲染的构造方法都需要指定渲染方式Shader.TileMode,共有三种

        public enum TileMode {
            /**
             * 拉伸 replicate the edge color if the shader draws outside of its original bounds
             */
            CLAMP   (0),
            /**
             * 重复 repeat the shader's image horizontally and vertically
             */
            REPEAT  (1),
            /**
             * 镜像 repeat the shader's image horizontally and vertically, alternating mirror images so that adjacent images always seam
             */
            MIRROR  (2); 
        }

     

    二、LinearGradient应用实战

    下面以LinearGradient为例,介绍Shader的一般用法。先看构造函数:

    LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],TileMode tile)

    x0,y0:表示渐变的起点坐标 x1,y1:表示渐变的终点坐标 colors[]:传入多个颜色,产生更加丰富的渐变效果。 float[]:可以设置在不同的渲染阶段渲染不同的颜色 TileMode:和上面讲的完全一致,不赘述了。

    一般用法如下:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
          int[] mColors = {Color.RED,Color.GREEN,Color.BLUE,Color.YELLOW}; //从红色——绿色——蓝色——黄色线性过渡
          float[] loaction=new float[] {0.25F, 0.5F, 0.75F, 1.0F }; //指定过渡分割点
          LinearGradient linearGradient=new LinearGradient(0,0,1000,50,mColors,loaction,Shader.TileMode.REPEAT);
          paint.setShader(linearGradient);
          paint.setStyle(Paint.Style.FILL);
          paint.setStrokeWidth(10);
          canvas.drawRect(new RectF(10,10,1000,50),paint);
       }

    效果如下:

    通过上面的例子我们可以看到,Shader只是简单的静态渲染,本身不具有动画属性。然而实际开发中,我们习惯用动画的手法来不断改变渲染方式以达到动态渲染的效果。以下面效果图为例

    核心代码:

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            if (mViewWidth == 0) {
                mViewWidth = getMeasuredWidth();
                if (mViewWidth > 0) {
                    mPaint = getPaint();
                    //制作一个白色半透明——白色全透明——白色半透明线性渲染
                    mLinearGradient = new LinearGradient(-mViewWidth, 0, 0, 0, new int[]{0x33ffffff, 0xffffffff, 0x33ffffff}, new float[]{0, 0.5f, 1}, TileMode.CLAMP);
                    mPaint.setShader(mLinearGradient);
                    mGradientMatrix = new Matrix();
                }
            }
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //通过Matrix来不断改变shader位移并重绘,达到动画效果
            if (mAnimating && mGradientMatrix != null) {
                mTranslate += mViewWidth / 10;
                if (mTranslate > 2 * mViewWidth) {
                    mTranslate = -mViewWidth;
                }
                mGradientMatrix.setTranslate(mTranslate, 0);
                mLinearGradient.setLocalMatrix(mGradientMatrix);
                postInvalidateDelayed(60);
            }
        }

    Github源码:https://github.com/JiaxtHome/AnimDemo


    
    

     三、总结

    通过上面LinearGradient的例子,我们知道了如何利用Shader来做动画效果,其他子类也是类似的:每一个Shader都有自己的一个Matrix,通过这个Matrix可以对Shader作平移、缩放等操作,采用动画的方式连续修改这个Matrix并重绘就可以实现一些特殊的动画。不同的Shader可以实现不同形式的效果,加上对Shader颜色透明度等变量的控制,可以实现的动画也是丰富多彩的。学习一个动效,不如学会一种方法,学会了方法,就可以开发更多自己的原创动效,而不仅仅是抄袭模仿别人的。下面列举一些其他Shader子类实现的动画效果:

    (1)SweepGradient梯度渲染

    效果图:

    核心代码:

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //将背景设置成白色
            canvas.drawColor(Color.WHITE);
    
            int mWidth = canvas.getWidth();
            //制作一个从透明到蓝色的SweepGradient梯度渲染
            if(mSweepGradient == null){
                mSweepGradient = new SweepGradient(mWidth / 2, mWidth / 2, new int[]{Color.TRANSPARENT, Color.parseColor("#530000ff")}, null);
            }
    
            //使用Matrix旋转
            mSweepGradient.setLocalMatrix(matrix);
            matrix.setRotate(degree, mWidth / 2, mWidth / 2);
            degree+=2;
            if (degree > 360) {
                degree = 0;
            }
            postInvalidate();
        }

    (2)BitmapShader图像渲染

    BitmapShader一般用于做圆角图像的静态渲染,如:

    核心代码:

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
            mPaint.setShader(bitmapShader);
            int min = Math.min(bitmapWidth, bitmapHeight);
            //画圆形图
            canvas.drawCircle(bitmapWidth / 2, bitmapHeight / 2, min / 2, mPaint);
        }

    (3)RadialGradient放射渲染

     RadialGradient适合做类似水波纹的辐射扩散效果:

    RadialGradient

    核心代码:

        int radius = 5;
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //禁用硬件加速
            setLayerType(LAYER_TYPE_SOFTWARE, null);
            canvas.drawColor(Color.parseColor("#FFC9C9C9"));
            //制定从白色透明到深灰色辐射状渲染
            RadialGradient radialGradient = new RadialGradient(mViewWidth / 2, mViewHeight / 2, radius, 0x00FFFFFF, 0xFFABABAB, Shader.TileMode.CLAMP);
            mPaint.setShader(radialGradient);
            canvas.drawCircle(mViewWidth / 2, mViewHeight / 2, radius, mPaint);
            radius += 3;
            if (radius > mViewWidth / 3 * 2) {
                radius = 5;
            }
            postInvalidate();
        }

    (4)ComposeShader组合渲染

    ComposeShader是组合渲染,顾名思义,它是任意两个其他渲染的叠加,叠加方式可以采用Xfermode或者PorterDuff.Mode。我们看一下它的构造方法:

    ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode)
    ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode)

    对于ComposeShader而言,不管是采用哪种混合模式都应慎用,达到的效果不太好控制,这里不再举例。

  • 相关阅读:
    Java语言
    Java面向对象编程思想
    final关键字
    abstract关键字
    对象初始化过程
    访问修饰符
    继承
    面向对象设计
    static
    封装
  • 原文地址:https://www.cnblogs.com/not2/p/10881962.html
Copyright © 2011-2022 走看看