一、动画概述
动画作为广泛存在于程序界面中的效果,具有相似的属性,Android中动画通用的属性包括:
1、目标(target):View
2、时长(duration):duration
3、开始状态(from):fromXXX
4、结束状态(to):toXXX
5、开始时间(beginTime):startOffset
6、重复次数(repeatCount):repeatCount
7、时间轴(timeLine):interpolator
Android动画主要分为两类:视图动画和属性动画(API 11)
二、视图动画:
1、TweenAnimation
TweenAnimation具有四种变换效果,其包括四个子类:TranslateAnimation(平移动画)、ScaleAnimation(缩放动画)、
RotateAnimation(旋转动画)、AlphaAnimation(透明度动画)以及组合动画类:AnimationSet
以下是每个变换效果中其他常用属性:
<?xml version="1.0" encoding="utf-8"?>
<!-- set标签代表动画组合
shareInterpolator 组合中动画是否共享同一插值器
startOffset 组合中动画是否共享同一开始时间-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 其他通用属性:
interpolator 插值器
fillAfter 结束时是否停留在结束位置
-->
<!-- fromAlpha 起始透明度
toAlpha 结束透明度
说明:
0.0表示完全透明
1.0表示完全不透明-->
<alpha
android:interpolator="@android:anim/cycle_interpolator"
android:fillAfter="true"
android:fromAlpha="1.0"
android:toAlpha="0.0">
</alpha>
<!-- fromXScale 起始X坐标的伸缩尺寸
fromYScale 起始Y坐标的伸缩尺寸
toXScale 结束X坐标的伸缩尺寸
toYScale 结束Y坐标的伸缩尺寸
说明:
0.0表示收缩到没有
1.0表示正常无伸缩
值小于1.0表示收缩
值大于1.0表示放大
pivotX 相对于控件X坐标的开始位置
pivotY 相对于控件Y坐标的开始位置
说明:
以上两个属性值 从0%-100%中取值
50%为控件的X或Y方向坐标上的中点位置-->
<scale
android:fromXScale="1"
android:fromYScale="1"
android:toXScale="2"
android:toYScale="2"
android:pivotX="50%"
android:pivotY="50%">
</scale>
<!-- fromXDelta 属性为动画起始时 X坐标上的位置
toXDelta 属性为动画结束时 X坐标上的位置
fromYDelta 属性为动画起始时 Y坐标上的位置
toYDelta 属性为动画结束时 Y坐标上的位置
注意:
100%为控件自身宽或高的一倍
负值为反方向
100%p为屏幕宽或高的一倍
负值为反方向-->
<translate android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="200"
android:toYDelta="200">
</translate>
<!-- fromDegrees 起始时控件角度
toDegrees 结束时控件旋转角度
pivotX 相对于控件的X坐标开始位置
pivotY 相对于控件的Y坐标开始位置-->
<rotate android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%">
</rotate>
</set>
应用动画:
<pre name="code" class="java" style="font-size: 13.3333px;">Animation animation = AnimationUtils.loadAnimation(this , R.anim.anim_set);
animation.setRepeatCount(2);//通过代码设置动画,其他属性相同
imageView.startAnimation(animation);
动画的组合除可并行外,也可串行,设置串行动画方法有两种:
1、设置startOffset,使不同动画时间相错
2、设置监听器
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
2、Frame动画:
Frame动画即帧动画,其原理就如同电影一般,一帧一帧播放形成动画的效果
首先在XML中定义AnimationDrawable
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false" >
<item android:drawable="@drawable/progress_one" android:duration="200"></item>
<item android:drawable="@drawable/progress_two" android:duration="200"></item>
<item android:drawable="@drawable/progress_three" android:duration="200"></item>
<item android:drawable="@drawable/progress_four" android:duration="200"></item>
</animation-list>
imageView.setBackgroundResource(R.drawable.loading);
AnimationDrawable drawable = (AnimationDrawable) imageView.getBackground();
drawable.start();
3、特殊使用场景:
LayoutAnimation作用于ViewGroup,为其子元素指定一个动画
1、定义LayoutAnimation
<?xml version="1.0" encoding="utf-8"?>
<!-- delay 动画延迟时间
animationOrder 子元素动画顺序-->
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animationOrder="normal"
android:animation="@anim/translate"
android:delay="0.5">
</layoutAnimation>
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:duration="300"
android:fromXDelta="500"
android:toXDelta="0">
</translate>
3、为ViewGroup指定android:layoutAnimation属性
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layoutAnimation="@anim/anim_layout"
android:layout_height="match_parent"></ListView>
</LinearLayout>
4、应用
ViewGroup子元素视图
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:src="@mipmap/ic_launcher"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/text"
android:layout_marginTop="15dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
public class TestActivity extends AppCompatActivity {
private ListView listView;
private List<String> s = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.anim_list);
listView = (ListView) findViewById(R.id.listView);
initList();
}
private void initList() {
for(int i = 0 ; i < 10 ; i ++)
s.add("标题" + i);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this , R.layout.list_item , R.id.text , s);
listView.setAdapter(adapter);
}
}
除了通过XML指定layoutAnimation外,也可通过LayoutAnimationController实现
TranslateAnimation translate = (TranslateAnimation) AnimationUtils.loadAnimation(this , R.anim.translate);
LayoutAnimationController controller = new LayoutAnimationController(translate);
controller.setDelay(1);
controller.setOrder(LayoutAnimationController.ORDER_RANDOM);
listView.setLayoutAnimation(controller);
2、Activity切换效果
4、视图动画局限性
视图动画仅仅改变了控件的视图位置,并未改变控件的属性,即控件并未移动,只是看起来动了
下面我们做一个测试,打开手机显示布局边界
可以看到,新位置无法触发单击事件,控件真正位置并未移动,为此Android于API 11新加入特性——属性动画
三、属性动画(Animator)
属性动画可以对任何对象做动画
常用属性:
平移 "translationX" \ "translationY"
旋转 "rotation" \ "rotationX" \ "rotationY"
缩放 "scaleX" \ "scaleY"
位置 "X" \ "Y"
透明度 "alpha"
常用的子类有ValueAnimator、ObjectAnimator和AniamtorSet,其中ObjectAnimator继承自ValueAnimator
1、属性动画应用
ObjectAnimator.ofFloat(imageView , "translationX" , 0f , 400f).setDuration(3000).start();
ObjectAnimator.ofInt(imageView , "backgroundColor" , 0xFFFF8080 , 0XFF8080FF).setDuration(3000).start();
由以上例子可以看出,属性动画新位置触发了点击事件,即真正改变了控件位置,并且操控了新属性——背景色的变化
其他设置属性动画方法:
-PropertyValuesHodler实现效果与第一种方法一样,优点是其对动画进行了优化,更加节省系统资源
PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("translationX" , 0f , 400f);
PropertyValuesHolder p2 = PropertyValuesHolder.ofInt("backgroundColor" , 0xFFFF8080 , 0XFF8080FF);
PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("rotation" , 0 , 360);
ObjectAnimator.ofPropertyValuesHolder(imageView , p1 , p2 , p3).setDuration(3000).start();
-AnimatorSet
ObjectAnimator animator1 = ObjectAnimator.ofFloat(imageView , "translationX" , 0f , 400f);
ObjectAnimator animator2 = ObjectAnimator.ofInt(imageView , "backgroundColor" , 0xFFFF8080 , 0XFF8080FF);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(imageView , "rotation" , 0 , 360);
AnimatorSet set = new AnimatorSet();
set.setDuration(3000).start();
2、串行动画
-依次完成
set.playSequentially(animator1 ,animator2 , animator3);//串行动画
-控制完成顺序
set.play(animator1).with(animator3);
set.play(animator2).after(animator1);
效果如图,先平移并选择,完成后改变background颜色
当然,属性动画同样可以使用XML定义,位置为res/animator目录下
<?xml version="1.0" encoding="utf-8"?>
<!-- ordering 动画集合顺序,默认为together-->
<set
android:ordering="sequentially"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- propertyName 动画属性
repeatCount 重复次数 默认为 0 无限循环 -1
repeatMode 重复方式 restart 正序 reverse 倒序 -->
<objectAnimator
android:propertyName="translationX"
android:duration="1000"
android:valueFrom="0.0"
android:valueTo="400.0"
android:valueType="floatType">
</objectAnimator>
<objectAnimator
android:propertyName="backgroundColor"
android:duration="1000"
android:valueFrom="@color/colorPrimaryDark"
android:valueTo="@color/colorAccent"
android:repeatCount="-1"
android:repeatMode="reverse"
android:valueType="colorType">
</objectAnimator>
</set>
使用方法
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(TestActivity1.this , R.animator.animator);
set.setTarget(imageView);
set.start();
设置监听器
animator.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) {
}
});
//AnimatorListenerAdapter可以选择事件
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});
//AnimatorUpdateListener监听整个动画过程,每播放一帧,就会调用一次
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
}
})
3、ValueAnimator
回到属性动画的特性之一,对任意属性做动画
其需满足
1、对象提供该属性的get和set方法
2、对属性的变化需能通过某种方法反映出来
解决方法
1、给对象加上get和set方法
2、用类包装原始对象,间接提供get和set方法
3、采用ValueAnimator,监听动画过程,实现属性改变
这里我们主要讲解第3种方法
ValueAnimator本身不提供任何动画效果,其作用为一个数值发生器,用来产生具有规律的数字
使用方法:
通过ValueAnimator改变Text属性实现计时器
ValueAnimator animator = ValueAnimator.ofInt(0 , 100);
animator.setDuration(5000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Integer i = (Integer) animation.getAnimatedValue();
button.setText(i + "");
}
});
animator.start();