Android动画

Drawable Animation

帧动画,多张图片循环播放,实现动画效果。

以Xml定义一组帧动画

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item
        android:drawable="@drawable/a1"
        android:duration="200" />
    <item
        android:drawable="@drawable/a2"
        android:duration="200" />
    <item
        android:drawable="@drawable/a3"
        android:duration="200" />
    <item
        android:drawable="@drawable/a4"
        android:duration="200" />
    <item
        android:drawable="@drawable/a5"
        android:duration="200" />
</animation-list>

oneshot表示动画是否只执行一次。

每一帧的动画可以设置图层,让同一帧能有几个图。

    <item android:duration="100">  
        <layer-list>  
            <item android:drawable="@drawable/login_loading_1" />  
            <item android:drawable="@drawable/login_loading_2" />  
        </layer-list>  
    </item>  

帧动画图片多,可能会有内存溢出的问题、

View Animation

视图动画,又叫补间动画,有旋转,透明度,大小,位移四种动画效果,特点是实现简单,但是动画并不改变实际view的属性

用代码实现动画

TranslateAnimation 平移动画

 TranslateAnimation ta = new TranslateAnimation(0,400,0,0);//左平移400个单位
 ta.setDuration(2000);
 view.startAnimation(ta);

AlphaAnimation 透明度动画

  AlphaAnimation aa = new AlphaAnimation(1.0f,0.5f);//从不透明到半透明
  aa.setDuration(2000);
  view.startAnimation(aa)

RotateAnimation 旋转动画

  RotateAnimation ra = new RotateAnimation(0,180);
  ra.setDuration(2000);
  view.startAnimation(ra);

ScaleAnimation 缩放动画

 ScaleAnimation sa = new ScaleAnimation(0,5,0,5);
 sa.setDuration(2000);
 view.startAnimation(ra);

其中除AlphaAnimation之外其余三种动画的参考坐标系有三种。

  • 默认是view的左上角。
  • 以及view自身:Animation.RELATIVE_TO_SELF
  • 还有view的父控件:Animation.RELATIVE_TO_PARENT

这里说的参考系,可以理解成一个关键点的确定

这是一个300*300px的ViewGroup,背景图是个圆,小红点位于ViewGroup的左上角
以TranslateAnimation来看这三种参考坐标系

TranslateAnimation ta1 = new TranslateAnimation(0,150,0,0);
//TranslateAnimation ta2 = new TranslateAnimation(Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,10f,Animation.RELATIVE_TO_SELF,0,Animation.RELATIVE_TO_SELF,0);
//TranslateAnimation ta3 = new TranslateAnimation(Animation.RELATIVE_TO_PARENT,0,Animation.RELATIVE_TO_PARENT,1f,Animation.RELATIVE_TO_PARENT,0,Animation.RELATIVE_TO_PARENT,0);
ta1.setDuration(2000);
image.startAnimation(ta1);


三种设置分别对应三个gif图,第一个是以左上角为参考点,右平移150个单位(px)

第二个是以自身为参考,右平移自身10倍的距离。

第三个是以父控件为参考,右平移父控件一倍宽的距离。

ScaleAnimation有个比较有意思的地方。如果参考点不在原先的view上,缩放之后的view会带移动的效果。

 ScaleAnimation sa1 = new ScaleAnimation(1,5,1,5,-10,0);
 ScaleAnimation sa = new ScaleAnimation(1,5,1,5,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);

比如说sa1这个ScaleAnimation,参考点在他的左侧-10px,0px的地方
他放大五倍的效果是这样的

由于参考点在圆的左边,所以圆是向右边移动的。实际上这个放大效果是把圆和他的参考点看成了一个整体,参考点固定不动,放大五倍的过程中,参考点和圆的距离10px也放大了五倍。

让几个动画一起作用可以使用AnimationSet

