关闭

RippleView(波纹按钮)的效果实现

2602人阅读 评论(0) 收藏 举报
分类:

Android M已经发布,但是很多机器才升级到Android L,升级到L之后我们发现很多的按钮点击的时候会有一圈波纹扩散出去的效果,炫酷到没朋友。但是不是所有的版本上都有这个效果的,怎么办呢?有大神开发出了一个nineOldAndroid的动画包,我们可以使用里面的api做自定义的开发这样就可以用到各种版本上面了。

传送门在此:

http://nineoldandroids.com/

https://github.com/JakeWharton/NineOldAndroids


我找到了这么一个图,类似于下面的效果,我只是非常简单的说下具体是怎么实现的,如果想做的更好一点请自己包装开发,只说关键代码,代码有参考下面的工程。

此图和代码的传送门https://github.com/siriscac/RippleView



public class RippleView extends Button {
    private PointF touchPoint = new PointF();
    private int radius = 150;
    private Paint mPaint;
    private ObjectAnimator objectAnimator;

    public RippleView(Context context) {
        super(context);
        init();
    }

    public RippleView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public RippleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setAlpha(100);
        mPaint.setColor(Color.GREEN);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touchPoint.x = event.getX();
            touchPoint.y = event.getY();
            radius = 150;
            setRadius(150);
            break;
        case MotionEvent.ACTION_MOVE:
            touchPoint.x = event.getX();
            touchPoint.y = event.getY();
            setRadius(150);
            break;
        case MotionEvent.ACTION_UP:
            objectAnimator = ObjectAnimator.ofFloat(this, "radius", 150, 1000).setDuration(400);
            objectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
            objectAnimator.addListener(new AnimatorListener() {

                @Override
                public void onAnimationStart(Animator arg0) {

                }

                @Override
                public void onAnimationRepeat(Animator arg0) {

                }

                @Override
                public void onAnimationEnd(Animator arg0) {
                    setRadius(0);
                }

                @Override
                public void onAnimationCancel(Animator arg0) {

                }
            });
            objectAnimator.start();
            break;
        }
        return super.onTouchEvent(event);
    }

    /** 根据给定的color和alpha值得到给定的color */
    public int getColor(int color, float aAlpha) {
        int alpha = Math.round(Color.alpha(color) * aAlpha);
        int red = Color.red(color);
        int green = Color.green(color);
        int blue = Color.blue(color);
        return Color.argb(alpha, red, green, blue);
    }

    /** 在执行ObjectAnimator的过程中就会调用此方法 */
    public void setRadius(float radius) {
        System.out.println("setRadius----------" + radius);
        this.radius = (int) radius;
        if (this.radius > 0) {
            RadialGradient mRadialGradient = new RadialGradient(touchPoint.x, touchPoint.y, this.radius, getColor(
                    Color.GREEN, 0.1f), Color.GREEN, Shader.TileMode.MIRROR);
            mPaint.setShader(mRadialGradient);
        }
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawCircle(touchPoint.x, touchPoint.y, radius, mPaint);
        super.onDraw(canvas);
    }
}

主要的思想是这样的:重写onDraw()和onTouchEvent(),在onDraw中根据得到的手指的位置画一个圆,给定半径和画笔。在手指移动的时候也圆中心点的坐标也会跟着移动。当手指抬起来的时候触发动画。

objectAnimator = ObjectAnimator.ofFloat(this, "radius", 150, 1000).setDuration(400);
objectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
objectAnimator.start();


这是动画的关键代码,首先我们使用ObjectAnimator.ofFloat这个工厂方法得到一个ObjectAnimator的对象,然后赋予执行时间和Interpolator,也就是动画的变化效果,我们这里没有使用变化效果。

start之后在执行中会不断的调用setRedius(Float)方法,并不断传入最新的redius的值,这时候我们需要做的是不断修改当前redius的值并且刷新界面画新圆。

期间我们用到了RadialGradient方法。

android.graphics.RadialGradient.RadialGradient(float x, float y, float radius, int color0, int color1, TileMode tile)

Create a shader that draws a radial gradient given the center and radius.

Parameters:
x The x-coordinate of the center of the radius
y The y-coordinate of the center of the radius
radius Must be positive. The radius of the circle for this gradient
color0 The color at the center of the circle.
color1 The color at the edge of the circle.
tile The Shader tiling mode

我们可以看出各个参数的信息。大体就是这样,还有一个比较好玩的就是getColor这个方法,是根据给定的色值和alpha得出需要显示的color的值。其中几个Color的静态方法比较有意思,比如Color.red(color)

<pre name="code" class="html">int android.graphics.Color.red(int color)

Return the red component of a color int. This is the same as saying (color >> 16) & 0xFF

Parameters:
color 

它说same as (color >> 16) & 0xFF,如果去看源码的话也是这么实现的
    /**
     * Return the red component of a color int. This is the same as saying
     * (color >> 16) & 0xFF
     */
    public static int red(int color) {
        return (color >> 16) & 0xFF;
    }
我们假如说我们有一个色值0xFF00FF00,转成二进制就是11111111000000001111111100000000,然后右移16位就是00000000000000001111111100000000然后需要跟0xFF取与,得到00000000,也就是0x00。

跑题了,谢谢观赏。

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:37586次
    • 积分:540
    • 等级:
    • 排名:千里之外
    • 原创:63篇
    • 转载:6篇
    • 译文:0篇
    • 评论:2条
    文章分类
    最新评论