1. 前言
动画在安卓中,使用是非常常见的,比如网络请求时的loading,就是通过旋转实现的。 在安卓中,动画分为两大类, 分别是视图动画和属性动画。视图动画又分为帧动画和补间动画。这篇文章主要讲补间动画的使用。三种动画的使用文章地址如下:
2. 介绍
补间动画指的是, 设置好动画的开始属性 和 结束属性。 系统会在我们设置的动画时间内, 从开始时属性过渡到结束时候的属性。举个例子,一个控件向右平移100像素,其实改变的属性就是控件x轴的坐标。系统提供了四种补间动画,分别为:
- 平移
- 缩放
- 旋转
- 透明度
3. 使用
3.1 平移动画
- 在res/anim 目录下新建动画描述文件translate.xml,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="5000"
android:startOffset="1000"
android:fillBefore="true"
android:fillAfter="false"
android:fillEnabled="true"
android:repeatMode="restart"
android:repeatCount="3"
android:fromXDelta="0"
android:toXDelta="500"
android:fromYDelta="0"
android:toYDelta="500"
>
</translate>
解释:
第一部分是动画的公共属性,也就是其他三种动画也有这些属性:
- duration:动画时间,单位毫秒
- startOffset:动画延迟执行时间
- fillBefore: 动画播放完后,视图是否会停留在动画开始的状态,默认为true
- fillAfter: 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
- fillEnable: 是否应用fillBefore值,对fillAfter值无影响,默认为true
- restart:选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart|
- repeatCount:重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复 下面的是 平移动画的特有属性
- fromXDelta:视图在水平方向x 移动的起始值
- toXDelta:视图在水平方向x 移动的结束值
- fromYDelta:视图在竖直方向y 移动的起始值
- toYdelta: 视图在竖直方向y 移动的结束值
- 在Java代码中加载动画文件并播放
Animation animation = AnimationUtils.loadAnimation(this, R.anim.translate); iv.startAnimation(animation);
至此动画就已经定义完成并可以播放了。 第一步中的xml方式也可以通过java代码来实现,代码方式如下:
Animation translateAnimation = new TranslateAnimation(0,500,0,500);
mation
translateAnimation.setDuration(3000);
// 固定属性的设置都是在其属性前加“set”,如setDuration()
iv.startAnimation(translateAnimation);
解释:
- new TranslateAnimation():这是平移动画的构造函数,传入xml中平移动画的那几个特有属性。
- setDuration:通过setXX()方法设置上面xml中的动画公共属性
3.2 缩放动画
- 在res/anim 目录下新建动画描述文件scale.xml,内容如下:\
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:repeatCount="2"
android:fillBefore="true"
android:repeatMode="restart"
android:fromXScale="0"
android:toXScale="2"
android:fromYScale="0"
android:toYScale="2"
android:pivotX="50%"
android:pivotY="50%"
>
</scale>
解释:
- fromXScale: 水平方向的起始缩放倍数
- toXScale: 水平方向的结束缩放倍数
- fromYScale: 垂直方向起始缩放倍数
- toYScale: 垂直方向结束缩放倍数
- pivotX:缩放中心点的x坐标
- pivotY: 缩放中心点的y坐标
- 在Java代码中加载动画文件并播放
Animation animation = AnimationUtils.loadAnimation(this, R.anim.scale);
iv.startAnimation(animation);
3.3 旋转动画
- 在res/anim 目录下新建动画描述文件rotate.xml,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:repeatCount="2"
android:repeatMode="restart"
android:fillBefore="true"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
>
</rotate>
解释:
- fromDegrees:旋转起始角度
- toDegrees:旋转结束角度
- pivotX:旋转中心点x轴坐标
- pivotY: 旋转中心点y轴坐标
- 在Java代码中加载动画文件并播放
Animation animation = AnimationUtils.loadAnimation(this, R.anim.rotate);
iv.startAnimation(animation);
3.4 透明动画
- 在res/anim 目录下新建动画描述文件alpha.xml,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:startOffset="500"
android:fillBefore="true"
android:fromAlpha="1.0"
android:toAlpha="0.0"
>
</alpha>
解释:
- fromAlpha:透明度起始值
- toAlpha: 透明度结束值
- 在Java代码中加载动画文件并播放
Animation animation = AnimationUtils.loadAnimation(this, R.anim.alpha);
iv.startAnimation(animation);
3.5 组合动画
- 在res/anim 目录下新建动画描述文件combination.xml,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:fillBefore="true"
android:repeatCount="0"
android:repeatMode="restart"
android:shareInterpolator="true"
>
<translate
android:fromXDelta="0"
android:toXDelta="250"
android:fromYDelta="0"
android:toYDelta="-250"
android:duration="3000"
>
</translate>
<rotate
android:pivotX="50%"
android:pivotY="50%"
android:duration="3000"
android:fromDegrees="0"
android:toDegrees="30"
>
</rotate>
<!--<alpha-->
<!--android:duration="3000"-->
<!--android:fromAlpha="1.0"-->
<!--android:toAlpha="0.5"-->
<!--/>-->
</set>
解释:
- set:组合动画的根节点
- shareInterpolator:表示组合动画中的动画是否和集合共享同一个差值器,如果集合不指定插值器,那么子动画需要单独设置
特别注意:
- 组合动画播放时是全部动画同时开始,如果想不同动画不同时间开始就要使用android:startOffset属性来延迟单个动画播放时间。
- 在组合动画里scale缩放动画设置的repeatCount(重复播放)和fillBefore(播放完后,视图是否会停留在动画开始的状态)是无效的。所以如果需要重复播放或者回到原位的话需要在set标签里设置。
- 在Java代码中加载动画文件并播放
Animation animation = AnimationUtils.loadAnimation(this, R.anim.combination);
iv.startAnimation(animation);
4. 实例
- xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/iv_water"
android:layout_width="35dp"
android:layout_height="35dp"
android:src="@mipmap/water"
android:layout_centerInParent="true"
android:layout_above="@id/iv_shumiao"
android:visibility="gone"
/>
<ImageView
android:id="@+id/iv_shumiao"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/shumiao"
android:layout_centerInParent="true"
/>
<ImageView
android:id="@+id/iv_shuihu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/shuihu"
android:layout_below="@id/iv_shumiao"
/>
</RelativeLayout>
- java编写组合动画
package com.domain.study.animation.tween;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.content.ContextCompat;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import com.domain.study.animation.R;
import com.domain.study.animation.base.BaseActivity;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class TweenCombinationActivity extends BaseActivity {
@BindView(R.id.iv_shumiao)
ImageView ivShumiao;
@BindView(R.id.iv_shuihu)
ImageView ivShuihu;
@BindView(R.id.iv_water)
ImageView ivWater;
int shuiHuX = 0;
int shuiHuY = 0;
int shuMiaoX = 0;
int shuMiaoY = 0;
int shuMiaoWidth = 0;
int shuMiaoHeight = 0;
int shuiHuWidth = 0;
int shuiHuHeight = 0;
int waterHeight = 0;
@Override
protected int setLayoutId() {
return R.layout.activity_combination;
}
@Override
protected void initView() {
ivShuihu.post(new Runnable() {
@Override
public void run() {
int[] location = new int[2];
ivShuihu.getLocationOnScreen(location);
shuiHuX = location[0]; // view距离 屏幕左边的距离(即x轴方向)
shuiHuY = location[1]; // view距离 屏幕顶边的距离(即y轴方向)
shuiHuWidth = ivShuihu.getWidth();
shuiHuHeight = ivShuihu.getHeight();
}
});
ivShumiao.post(new Runnable() {
@Override
public void run() {
int[] location = new int[2];
ivShumiao.getLocationOnScreen(location);
shuMiaoX = location[0]; // view距离 屏幕左边的距离(即x轴方向)
shuMiaoY = location[1]; // view距离 屏幕顶边的距离(即y轴方向)
shuMiaoWidth=ivShumiao.getWidth(); // 获取宽度
shuMiaoHeight =ivShumiao.getHeight(); // 获取高度
}
});
ivWater.post(new Runnable() {
@Override
public void run() {
waterHeight = ivWater.getHeight();
}
});
}
@OnClick(R.id.iv_shuihu)
public void onViewClicked() {
start();
}
private void start(){
AnimationSet setAnimation = new AnimationSet(true);
// 子动画1:旋转动画
Animation rotate = new RotateAnimation(0,10,0.5f,0.5f);
rotate.setDuration(1000);
rotate.setStartOffset(3000);
// 子动画2:平移动画
Animation translate = new TranslateAnimation(
0,
shuMiaoX-shuiHuWidth,
0
,-(shuiHuHeight+shuMiaoHeight+waterHeight+100));
translate.setDuration(3000);
//等待水滴落下动画
Animation wait = new TranslateAnimation(
0,
0,
0
,0);
wait.setStartOffset(4000);
wait.setDuration(2000);
// 将创建的子动画添加到组合动画里
setAnimation.addAnimation(translate);
setAnimation.addAnimation(rotate);
setAnimation.addAnimation(wait);
ivShuihu.startAnimation(setAnimation);
rotate.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
ivWater.setVisibility(View.VISIBLE);
startWaterAnimation();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
private void startWaterAnimation(){
AnimationSet animationSet = new AnimationSet(true);
TranslateAnimation translateAnimation = new TranslateAnimation(0,0,0,50);
translateAnimation.setDuration(2000);
AlphaAnimation alphaAnimation = new AlphaAnimation(1,0);
alphaAnimation.setDuration(2000);
animationSet.addAnimation(translateAnimation);
animationSet.addAnimation(alphaAnimation);
ivWater.startAnimation(animationSet);
animationSet.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
ivWater.setVisibility(View.GONE);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
}
}
5.总结
- 补间动画系统提供了四种,分别是:平移、缩放、旋转、透明度。
- 动画可以通过xml文件来描述,也可以通过java代码来实现。
- 补间动画只能作用在view上。
- 补间动画其实没有改变view的真实属性,比如动画后看到的view,是没办法点击的。
- 可以通过组合动画,把四种动画结合使用。
- 组合动画启动时,所有的子动画是同时启动的,如果要有先后顺序,可以通过子动画的延时执行来实现。
6. 完整demo地址
7. 参考文章
8. 历史文章目录