码迷,mamicode.com
首页 > 其他好文 > 详细

RippleEffect原理解析

时间:2015-02-24 00:48:32      阅读:209      评论:0      收藏:0      [点我收藏+]

标签:demo   android开发   开源   

闲来无事,看了看RippleEffect的具体实现过程,先将心得写下,与诸位共享…

RippleEffect的效果就是点击View,然后View上一个圆圈慢慢的变大,然后消失…

原效果:
技术分享

我的Demo效果:
技术分享

原理:重写View的onDraw(Canvas canvas)方法,然后使用canvas.drawCircle(x, y, currentRadius, paint),通过不断的改变currentRadius的值,使其从小到大的变化,来达到这么一种效果。

(1)定义变量:

/**
 * 圆从最小到最大,需要多长时间
 */
private int DURATION = 2000;
/**
 * 想要画的圆的最大半径
 */
private float radiusMax = 0;
/**
 * View的最大宽度
 */
private int WIDTH;
/**
 * View的最大高度
 */
private int HEIGHT;
/**
 * 记录手指点下去的x坐标
 */
private float x;
/**
 * 记录手指点下去的y坐标
 */
private float y;
/**
 * 对timer的放大系数
 */
private int FRAME_RATE = 10;
/**
 * 通过timer不停的timer++,达到让圆不断增大的效果
 */
private int timer = 0;
/**
 * Handler用来更新界面用的
 */
private Handler canvasHandler;
/**
 * 是否正在播放动画
 */
private boolean animationRunning = false;
/**
 * 画笔
 */
private Paint paint;
/**
 * 结合Handler用来刷新当前界面的任务
 */
private final Runnable runnable = new Runnable() {
    @Override
    public void run() {
        invalidate();
    }
};

(2)重写 protected void onSizeChanged(int w, int h, int oldw, int oldh) 得到我们View的高度和宽度。

@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        Log.d("K", "onSizeChanged,w:" + w + ", h: " + h);

        WIDTH = w;
        HEIGHT = h;
    }

(3)在构造函数中,我们需要初始化我们的画笔,用来刷新界面的Handler。

    /**
     * 初始化画笔,Handler
     * @param context
     */
    private void init(Context context){
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(getResources().getColor(android.R.color.white));
        canvasHandler = new Handler();
    }

(4)想象一下,我们用手点击View的时候,点击的位置出现一个逐渐放大的圆,那么我们肯定就需要重写 public boolean onTouchEvent(MotionEvent event) 方法,然后记录下我们点击的(x, y)坐标,然后以这个(x, y)位置为圆心,以适当半径画一个圆就OK。

(4-1)重写onTouchEvent(MotionEvent event) 方法,响应用户触屏事件。

@Override
public boolean onTouchEvent(MotionEvent event) {
    animateRipple(event);
    return super.onTouchEvent(event);
}

(4-2)编写 animateRipple 函数,在没有播放动画的时候,播放动画,即画圆。

/**
 * 开始画圆
 * @param event
 */
public void animateRipple(MotionEvent event){
    //当前没有播放动画的时候,执行这些赋值操作
    if(!animationRunning){
        radiusMax = Math.max(WIDTH, HEIGHT);
        Log.d("K","radius:" + radiusMax);
        this.x = event.getX();
        this.y = event.getY();
        animationRunning = true;
        invalidate();
    }
}

这个函数最主要的作用,就是设置 animationRunning 这个变量,用以标示当前是否正在播放动画。然后确定了我们当前想要画的圆的最大半径是手机宽度和高度的最大值。

(4-3)接下来就得编写我们最核心的函数onDraw(Canvas canvas) 了,

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

    if(animationRunning){
        if(DURATION <= timer * FRAME_RATE){
            animationRunning = false;
            timer = 0;
            canvas.restore();
            Log.d("K", "animation end.");
            return;
        }else{
            //每隔FRAME_RATE刷新一下
            canvasHandler.postDelayed(runnable, FRAME_RATE);
        }

        if(timer == 0){
            canvas.save();
        }

        float currentRadius = radiusMax * (((float) timer * FRAME_RATE) / DURATION);
        Log.d("K", "current radius:" + currentRadius);
        canvas.drawCircle(x, y, (currentRadius), paint);
        timer++;
    }
}

在onDraw函数中,做的最重要的事情就是 canvas.drawCircle(x, y, (currentRadius), paint); ,这个是我们的核心代码,就是这句代码呈现出来我们想画的圆。那么 currentRadius 是靠什么来改变的呢?答案就是 timer 变量,我们知道每调用一次 invalidate()onDraw 函数就会被调用一次,所以我们可以在onDraw函数中通过不断的累加timer,来模拟半径的不断增加。DURATION 是总的时长,FRAME_RATE 相当于是对 timer 的一个放大系数,FRAME_RATE * timer 必须大于 DURATION 的时候,我们就 canvas.restore() 恢复现场,回到没有画圆之前的场景,即圆消失。

【源代码下载地址】

【本博将会持续不断的关注各种Android开源组件的核心原理,欢迎大家转载分享~不明白的地方直接评论回复即可】

RippleEffect原理解析

标签:demo   android开发   开源   

原文地址:http://blog.csdn.net/anxiaoyi520/article/details/43909893

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!