Android Reveal Animation(揭露动画)实现

Android L (21)添加了揭露动画,我们先来看一下效果图:
这里写图片描述
看起来是不是蛮爽的~~
接下来我们看一下怎么实现这种效果把
首先我们新建一个Android项目,打开对应的layout,写成这样:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!--做动画的布局-->
    <RelativeLayout
        android:id="@+id/targetView"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        android:background="#ff00ff"
        android:layout_width="300dp"
        android:gravity="center"
        android:layout_height="400dp">
        <!--启动动画按钮-->
        <Button
            android:id="@+id/start"
            android:text="哈哈"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </RelativeLayout>
</LinearLayout>

然后我们在Activity里添加这样的代码:

final View targetView = findViewById(R.id.targetView);

findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        final int width = targetView.getMeasuredWidth();
        final int height = targetView.getMeasuredHeight();
        final float radius = (float)Math.sqrt(width*width + height*height) / 2;//半径
        Animator animator = ViewAnimationUtils.createCircularReveal(targetView, width/2, height/2, radius, 0);
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                targetView.setVisibility(View.GONE);
                }
            });
       animator.setDuration(2000l);
       animator.start();
     }
});

然后我们运行一下就可以看到想要的效果了~~~


然而我们平时开发却并不是这么如意,设计师不会让我们做这么简单的动画的,一定会有很多要求,然后发现这个就没办法做到了~~
我们再来看一下sdk提供的方法:

public static Animator createCircularReveal(View view,
            int centerX,  int centerY, float startRadius, float endRadius) {
       ...
    }

通过参数来看,要做动画的view,中心坐标, 起始半径
感觉能做的事情太少了,比如我有个需要要求做动画时中心坐标要做一个位移,类似这样:
这里写图片描述
为了方便看圆心位置,特意画了个蓝色小点标识一下,如果要实现这种可定制画的操作我们又该如何实现呢?我这里提供一种思路,当然方法应该还有其他的方式~
我这里用到了ValueAnimator动画类,这个类可以帮助我们算动画进度百分比,然后根据比例进行相应的图形处理即可~

第一步:

新建一个动画布局类:CircleAnimationLayout
这里我继承了FrameLayout,这样的话,我们只要包裹想要做动画的View即可,不管是View还是ViewGroup都可以了就。
来看一下这个类代码(先声明一下,这里写的比较随意,大家在项目里可以写的更完整一些,规范一些要):

public class CircleAnimationLayout extends FrameLayout {
    private Point mStartPoint;//起始圆心x,y
    private Point mEndPoint;//结束圆心x,y
    private float mStartR;//起始圆半径
    private float mEndR;//结束圆半径

    private float dx, dy, dr;// 用于存放x y r的变化值
    private Animator.AnimatorListener mListener;//动画回调
    private Paint mPaint;// 画笔,画那个蓝色小圆,标记用
    private Path mPath;// 用于裁剪view
    private boolean isClipView = false;//标识是否被裁剪,即不动画不需要裁剪

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

    public CircleAnimationLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CircleAnimationLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setWillNotDraw(false);//这个必须加在ViewGroup里,否则不会调用OnDraw方法
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(0xff0000ff);//圆心颜色
        mPath = new Path();
    }

    public CircleAnimationLayout setStartPoint(Point point) {
        mStartPoint = point;
        return this;//非正规建造模式
    }

    public CircleAnimationLayout setEndPoint(Point point) {
        mEndPoint = point;
        return this;//非正规建造模式
    }

    public CircleAnimationLayout setStartR(float r) {
        mStartR = r;
        return this;//非正规建造模式
    }
    public CircleAnimationLayout setEndR(float r) {
        mEndR = r;
        return this;//非正规建造模式
    }

    public CircleAnimationLayout setOnAnimatorListener(Animator.AnimatorListener listener) {
        mListener = listener;
        return this;//非正规建造模式
    }

    public void startAnimation() {
        ValueAnimator animator = ValueAnimator.ofFloat(0, 1).setDuration(2000);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float fraction = animation.getAnimatedFraction(); // 百分比
                dx = fraction * (mEndPoint.x - mStartPoint.x);
                dy = fraction * (mEndPoint.y - mStartPoint.y);
                dr = fraction * (mEndR - mStartR);
                Log.e("yk3372", dx + " " + dy + " " + dr);
                invalidate();
            }
        });
        animator.addListener(mListener);//设置动画回调
        animator.start();
        isClipView = true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 重点在这,上面所有都是为了这服务的
        if (isClipView) {
            float x = mStartPoint.x + dx;//临时x坐标
            float y = mStartPoint.y + dy;//临时y坐标
            float r = mStartR + dr;//临时半径r
            mPath.reset();
            mPath.addCircle(x, y, r, Path.Direction.CW);// 设置path为圆,我们可以任意定义各种图形
            canvas.clipPath(mPath);// 对view进行裁剪! 重点在这
            canvas.drawCircle(x, y, 10, mPaint); // 画那个蓝色圆心用的
        }
    }
}

第二步:

至于布局呢,就直接把刚才那个给套在这个View下即可:

<!--包裹即可-->
<com.example.yukai.test.CircleAnimationLayout
        android:id="@+id/targetView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <RelativeLayout
            android:layout_width="300dp"
            android:layout_height="400dp"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="10dp"
            android:background="#66ff00ff"
            android:gravity="center">

            <Button
                android:id="@+id/start"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="哈哈" />

        </RelativeLayout>
    </com.example.yukai.test.CircleAnimationLayout>

第三步:

然后我们再来看一下使用方式:

final CircleAnimationLayout targetView = (CircleAnimationLayout) findViewById(R.id.targetView);

        findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                final int width = targetView.getMeasuredWidth();
                final int height = targetView.getMeasuredHeight();
                final float radius = (float) Math.sqrt(width * width + height * height);
                targetView.setStartPoint(new Point(width / 2, height / 2))// 外面看起来跟建造模式使用一样
                        .setEndPoint(new Point(width / 2, 0))
                        .setStartR(radius/2)
                        .setEndR(0)
                        .setOnAnimatorListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation) {
                                targetView.setVisibility(View.GONE);//动画结束后就可以隐藏之类的操作了~
                            }
                        });
                targetView.startAnimation();
            }
        });

ok,通过上面的学习,我们其实可以做很多各种各样的动画,要感谢ValueAnimator这个动画类,是我们实现动画很简单。在不知道这个类之前,我曾经尝试自己去计算这些值,当然还要考虑进插值器(Interpolator),有点麻烦就不写了,用ValueAnimator足够了~~
赶紧自己去试一下吧~~^_^

原文地址:http://blog.csdn.net/yk3372/article/details/53053518

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值