动画分类
Android动画总体分为两类:View动画 和 Android3.0 之后出现的属性动画。
View动画又分为两类:帧动画(Frame Animation)和补间动画(Tweened Animation)。
View动画
1. 帧动画
帧动画是最容易实现的一种动画,这种动画更多的依赖于完善的UI资源,他的原理就是将一张张单独的图片连贯的进行播放,从而在视觉上产生一种动画的效果;有点类似于某些软件制作gif动画的方式。
如上图,就是把一幅幅的图片按顺序显示,造成动画的视觉效果。
实现:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/a_0"
android:duration="100" />
<item
android:drawable="@drawable/a_1"
android:duration="100" />
<item
android:drawable="@drawable/a_2"
android:duration="100" />
</animation-list>
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frame_animation);
ImageView animationImg1 = (ImageView) findViewById(R.id.animation1);
animationImg1.setImageResource(R.drawable.frame_anim1);
AnimationDrawable animationDrawable1 = (AnimationDrawable) animationImg1.getDrawable();
animationDrawable1.start();
}
2. 补间动画
补间动画分为四种形式:translate(位移)、rotate(旋转)、scale(缩放大小)、alpha(淡入淡出)。
补间动画有两种实现方式:xml文件形式和代码形式。
1、前者优点:动画描述可读性更好
2、后者优点:动画效果可动态创建
2.1 位移
xml 形式:
translate.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<!--
位移
android:fillBefore = “true” 动画播放完后,视图是否会停留在动画开始的状态,默认为true
android:fillAfter = “false” 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
android:fillEnabled= “true” 是否应用fillBefore值,对fillAfter值无影响,默认为true
android:repeatMode= “restart” 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart
android:repeatCount = “0” 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复
android:interpolator = @[package:]anim/interpolator_resource 插值器,即影响动画的播放速度,下面会详细讲 -->
<translate
android:duration="2000"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="600"
android:toYDelta="600"
android:interpolator="@android:anim/linear_interpolator"
android:repeatMode="restart"
android:repeatCount="infinite"/>
</set>
Android内置了 9 种内置的插值器实现:
作用 | 资源ID | 对应的Java类 |
---|---|---|
动画加速进行 | @android:anim/accelerate_interpolator | AccelerateInterpolator |
快速完成动画,超出再回到结束样式 | @android:anim/overshoot_interpolator | OvershootInterpolator |
先加速再减速 | @android:anim/accelerate_decelerate_interpolator | AccelerateDecelerateInterpolator |
先退后再加速前进 | @android:anim/anticipate_interpolator | AnticipateInterpolator |
先退后再加速前进,超出终点后再回终点 | @android:anim/anticipate_overshoot_interpolator | AnticipateOvershootInterpolator |
最后阶段弹球效果 | @android:anim/bounce_interpolator | BounceInterpolator |
周期运动 | @android:anim/cycle_interpolator | CycleInterpolator |
减速 | @android:anim/decelerate_interpolator | DecelerateInterpolator |
匀速 | @android:anim/linear_interpolator | LinearInterpolator |
在Activity中调用
Animation animation = AnimationUtils.loadAnimation(this, R.anim.translate);
tvTitle.startAnimation(animation);
代码形式:
TranslateAnimation translate = new TranslateAnimation(0, 0, 0, 750);
translate.setDuration(4000);
translate.setFillAfter(true);
translate.setRepeatCount(Animation.INFINITE); //无线循环
translate.setRepeatMode(Animation.REVERSE); //倒序播放
translate.setInterpolator(new LinearInterpolator());
tvTitle.startAnimation(translate);
2.2 旋转
xml形式:
rotate.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!--
旋转
fromDegrees 动画开始时的角度
toDegrees 动画结束时物件的旋转角度,正代表顺时针,负代表逆时针
pivotX pivotY,可取值为数字,百分比,或者百分比p
设置为数字时(如50),轴点为View的左上角的原点在x方向和y方向加上50px的点。在Java代码里面设置这个参数的对应参数是Animation.ABSOLUTE。
设置为百分比时(如50%),轴点为View的左上角的原点在x方向加上自身宽度50%和y方向自身高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_SELF。
设置为百分比p时(如50%p),轴点为View的左上角的原点在x方向加上父控件宽度50%和y方向父控件高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_PARENT -->
<rotate
android:duration="4000"
android:fromDegrees="0"
android:interpolator="@android:anim/linear_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="-360" />
</set>
在Activity中调用:
Animation rotateAnimation = AnimationUtils.loadAnimation(this, R.anim.rotate);
tvTitle.startAnimation(rotateAnimation);
代码形式:
// 参数说明:
// 1. fromDegrees :动画开始时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
// 2. toDegrees :动画结束时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
// 3. pivotXType:旋转轴点的x坐标的模式
// 4. pivotXValue:旋转轴点x坐标的相对值,取值范围0-1
// 5. pivotYType:旋转轴点的y坐标的模式
// 6. pivotYValue:旋转轴点y坐标的相对值,取值范围0-1
// pivotXType = Animation.ABSOLUTE:旋转轴点的x坐标 = View左上角的原点 在x方向 加上 pivotXValue数值的点(y方向同理)
// pivotXType = Animation.RELATIVE_TO_SELF:以自身为标准,旋转轴点的x坐标 = View左上角的原点 在x方向 加上 自身宽度乘上pivotXValue数值的值(y方向同理)
// pivotXType = Animation.RELATIVE_TO_PARENT:以父组件为标准,旋转轴点的x坐标 = View左上角的原点 在x方向 加上 父控件宽度乘上pivotXValue数值的值 (y方向同理)
RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(4000);
rotateAnimation.setRepeatCount(Animation.INFINITE);
rotateAnimation.setRepeatMode(Animation.RESTART);
rotateAnimation.setInterpolator(new AccelerateInterpolator());
tvTitle.startAnimation(rotateAnimation);
2.3 缩放大小
xml形式
scale.xml
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!--
缩放大小
fromXScale,fromYScale 动画开始前X,Y的缩放,0.0为不显示, 1.0为正常大小
toXScale,toYScale 动画最终缩放的倍数, 1.0为正常大小,大于1.0放大
startOffset 动画多次执行的间隔时间,如果只执行一次,执行前会暂停这段时间
轴点 = 视图缩放的中心点
pivotX pivotY,可取值为数字,百分比,或者百分比p
设置为数字时(如50),轴点为View的左上角的原点在x方向和y方向加上50px的点。在Java代码里面设置这个参数的对应参数是Animation.ABSOLUTE。
设置为百分比时(如50%),轴点为View的左上角的原点在x方向加上自身宽度50%和y方向自身高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_SELF。
设置为百分比p时(如50%p),轴点为View的左上角的原点在x方向加上父控件宽度50%和y方向父控件高度50%的点。在Java代码里面设置这个参数的对应参数是Animation.RELATIVE_TO_PARENT-->
<scale
android:duration="4000"
android:fromXScale="0"
android:fromYScale="0"
android:interpolator="@android:anim/linear_interpolator"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:startOffset="0"
android:toXScale="1.5"
android:toYScale="1.5" />
</set>
在Activity中调用:
Animation scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.scale);
tvTitle.startAnimation(scaleAnimation);
代码形式
// 参数说明:
// 1. fromX :动画在水平方向X的结束缩放倍数
// 2. toX :动画在水平方向X的结束缩放倍数
// 3. fromY :动画开始前在竖直方向Y的起始缩放倍数
// 4. toY:动画在竖直方向Y的结束缩放倍数
// 5. pivotXType:缩放轴点的x坐标的模式
// 6. pivotXValue:缩放轴点x坐标的相对值,取值范围0-1
// 7. pivotYType:缩放轴点的y坐标的模式
// 8. pivotYValue:缩放轴点y坐标的相对值,取值范围0-1
// pivotXType = Animation.ABSOLUTE:缩放轴点的x坐标 = View左上角的原点 在x方向 加上 pivotXValue数值的点(y方向同理)
// pivotXType = Animation.RELATIVE_TO_SELF:以自身为标准,缩放轴点的x坐标 = View左上角的原点 在x方向 加上 自身宽度乘上pivotXValue数值的值(y方向同理)
// pivotXType = Animation.RELATIVE_TO_PARENT:以父组件为标准,缩放轴点的x坐标 = View左上角的原点 在x方向 加上 父控件宽度乘上pivotXValue数值的值 (y方向同理)
ScaleAnimation scaleAnimation = new ScaleAnimation(1f,0.5f,1f,0.5f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
scaleAnimation.setDuration(4000);
scaleAnimation.setRepeatCount(Animation.INFINITE); scaleAnimation.setRepeatMode(Animation.REVERSE);
tvTitle.startAnimation(scaleAnimation);
2.4 淡入淡出
xml形式
alpha.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!--
淡入淡出
fromAlpha 开始时透明度,范围0-1,1:不透明;0:完全透明
toAlpha 结束时透明度
duration 动画持续时间 -->
<alpha
android:duration="4000"
android:fromAlpha="1"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:toAlpha="0.3" />
</set>
在Activity中调用:
Animation alphaAnimation = AnimationUtils.loadAnimation(this, R.anim.alpha);
tvTitle.startAnimation(alphaAnimation);
代码形式:
AlphaAnimation alphaAnimation = new AlphaAnimation(0.2f, 1f);
alphaAnimation.setDuration(4000);
alphaAnimation.setRepeatCount(Animation.INFINITE);
alphaAnimation.setRepeatMode(Animation.REVERSE);
tvTitle.startAnimation(alphaAnimation);
2.5 组合动画
xml形式
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="5000"
android:fillAfter="true"
android:interpolator="@android:anim/linear_interpolator"
android:shareInterpolator="true"
android:startOffset="1000">
<!--
android:shareinterpolator = “true” 组合动画独特的属性
表示组合动画中的动画是否和集合共享同一个差值器
如果集合不指定插值器,那么子动画需要单独设置
android:startOffset 动画延迟开始时间(ms)
组合动画播放时是全部动画同时开始
如果想不同动画不同时间开始就要使用android:startOffset属性来延迟单个动画播放时间 -->
<!-- 平移 -->
<translate
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="600"
android:toYDelta="700"
android:repeatCount="infinite"
android:repeatMode="reverse"/>
<!-- 缩放大小 -->
<scale
android:fromXScale="1"
android:fromYScale="1"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="0.5"
android:toYScale="0.5"
android:repeatCount="infinite"
android:repeatMode="reverse"/>
<!-- 旋转 -->
<!--<rotate
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360"
android:repeatCount="infinite"
android:repeatMode="reverse"/>-->
<!-- 淡入淡出 -->
<alpha
android:fromAlpha="1"
android:toAlpha="0.3"
android:repeatCount="infinite"
android:repeatMode="reverse"/>
</set>
在Activity中调用:
Animation zuheAnimation = AnimationUtils.loadAnimation(this, R.anim.zuhe_animation);
tvTitle.startAnimation(zuheAnimation);
代码形式
//组合动画设置
//步骤1:创建组合动画对象(设置为true)
AnimationSet animationSet = new AnimationSet(true);
//步骤2:设置组合动画的属性
animationSet.setFillAfter(true);
animationSet.setInterpolator(new LinearInterpolator());
animationSet.setDuration(4000);
//步骤3:创建子动画
//旋转动画
Animation rotate = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f,Animation.RELATIVE_TO_SELF, 0.5f);
rotate.setRepeatCount(Animation.INFINITE);
rotate.setRepeatMode(Animation.REVERSE);
//平移动画
Animation translate01 = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_PARENT, 0,
TranslateAnimation.RELATIVE_TO_PARENT, 0.5f,
TranslateAnimation.RELATIVE_TO_SELF, 0,
TranslateAnimation.RELATIVE_TO_SELF, 0);
//淡入淡出动画
Animation alpha = new AlphaAnimation(1, 0.2f);
alpha.setStartOffset(1000);
//缩放动画
Animation scale = new ScaleAnimation(1,0.5f,1,0.5f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
scale.setStartOffset(1500);
//步骤4:将创建的子动画添加到组合动画里
animationSet.addAnimation(rotate);
animationSet.addAnimation(translate01);
animationSet.addAnimation(alpha);
animationSet.addAnimation(scale);
tvTitle.startAnimation(animationSet);
3. 监听动画
- Animation类通过监听动画开始 / 结束 / 重复时刻来进行一系列操作,如跳转页面等等
- 通过在 Java 代码里setAnimationListener()方法设置
animationSet.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
//动画开始时执行
Toast.makeText(ViewAnimatorActivity.this, "动画开始了", Toast.LENGTH_SHORT).show();
}
@Override
public void onAnimationEnd(Animation animation) {
//动画结束时执行
}
@Override
public void onAnimationRepeat(Animation animation) {
//动画重复时执行
}
});
4. 应用场景
4.1 标准的动画效果
- 补间动画常用于视图View的一些标准动画效果:平移、旋转、缩放 & 透明度;
- 除了常规的动画使用,补间动画还有一些特殊的应用场景。
4.2 特殊的应用场景
- Activity 的切换效果
- Fragement 的切换效果
- 视图组(ViewGroup)中子元素的出场效果
4.2.1 Activity 的切换效果
即 Activity 启动 / 退出时的动画效果。
a.启动动画
此处使用系统自带的动画效果
Intent intent = new Intent(this, ViewAnimatorActivity.class);
startActivity(intent);
//系统自带:淡入淡出动画
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out);
//系统自带:从左向右滑动效果
overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
//特别注意
//overridePendingTransition()必须要在startActivity(intent)后被调用才能生效
//采用overridePendingTransition(int enterAnim, int exitAnim)进行设置
//enterAnim:从Activity a跳转到Activity b,进入b时的动画效果资源ID
//exitAnim:从Activity a跳转到Activity b,离开a时的动画效果资源Id
b.退出动画
此处使用系统自带的动画效果
@Override
public void finish() {
super.finish();
//系统自带:从左向右滑动效果
overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
//特别注意
//overridePendingTransition()必须要在finish()后被调用才能生效
}
对于参数 enterAnim & exitAnim 的资源ID,也可自定义Activity的切换效果:
此处就用到补间动画了
a. 自定义 淡入淡出 效果
淡入淡出 效果是采用透明度动画(Alpha)。
fade_in.xml(淡入)
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="1500"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>
fade_out.xml(淡出)
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="1500"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>
在Java代码中设置
Intent intent = new Intent(this, ViewAnimatorActivity.class);
startActivity(intent);
//自定义:淡入淡出动画
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
b. 自定义 左右滑动 效果
- 左右滑动 效果是采用平移动画(Translate)
- 先了解 Activity 的位置信息,如下图
从上图可以看出:
- 以屏幕底边为X轴,屏幕左边为Y轴;
- 当Activity在X轴 = -100%p时,刚好完全超出屏幕到左边(位置1)
- 当Activity在X轴 = 0%p时,刚好完全在屏幕内(位置2)
- 当Activity在X轴 = 100%p时,刚好完全超出屏幕到右边(位置3)
下面自定义一个动画效果:从右滑到左
out_to_left.xml
从中间滑到左边,即从位置2 - 位置1
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!--从中间滑到左边-->
<translate
android:duration="500"
android:fromXDelta="0%p"
android:toXDelta="-100%p" />
</set>
in_from_right.xml
从右边滑到中间,即从位置3 - 位置2
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!--从右边滑到中间-->
<translate
android:duration="500"
android:fromXDelta="100%p"
android:toXDelta="0%p" />
</set>
在Java代码中设置效果
Intent intent = new Intent(this, ViewAnimatorActivity.class);
startActivity(intent);
//自定义:从左向右滑动效果
overridePendingTransition(R.anim.in_from_right, R.anim.out_to_left);
效果图
- 关于 缩放和旋转动画 作为Activity的动画效果也是类似的
- 通过 想象力 能组合 上述4种基本动画 进行动画效果展示
- 此处仅列出较为简单的切换效果,如想实现更多酷炫的切换动画,请看文章
4.2.2 Fragment动画切换效果
系统自带的动画切换效果
FragmentTransaction fragmentTransaction = mFragmentManager
.beginTransaction();
fragmentTransaction.setTransition(int transit);
// 通过setTransition(int transit)进行设置
// transit参数说明
// 1. FragmentTransaction.TRANSIT_NONE:无动画
// 2. FragmentTransaction.TRANSIT_FRAGMENT_OPEN:标准的打开动画效果
// 3. FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:标准的关闭动画效果
// 标准动画设置好后,在Fragment添加和移除的时候都会有。
自定义动画效果
// 采用`FragmentTransavtion`的 `setCustomAnimations()`进行设置
FragmentTransaction fragmentTransaction = mFragmentManager
.beginTransaction();
fragmentTransaction.setCustomAnimations(
R.anim.in_from_right,
R.anim.out_to_left);
// 此处的自定义动画效果同Activity,此处不再过多描述
4.2.3 视图组(ViewGroup)中子元素的出场效果
- 视图组(ViewGroup)中子元素可以具备出场时的补间动画效果
- 常用需求场景:为 ListView 或 RecyclerView的 item 设置出场动画
使用步骤:
步骤1:设置子元素的出场动画
res/anim/view_animation.xml
<?xml version="1.0" encoding="utf-8"?>
<!--此处采用了组合动画-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000">
<alpha
android:duration="1500"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
<translate
android:fromXDelta="500"
android:toXDelta="0" />
</set>
步骤2:设置 视图组(ViewGroup)的动画文件
res/ anim /anim_layout.xml
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="0.5"
android:animationOrder="normal"
android:animation="@anim/view_animation">
<!--
android:delay="0.5" 子元素开始动画的时间延迟
如子元素入场动画的时间总长设置为300ms,那么 delay = "0.5" 表示每个子元素都会延迟150ms才会播放动画效果,
第一个子元素延迟150ms播放入场效果;第二个延迟300ms,以此类推
android:animationOrder="normal" 表示子元素动画的顺序
可设置属性为:
1、normal :顺序显示,即排在前面的子元素先播放入场动画
2、reverse:倒序显示,即排在后面的子元素先播放入场动画
3、random:随机播放入场动画
android:animation="@anim/view_animation" 设置入场的具体动画效果 -->
</layoutAnimation>
步骤3:为视图组(ViewGroup)指定andorid:layoutAnimation属性
指定的方式有两种: XML / Java代码设置
方式1:在 XML 中指定
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"
// 指定layoutAnimation属性用以指定子元素的入场动画
android:layoutAnimation="@anim/anim_layout"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
方式2:在Java代码中指定
这样就不用额外设置res/ anim /anim_layout.xml该xml文件了
ListView lv = (ListView) findViewById(R.id.listView1);
// 加载子元素的出场动画
Animation animation = AnimationUtils.loadAnimation(this,R.anim.anim_item);
// 设置LayoutAnimation的属性
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
// 为ListView设置LayoutAnimation的属性
lv.setLayoutAnimation(controller);
上述二者的效果是一样的。
效果图
相关文章阅读
属性动画
Android 动画:插值器与估值器