Android -- 动画

一,首先说一下,Android 项目中res下的anim 和 animtor 文件夹。
  • anim文件夹
    anim文件夹下存放tween animationframe animation;xml文件里只有scale、rotate、translate、alpha、set五个标签(默认的中心是View的左上角)
使用方法:
1. 加载动画:animation = AnimationUtils.loadAnimation(R.anim.xxx) 
2. 设置动画:mView.setAnimation(animation) 
3. 开启动画:mView.startAnimation()
  • animator文件夹
    animator文件夹下存放property animation,即属性动画,xml文件里有animatorobjectAnimatorset三个标签。
    在XML中:
    ObjectAnimator --对应--> <objectAnimator>
    AnimatorSet --对应--> <set>
使用方法: 
1. 加载动画:animation = AnimatorInflater.loadAnimator(R.animator.xxx) 
2. 设置动画:animation.setTarget(mView) 
3. 开启动画:animation .start()
二,视图动画(tween animation)

tween动画一共有四种动画效果:

  • 平移动画 translate (xml) -->TranslateAnimation (java代码)
  • 缩放动画 scale (xml) -->ScaleAnimation (java代码)
  • 旋转动画 rotate (xml) -->RotateAnimation (java代码)
  • 透明度动画 alpha (xml) -->AlphaAnimation (java代码)
视图动画属性(图片源自网络).png
tween 动画的坐标

tween 的坐标体系 ( ↓ Y正方向;→ X正方形)也是以目标 view 的坐标为参考的。以目标 view 的左上角为坐标原点。
xml中参数数值:

1,px为单位
image.png

2,% 自身的%为单位

image.png

3,%p 以父布局%为单位

image.png

注意:tween动画,四种操作都不改变其view的属性。例如:给view添加点击事件,进行平移操作之后,该点击事件仍在原地。

三,属性动画(Property Animation) -- 通过动画的方式改变对象的属性了

1,ObjectAnimator: 常用方法有这些:ofFloat(),ofInt(),ofObject(),ofArgb(),ofPropertyValuesHolder()。

/**
    * @param target  动画操作的对象(可以是任意对象)
    * @param propertyName 表示操作对象的属性名字(只要是对象有的属性都可以),任何一切带有set开头的方法属性名字。
    * 常用的有:
    * 平移 translationX,translationY, X,Y
    * 缩放 scaleX,scaleY
    * 旋转 rotationX, rotationY
    * 透明度 alpha。
    * 也就是说控件都有以上setTranslationX(),setScaleX(),setRotationX(),setAlpha() 等方法。
    * @param values 动画过渡值。当然过度值可以有一个到N个,如果是一个值的话默认这个值是动画过渡值的结束值。如果有N个值,动画就在这N个值之间过渡。
    * @return An ObjectAnimator object that is set up to animate between the given values.
    */
ObjectAnimator ofFloat(Object target, String propertyName, float... values)

例如:

ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0.3f, 1.0F);
        animator.setDuration(2000);//动画时间
        animator.setInterpolator(new BounceInterpolator());//动画插值(有好多种)
        animator.setRepeatCount(-1);//设置动画重复次数--无限次(ValueAnimator.INFINITE=-1)
        animator.setRepeatMode(ValueAnimator.RESTART);//动画重复模式
        animator.setStartDelay(1000);//动画延时执行
        animator.start();//启动动画

2,组合动画 -- AnimatorSet
常见方法有:

  • after(Animator anim) 将现有动画插入到传入的动画之后执行
  • after(long delay) 将现有动画延迟指定毫秒后执行
  • before(Animator anim) 将现有动画插入到传入的动画之前执行
  • with(Animator anim) 将现有动画和传入的动画同时执行
        //开始图片的透明度从不透明到0.2的透明再到不透明,随着整个布局背景的颜色变化的同时ImageView先向右平移200个像素,
        //然后再放大2倍,最后沿着X轴从0到90度再到0度的旋转。
        ObjectAnimator animator1 = ObjectAnimator.ofFloat(imageView, "translationX", 0.0f, 200.0f, 0f);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(imageView, "scaleX", 1.0f, 2.0f);
        ObjectAnimator animator3 = ObjectAnimator.ofFloat(imageView, "rotationX", 0.0f, 90.0f, 0.0F);
        ObjectAnimator animator4 = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0.2f, 1.0F);

        //组合动画方式
        AnimatorSet set = new AnimatorSet();
        ((set.play(animator).with(animator1).before(animator2)).before(animator3)).after(animator4);
        set.setDuration(5000);
        set.start();

3,动画监听器 -- 用来监听不同状态下的动画情况。

animator.addListener(new Animator.AnimatorListener() {
           @Override
           public void onAnimationStart(Animator animation) {
               //TODO 动画开始前的操作
               /**
                * 比如这里可以初始化一些UI
                */
           }

           @Override
           public void onAnimationEnd(Animator animation) {
               //TODO 动画结束的操作
               /**
                * 比如这里可以等动画结束进行一些账号登录或者网络数据请求等。
                */
           }

           @Override
           public void onAnimationCancel(Animator animation) {
               //TODO 动画取消的操作
           }

           @Override
           public void onAnimationRepeat(Animator animation) {
               //TODO 动画重复的操作
           }
       });

如果你不想都写上面的几个方法,只需要动画结束时的监听,可以这样:

animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                //TODO 动画结束的操作
            }
        });

AnimatorListenerAdapter的源码只是一个实现了AnimatorListener接口的抽象类而已,你需要监听哪种动画状态就重写哪种方法就可以了。

Android系统还给我们提供了一个更加精确的方法来时刻监听当前动画的执行情况。那就是addUpdateListener(AnimatorUpdateListener listener)方法了。调用该方法只需实现AnimatorUpdateListener接口就可以读取到动画的每个更新值了。

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = (float) animation.getAnimatedValue();
                //获取动画更新值。
            }
        });

4,ValueAnimator
ValueAnimator是属性动画中的一个重要的类,其内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果我们通过例子来看看它的用法。ValueAnimator的用法很简单:

ValueAnimator animator = ValueAnimator.ofInt(0, 20,0);
        //动画值的变化,0---> 20 ---->0,常用于自定义View中,值的变化
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int value = (int) animation.getAnimatedValue();
                Log.e("TAG", "the value is " + value);
            }
        });
        animator.setDuration(1000);//动画时间
        animator.start();//启动动画


    /**
      * 当然,还有           
      * ValueAnimator.ofFloat(0f,10.5f,5.0f,0f);
      * ValueAnimator.ofArgb(0x00ffff,0x00ffee);
      * ValueAnimator.ofObject()   // 比较重要,涉及到了估值器
      */

5,估值器 -- TypeEvaluator
动画过程中TypeEvaluator(估值器)的作用:当我们ValueAnimator.ofObject()函数来做动画效果的时候就会用到估值器了,估值器说白了就是用来确定在动画过程中每时每刻动画的具体值的;换句话说就是确定ValueAnimator.getAnimatedValue()返回的具体对象类型 ( 当我们使用ValueAnimator.ofObject()的时候,是一定要去设置估值器的 ) 。

所有的估值器都要实现TypeEvaluator接口,TypeEvaluator接口具体代码如下。

public interface TypeEvaluator<T> {

    /**
     * This function returns the result of linearly interpolating the start and end values, with
     * <code>fraction</code> representing the proportion between the start and end values. The
     * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
     * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
     * and <code>t</code> is <code>fraction</code>.
     *
     * @param fraction   表示当前这段数值变化值得比例
     * @param startValue 当前这段数值变化的开始值
     * @param endValue   当前这段数据变化的结束值。
     * @return A linear interpolation between the start and end values, given the
     *         <code>fraction</code> parameter.
     */
    public T evaluate(float fraction, T startValue, T endValue);

}

简单使用如下:

private void startAnimation() {
            PointF startPointF = new PointF(0, 0);
            PointF endPointF = new PointF(300, 300);
            ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(), startPointF, endPointF);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    //此处得到的返回值类型,由PointEvaluator 决定,为 PointF
                    PointF pointF = (PointF) animation.getAnimatedValue();
                    Log.d(TAG, "onAnimationUpdate: " + pointF.x);
                    x = pointF.x;
                    //不断的刷新UI
                    invalidate();
                }
            });
            animator.setDuration(2000);
            animator.start();
        }

    /**
     * 自定义 ,估值器
     */
    private class PointEvaluator implements TypeEvaluator<PointF> {
        @Override
        public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
            float resultX = startValue.x + fraction * (endValue.x - startValue.x);
            float rexultY = startValue.y + fraction * (endValue.y - startValue.y);

            Log.d(TAG, "evaluate: resultX= " + resultX + "\nrexultY=" + rexultY);
            return new PointF(resultX, rexultY);
        }
    }

6,插值器 -- Interpolator
几种常用的集中插值器(以下图片源自网络):

  • AccelerateDecelerateInterpolator开始与结束的地方速率改变比较慢,在中间的时候加速。
image.png
  • AccelerateInterpolator开始的地方速率改变比较慢,然后开始加速。
image.png

-AnticipateInterpolator开始的时候向后然后向前甩

image.png

四、Android 圆形揭露动画(API>21)

官方介绍
当您显示或隐藏一组UI元素时,显示动画可为用户提供视觉连续性。

   / * @param view 要隐藏或显示在屏幕上的视图View.
     * @param centerX 剪切圆中心的x坐标
     * @param centerY 剪切圆中心的y坐标
     * @param startRadius 剪切圆的起始半径
     * @param endRadius 圆的最终半径
     */
    public static Animator createCircularReveal(View view,
            int centerX,  int centerY, float startRadius, float endRadius) {
        return new RevealAnimator(view, centerX, centerY, startRadius, endRadius);
    }

简单使用:

                Button mRevealBtn = findViewById(R.id.reveal_btn);
                int centerX = mRevealBtn.getWidth() / 2;
                int centerY = mRevealBtn.getHeight() / 2;
                //判断api是否大于21
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                    Animator mAnimator = ViewAnimationUtils.createCircularReveal(mRevealBtn, centerX, centerY, Math.max(centerX, centerY), 0);
                    mAnimator.addListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            super.onAnimationEnd(animation);
                            //这里可以监听到动画完成的事件;
                            //可以在这里进行gone的操作
                        }
                    });
                    mAnimator.start();
                }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,194评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,058评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,780评论 0 346
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,388评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,430评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,764评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,907评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,679评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,122评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,459评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,605评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,270评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,867评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,734评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,961评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,297评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,472评论 2 348

推荐阅读更多精彩内容