Android 动画

Android 3.0之前已有View动画框架Animation(详见:Android之视图动画Animation),但存在一些局限性,当某个元素发生视图动画后,其响应事件位置还在动画前的地方。于是3.0之后,Google提出了属性动画。

Animation的优点

1. 版本兼容

不得不说,相对于 Animation,Animator 的版本兼容性还是太差,直到 Android3.0才开始出现的 Animator, 是无法满足目前开发环境2.x 的兼容支持的,而且在 android 官方的 support 包中也没有对于低版本的 Animator 进行支持,所以单从版本兼容来看, Animator 还是不够的,不过这是系统历史原因,我们只能接受.

2.实现效率

同样的,这也是 Animator 的一个缺点,由于 Animator 是直接通过设置对象的 setter,getter 方法,来起到动画显示效果的,所以为了满足对任意对象调用正确方法,Animator 使用了 Java 反射机制, 而 Animation 则是直接通过代码对矩阵进行处理,所以就效率这一方面而言, Animator比不上 Animation

Animator的实现原理

Animator 动画的实现机制说起来其实更加简单一点,因为他其实只是计算动画开启之后,结束之前,到某个时间点得时候,某个属性应该有的值,然后通过回调接口去设置具体值,其实 Animator 内部并没有针对某个 view 进行刷新,来实现动画的行为,动画的实现是在设置具体值的时候,方法内部自行调取的类似 invalidate 之类的方法实现的.也就是说,使用 Animator ,内部的属性发生了变化.

Animator的优点

1. 适用性

在上一个分析中,我们看到了由于 Animator 使用了反射机制导致其效率偏低,但是这也带来了他适用的对象范围的增加, Animation 仅对 View 这一种对象有用,但是 Animator 可以设置任意对象的属性,使其在某段时间内进行变化

2. 使用效果

相信大家平时使用 Animation 的时候,都有发现当正在进行平移移动,或者动画结束后,但位置发生改变的时候,你点击之前的位置,点击效果仍然存在,这就是因为 View 在内部的坐标位置其实没有发生改变,而如果使用 Animator 进行位移变换,那么你的点击位置就会随着动画效果发生相应改变,所以即使你正处在动画过程中,你也可以去点击按钮得到你想要的效果.

-----------------------------------------------

补间动画

  • 视图动画,也叫Tween(补间)动画可以在一个视图容器内执行一系列简单变换(位置、大小、旋转、透明度)。譬如,如果你有一个TextView对象,您可以移动、旋转、缩放、透明度设置其文本,当然,如果它有一个背景图像,背景图像会随着文本变化。
  • 补间动画通过XML或Android代码定义,建议使用XML文件定义,因为它更具可读性、可重用性。
    如下是视图动画相关的类继承关系:

AlphaAnimation <alpha> 放置在res/anim/目录下 渐变透明度动画
RotateAnimation <rotate> 放置在res/anim/目录下 画面转移旋转动果
ScaleAnimation <scale> 放置在res/anim/目录下 渐变尺寸伸缩动画
TranslateAnimation <translate> 放置在res/anim/目录下 画面转换位置移动动画效果
AnimationSet <set> 放置在res/anim/目录下 一个持有其它动画元素alpha、scale、translate、rotate或者其它set元素的容器
Animation属性详解


image.png

android:detachWallpaper setDetachWallpaper(boolean) 是否在壁纸上运行
android:duration setDuration(long) 动画持续时间,毫秒为单位
android:fillAfter setFillAfter(boolean) 控件动画结束时是否保持动画最后的状态
android:fillBefore setFillBefore(boolean) 控件动画结束时是否还原到开始动画前的状态
android:fillEnabled setFillEnabled(boolean) 与android:fillBefore效果相同
android:interpolator setInterpolator(Interpolator) 设定插值器(指定的动画效果,譬如回弹等)
android:repeatCount setRepeatCount(int) 重复次数
android:repeatMode setRepeatMode(int) 重复类型有两个值,reverse表示倒序回放,restart表示从头播放
android:startOffset setStartOffset(long) 调用start函数之后等待开始运行的时间,单位为毫秒
android:zAdjustment setZAdjustment(int) 表示被设置动画的内容运行时在Z轴上的位置(top/bottom/normal),默认为normal

Alpha 属性
image.png

Scale属性
image.png

Rotate属性
image.png

Translate属性
image.png
LinearLayout layout = (LinearLayout) findViewById(R.id.test_layout );
 ScaleAnimation scaleAnimation = new ScaleAnimation(0,1,0,1);
 scaleAnimation.setDuration(2000);
 LayoutAnimationController layoutAnimationController = new LayoutAnimationController(scaleAnimation,0.5f);
 layoutAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);
 layout .setLayoutAnimation(layoutAnimationController);

AnimationSet详解
AnimationSet继承自Animation,是上面四种的组合容器管理类,没有自己特有的属性,他的属性继承自Animation,所以特别注意,当我们对set标签使用Animation的属性时会对该标签下的所有子控件都产生影响。

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@[package:]anim/interpolator_resource"
    android:shareInterpolator=["true" | "false"] >
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float" />
    <translate
        android:fromXDelta="float"
        android:toXDelta="float"
        android:fromYDelta="float"
        android:toYDelta="float" />
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />
    <set>
        ...
    </set>
</set>

至于补间动画的使用,Animation还有如下一些比较实用的方法介绍
image.png

逐帧动画

属性动画

