Android开发自定义控件

自定义View-第十七步:水波效果RadialGradient

2017-02-17  本文已影响74人  crossroads

前言

根据启舰大大 的博客所学习的自定义View。

一、RadialGradient详解

RadialGradient的意思是放射渐变,即它会向一个放射源一样,从一个点开始向外从一个颜色渐变成另一种颜色;

//两色渐变
RadialGradient(float centerX, float centerY, float radius, int centerColor, int edgeColor, Shader.TileMode tileMode)
//多色渐变
RadialGradient(float centerX, float centerY, float radius, int[] colors, float[] stops, Shader.TileMode tileMode)

二、小试牛刀

        //多色渐变
        int[]   colors = new int[]{0xffff0000,0xff00ff00,0xff0000ff,0xffffff00};
        float[] stops  = new float[]{0f,0.4f,0.6f,1f};

        paint.setShader(new RadialGradient(100,100,50,colors,stops, Shader.TileMode.CLAMP));
        canvas.drawCircle(100,100,100,paint);

        //双色渐变
        paint.setShader(new RadialGradient(300,300,50,0xffff0000, 0xff0000ff,Shader.TileMode.MIRROR));
        canvas.drawCircle(300,300,150,paint);
效果图

ps:看着第二个镜像是不是有点晕呢?嘿嘿,我也晕了,其实是由红变蓝,再由蓝变红,再由红变蓝......这样子继续下去,白色的那条线就是每一圈渐变的边界,(⊙o⊙)…有点不清晰,大家可以自己画个大大的圆试试

三、水波纹效果

先看效果图吧

水波纹效果

源码如下:

public class MineView extends View {
    private Paint paint;
    float radius;
    ValueAnimator animator;
    int width; //控件的宽度
    int x, y; //当前触摸点的位置

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

    public MineView(Context context, AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
       //在这可以获取控件宽度,不要在初始化的时候获取,那时候是获取不到的
        width = getMeasuredWidth();
        animator = ValueAnimator.ofInt(50, width);
        animator.setDuration(1000);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                radius = (int) animation.getAnimatedValue();
                updateShader();
            }
        });

        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                radius = 0;
                updateShader();
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        setLayerType(LAYER_TYPE_SOFTWARE, null);//对单独的View在运行时阶段禁用硬件加速
        canvas.drawColor(Color.LTGRAY);
        canvas.drawCircle(x, y, radius, paint);
    }

    private void updateShader() {
        if (x > 0 && y > 0 && radius > 0) {
            //从零透明度逐渐变为绿色
            RadialGradient radialGradient = new RadialGradient(x, y, radius, 0x00FFFFFF, 0xFF00FF00, Shader.TileMode.CLAMP);
            paint.setShader(radialGradient);
        }
        postInvalidate();
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (x != event.getX() || y != event.getY()) {
            x = (int) event.getX();
            y = (int) event.getY();
            radius = 50;
            updateShader();
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                return true;
            case MotionEvent.ACTION_UP:
                if (animator != null) {
                    if (animator.isRunning()) animator.cancel();
                    animator.start();
                }
                break;
        }
        return super.onTouchEvent(event);
    }
}

小知识

getMeasureWidth()方法在measure()过程结束后就可以获取到了,
而getWidth()方法要在layout()过程结束后才能获取到

上一篇下一篇

猜你喜欢

热点阅读