AnimationSet as = new AnimationSet(true);//boolean 是否共享插值器
ScaleAnimation sa1 = new ScaleAnimation(1,5,1,5,-10,0);
ScaleAnimation sa = new ScaleAnimation(1,5,1,5,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
RotateAnimation ra = new RotateAnimation(0, 360f, Animation.RELATIVE_TO_PARENT, 0.5f, Animation.RELATIVE_TO_PARENT, 0.5f);
as.setInterpolator(new AccelerateDecelerateInterpolator());
as.addAnimation(sa1);
as.addAnimation(ra);
as.setDuration(2000);
image.startAnimation(as);

相比在代码里设置动画,一般还是用Xml来配置
在res目录下新建文件夹anim用来存放动画文件

如下代码

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <scale
        android:duration="1000"
        android:fillAfter="true"
        android:fromXScale="1"
        android:fromYScale="1"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="5"
        android:toYScale="5" />

    <set android:startOffset="1000">
        <translate
            android:duration="2000"
            android:fromXDelta="0"
            android:fromYDelta="0"
            android:toXDelta="200"
            android:toYDelta="0"
            />
        <alpha
            android:duration="2000"
            android:fromAlpha="1"
            android:toAlpha="0"
            />
    </set>
</set>

定义了一个一秒内放大五倍,接着一边平移一边消失的动画
值得注意的是pivotX和pivotY参考点的确定,以view的左上角为0,0点,用绝对数值确定,比如pivotX="-10",pivotY="0",表示左上角往左10px的点,pivotX="50%"表示相对于自身的百分之50,pivotX="50%p"表示相对于父控件的百分之50.对应代码设置的三种坐标确定

加载一个xml的Animation

Animation animation =  AnimationUtils.loadAnimation(MainActivity.this,R.anim.animation);
img.startAnimation(animation);

Property Animation

属性动画,通过改变View的属性,来达到动画的效果。
因为改变的是属性值,所以动画会改变View的位置,大小等。
一般要求改变的属性值有 get/set 方法

属性动画有两个动画执行类分别是ObjectAnimator和ValueAnimator

ObjectAnimator是ValueAnimator的子类,具有比ValueAnimator更强的封装性,使用代码更简洁,相反的,封装性不强的ValueAnimator则显得更加灵活,容易实现复杂的效果

ObjectAnimator

修改单个属性的动画效果

 ObjectAnimator.ofFloat(img,"rotation",0.0F,180F).setDuration(500).start();

直接调用ObjectAnimator的ofFloat,ofInt,ofObject方法,第一个参数是作用的view,第二个是操作的属性,第三个是一个不定参,只填一个表示结束的属性值,填两个分别表示开头和结尾的属性值。

多个属性值改变的动画效果,(同时改变)可以用PropertyValuesHolder

    PropertyValuesHolder pvha = PropertyValuesHolder.ofFloat("alpha", 1f, 0, 1f);
    PropertyValuesHolder pvhsx = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
    PropertyValuesHolder pvhsy = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
    ObjectAnimator.ofPropertyValuesHolder(view, pvha, pvhsx, pvhsy).setDuration(2000).start();

ValueAnimator

实际上,ValueAnimator可以看成是提供一个区间的计算过程。
而实际的动画效果,需要我们在回调中自己去设置。
例如:

            ValueAnimator valueAnimator = ValueAnimator.ofFloat(200.0F);
            valueAnimator.setTarget(img);
            valueAnimator.setDuration(2000).start();
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    img.setTranslationY((Float) valueAnimator.getAnimatedValue());
                }
            });

因为ofFloat只传了一个参,所以200是结束值,区间是0-200;
2000ms时间内在该区间内不断的递增,AnimatorUpdateListener里通过valueAnimator.getAnimatedValue()就能拿到某时刻的值,再根据需要进行设置,这里是平移200个px

TypeEvaluator

上面说道ValueAnimator可看成是提供一个区间的计算过程。实际上,这个计算的操作,是由TypeEvaluator来进行的。

TypeEvaluator是一个接口,我们可以实现这个接口来实现自己的需求,也可以用Android提供的几个Evaluator

比如:

            ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointFEvaluator(),new PointF(0,0),new PointF(100,100));
            valueAnimator.setDuration(2000).start();
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    PointF pf = (PointF) valueAnimator.getAnimatedValue();
                    Log.e("walker","x值 : " + pf.x);
                    Log.e("walker","y值 : " + pf.y);
                }
            });

PointFEvaluator 是 自带的一个Evaluator,上面代码是(0,0)点到
(100,100)的计算过程,过程中不断回调AnimatorUpdateListener
因为我们没有为任何view设置动画,所以不会有什么动画效果,但是Log里可以看到2s间点的移动状态。毫无疑问,这是一条直线的运动轨迹

自定义TypeEvaluator模拟抛物线效果

            ValueAnimator valueAnimator = ValueAnimator.ofObject(new TypeEvaluator<PointF>() {

                @Override
                public PointF evaluate(float v, PointF o, PointF t1) {
                    
                    PointF pf = new PointF();
                    pf.x = 200 * v * 2;
                    pf.y = 0.5f * 200 * (v * 2) * (v * 2);
                    return pf;
                }
            },new PointF(0,0));

            valueAnimator.setDuration(2000).start();
            valueAnimator.setInterpolator(new LinearInterpolator());

            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {

                    PointF point = (PointF) valueAnimator.getAnimatedValue();
                    ball.setX(point.x);
                    ball.setY(point.y);
                }
            })

关于动画状态的监听
一个有四个状态,分别为开始,结束,取消,重复

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

                @Override
                public void onAnimationEnd(Animator animator) {

                }

                @Override
                public void onAnimationCancel(Animator animator) {

                }

                @Override
                public void onAnimationRepeat(Animator animator) {

                }
            })

也可以用AnimatorListenerAdapter选择自己需要的监听
比方说只需要动画结束的监听

            valueAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {

                }
            })

AnimatorSet设置多个动画的执行

            ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(img,"rotation",0.0F,360F);

            ValueAnimator valueAnimator = ValueAnimator.ofFloat(400.0F);
            valueAnimator.setTarget(img);
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    img.setTranslationY((Float) valueAnimator.getAnimatedValue());
                }
            });
            AnimatorSet animatorSet = new AnimatorSet();
            animatorSet.setDuration(2000);
            animatorSet.playTogether(objectAnimator,valueAnimator);//一起执行
//          animatorSet.playSequentially(objectAnimator,valueAnimator);//顺序执行
//          animatorSet.play(objectAnimator).with(valueAnimator);//链式排列
            animatorSet.start();

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,009评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,808评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,891评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,283评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,285评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,409评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,809评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,487评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,680评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,499评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,548评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,268评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,815评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,872评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,102评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,683评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,253评论 2 341

推荐阅读更多精彩内容