ObjectAnimator
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "translationX", 300);
objectAnimator1.setInterpolator(new AccelerateInterpolator());
objectAnimator1.setDuration(2000);
objectAnimator.setRepeatCount(ValueAnimator.INFINITE);//Animation.INFINITE 表示重复多次
objectAnimator.setRepeatMode(ValueAnimator.RESTART);//RESTART表示从头开始,REVERSE表示从末尾倒播
objectAnimator1.start();
Animation 使用setFillAfter(true)让动画停留在原处

动画属性值

平移:

translationX和translationY:增量控制view从它布局容器左上角坐标偏移
ObjectAnimator.ofFloat(imageView, "translationX", 300f);

rotation 控制view旋转:

rotation、rotationX、rotationY:控制view绕支点进行旋转
ObjectAnimator.ofFloat(imageView, "rotation", 360);

// 翻转
ObjectAnimator rotateX = ObjectAnimator.ofFloat(mTvText, "rotationX", 0, 360);
rotateX.setDuration(2000);
rotateX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        // 属性动画执行时,会回调这个监听器
        // 如果你的属性没有触发重绘,那你可以在这里加上invalidate()或postInvalidate()
        Log.d(TAG, "onAnimationUpdate: value=" + animation.getAnimatedValue()
                + "fraction=" + animation.getAnimatedFraction());
    }
});

scaleX、scaleY:控制view进行缩放:

scaleX、scaleY:控制view绕支点进行缩放
ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 0.3f,1f);

alpha:控制view透明度:

alpha:控制view透明度,默认是1(不透明),0完全透明(不可见)
ObjectAnimator.ofFloat(imageView, "alpha", 1f, 0.3f);

可变数组参数

可以有一个到N个,如果是一个值的话默认这个值是动画过渡值的结束值。如果有N个值,动画就在这N个值之间过渡。
动画监听:

ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "alpha", 0.5f, 1f);
objectAnimator1.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animation) {

    }

    @Override
    public void onAnimationEnd(Animator animation) {

    }

    @Override
    public void onAnimationCancel(Animator animation) {

    }

    @Override
    public void onAnimationRepeat(Animator animation) {

    }
});

Android提供了AnimatorListenerAdapter:

 ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "alpha", 0.5f, 1f);
 objectAnimator1.addListener(new AnimatorListenerAdapter() {
     @Override
     public void onAnimationEnd(Animator animation) {
         super.onAnimationEnd(animation);
     }
 });
XML中使用 ObjectAnimator

放置在res/animator/目录下
<objectAnimator>属性解释:


image.png

XML属性动画使用方法:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.animtor.property_animator);
set.setTarget(myObject);
set.start();

ValueAnimator
ValueAnimator 本身不提供任何动画效果,像个数值 发生器,用来产生具有一点规律数字。
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 500);
valueAnimator.setTarget(mTvText);
valueAnimator.setDuration(2000);
/**
* valueAnimator 必须使用updateListener进行接收数据
* ValueAnimator不跟属性进行绑定
*/
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
       // 在数值变化监听器中实现动画变换
       mTvText.setTranslationX((Float) animation.getAnimatedValue());
   }
});
valueAnimator.start();
PropertyValuesHolder 针对同一个对象多个属性,同时作用多种动画
PropertyValuesHolder propertyValuesHolder1 = PropertyValuesHolder.ofFloat("translationX", 300f);
PropertyValuesHolder propertyValuesHolder2 = PropertyValuesHolder.ofFloat("alpha", 1f, 0.5f);
PropertyValuesHolder propertyValuesHolder3 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder propertyValuesHolder4 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(imageView, propertyValuesHolder1, propertyValuesHolder2, propertyValuesHolder3, propertyValuesHolder4)
        .setDuration(5000).start();

AnimatorSet

与PropertyValuesHolder类似,但AnimatorSet多了playTogether(同时执行)、playSequentially(顺序执行)、play(objectAnimator1).with(objectAnimator2)、before、after这些方法协同工作。
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "alpha", 1f, 0.5f);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageView, "translationY", 300);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 0, 1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(5000);
animatorSet.playTogether(objectAnimator1, objectAnimator2,objectAnimator3);
animatorSet.start();

AnimatorSet set = new AnimatorSet(); // 下面代码产生的规则并不能确定anim2与anim3的先后关系 
 // 下面代码产生的规则可间接确定anim2与anim3的先后关系
set.play(anim1).before(anim2).before(anim3); 
// 下面代码产生的规则可完全确定anim1、anim2、anim3之间的先后关系
set.play(anim1).before(anim2).after(anim3); 
set.play(anim1).before(anim2); 
set.play(anim2).before(anim3);

xml使用属性动画

  • res下建立animator文件夹,然后建立res/animator/main_animator.xml
  • set标签,有一个orderring属性设置为together,还有另一个值:sequentially(表示一个接一个执行)。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:valueType="floatType">
    <objectAnimator
        android:duration="1000"
        android:propertyName="scaleX"
        android:valueFrom="1"
        android:valueTo="0.5" />
    <objectAnimator
        android:duration="1000"
        android:propertyName="scaleY"
        android:valueFrom="1"
        android:valueTo="0.5" />
</set>
<!--  代码中调用
    Animator animator = AnimatorInflater.loadAnimator(getApplicationContext(), R.animator.set_animator);
    animator.setTarget(imageView);
    animator.start();
  -->

View的animate方法

Android 3.0后,谷歌给View增加animate方法直接驱动属性动画。

 imageView.animate()
 .alpha(0.5f)
 .y(300)
 .setDuration(2000)
 //api min is 16
 .withStartAction(new Runnable() {
     @Override
     public void run() {

     }
 })
 //api min is 16
 .withEndAction(new Runnable() {
     @Override
     public void run() {

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