
基础
视图动画可以在一个视图容器内执行一系列简单变换(位置、大小、旋转、透明度),包括
- TranslateAnimation
- ScaleAnimation
- RotateAnimation
- AlphaAnimation
例外还有AnimationSet,一个持有其它动画元素 alpha、scale、translate、rotate 或者其它 set 元素的容器。
既可以通过xml来设置,也可以通过代码来控制。比较推荐的方式是xml方法。在res新建anim包
命名
anim 资源名称以小写单词+下划线的方式命名,采用以下规则:
模块名_逻辑名称 _ [方向|序号]
Tween 动画(使用简单图像变换的动画,例如缩放、平移)资源:尽可能以通用的动画名称命名,如 module_fade_in , module_fade_out , module_push_down_in (动画+方向)。
<set
android:duration="10000" 单位毫秒
android:fillAfter="true/false" 结束是否停留在当前位置
android:fillBefore="true/false"
android:interpolator="" 设定插值器
android:shareInterpolator="true /false"> 是否共用插值器
<alpha
android:fromAlpha="float" 动画开始的透明度(0.0到1.0,0.0是全透明,1.0是不透明)
android:toAlpha="float"/>
<scale
android:fromXScale="float" 水平方向缩放的起始值 比例
android:toXScale="float"
android:fromYScale="float"
android:toYScale="float"
android:pivotX="float" 缩放轴点的x坐标
android:pivotY="float"/>
<rotate
android:fromDegrees="float" 起始旋转角度 0 旋转开始角度,正代表顺时针度数,负代表逆时针度数
android:toDegrees="float" 比如180
android:pivotY="float"
android:pivotX="float"/>
旋转起点X轴坐标(数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以父控件的左上角加上父控件宽高的50%做为初始点)
<translate
android:fromXDelta="float" x的起始值
android:toXDelta="float" x的结束值
android:fromYDelta="float" y的起始值
android:toYDelta="float"/> y的结束值
</set>
代码调用
Animation anim= AnimationUtils.loadAnimation(this, R.anim.set);
view.startAnimation(anim);
举例view从top位置到原位置
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fillAfter="false" >
<translate
android:fromYDelta="-100%"
android:toYDelta="0%"/>
</set>
或者代码控制
TranslateAnimation translate = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f,
Animation.RELATIVE_TO_SELF, -1f, Animation.RELATIVE_TO_SELF, 0f );
translate.setDuration(2000);
mButton.startAnimation(translate);
//Animation.RELATIVE_TO_SELF(相对于自身)、Animation.RELATIVE_TO_PARENT(相对于父控件(容器))
另外在上面y是负,在左边x是负,跟手机坐标系一致
其他的方法
方法 | 解释 |
---|---|
reset() | 初始化 |
cancel() | 取消 |
start() | 开始 |
setAnimationListener | 设置监听 |
记自己犯的一个错误,貌似是 因为我对anim多次赋值,导致我调用cancel,动画无法暂停,因为对象不对。
其他
Q:View视图动画为何不能改变View的位置?
补间动画执行之后并未改变 View 的真实布局属性值,产生的动画数据实际是应用在canvas。切记这一点,譬如我们在 Activity 中有一个 Button 在屏幕上方, 我们设置了平移动画移动到屏幕下方然后保持动画最后执行状态呆在屏幕下方,这时如果点击屏幕下方动画执行之后的 Button 是没有任何反应的, 而点击原来屏幕上方没有 Button 的地方却响应的是点击Button的事件。
出自阿里巴巴android开发手册
在有强依赖onAnimationEnd回调的交互时,如播放完毕才能操作页面时,onAnimationEnd可能因为各种异常没有回调,建议加上超时保护或通过postDelay替代onAnimationEnd
new Handler().postDelay(new Runnable(){
public void run(){
if(view!=null){
v.clearAnimation();
}
}
})
View的annimation动画结束时,通过clearAnimation释放资源
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if(mButton!=null){
mButton.clearAnimation(); //判断资源是否被释放了
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
帧动画
帧动画 实现像播放幻灯片一样的效果,类似于gif图。它最大的问题还是容易引起OOM的问题
帧动画AnimationDrawable的真正父类是Drawable,所以
在drawable中添加frame.xml。文件的标签是<animation-list>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:duration="500" android:drawable="@drawable/a"/>
<item android:duration="500" android:drawable="@drawable/b"/>
<item android:duration="500" android:drawable="@drawable/c"/>
<item android:duration="500" android:drawable="@drawable/d"/>
<item android:duration="500" android:drawable="@drawable/e"/>
</animation-list>
注意
设置ImageView的background为frame.xml,而不是src
使用
AnimationDrawable drawable = (AnimationDrawable) mImageView.getBackground();
drawable.start();
尽量不要使用AnimationDrawable ,它在初始化的时候将所有的图片加载到内存中,特别占内存,而且不能释放。释放后下次加载会报错
加载gif
可以通过Glide等开源框架,也可以参考Android自定义View播放Gif动画,主要使用了android.graphics.Movie这个类来加载Gif动画, setTime(int relativeMilliseconds) 设置movie当前处在什么时间,然后找到对应时间的图片帧,范围0 ~ duration。返回是否成功找到那一帧。里面提到一个变量SystemClock.uptimeMillis() // 从开机到现在的毫秒数(手机睡眠的时间不包括在内)
属性动画
通过在一段时间间隔内完成对象从一个属性值到另一个属性值的改变,来实现动画效果
最核心的类有
- ValueAnimator 实现了整个动画处理逻辑
- ObjectAnimator 继承自ValueAnimator
- AnimatorSet 动画的集合
代码
举例1. 改变一个对象的透明度
ObjectAnimator animator = ObjectAnimator.ofFloat(mImageView, "alpha",1f,0f);
animator.setDuration(2000);
animator.start();
举例2.绕着x轴旋转
ValueAnimator va=ValueAnimator.ofFloat(0,90); //控制value值从0到90
va.setDuration(5000);
va.start();
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { //设置动画监听
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float v = (float) animation.getAnimatedValue(); //拿到0~90之间的某个值 动态的给属性赋值
mImageView.setRotationX(v); //或者va.setTarget(mImageView.getRotationX());然后这边直接mImageView.invalidate();
}
});

举例3. 对view进行缩放平移都改变
AnimatorSet set = new AnimatorSet();
set.playTogether{
ObjectAnimator animator = ObjectAnimator.ofFloat(mImageView, "scaleX",1f,1.5f);
ObjectAnimator animator = ObjectAnimator.ofFloat(mImageView, "translationX",0,90);
}
set.setDuration(5000).start();
或者
set.play(animator 1).with(animator 2).before(animator 3).after(animator 4).start();
xml控制
在res目录下建animator资源文件夹
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together/sequentially"> together 同时播放 sequentially集合中的顺序播放
<objectAnimator 对应objectAnimator
android:propertyName="translateY" 对象的属性名称
android:duration="1000"
android:valueFrom="-100"
android:valueTo="0"
android:startOffset="1000" 动画延迟时间
android:repeatCount="-1" 默认0, -1代表无限循环
android:repeatMode="restart"
android:valueType="intType"/> propertyName属性的类型
<animator 对应ValueAnimator 但是没有propertyName属性
..../>
</set>
使用动画:
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.set_animation);
// 载入XML动画
animator.setTarget(view); // 设置动画对象
animator.start();
说明
控件的属性需要提供set get方法,因为他是通过反射来实现。如果没有对应get,set的方法,可以通过AnimatorUpdateListener来实现
动画监听
View设置监听
view.addAnimatorUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
}
});
view.addAnimatorListener(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) {
}
});
或者属性动画设置监听
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
}
});
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) {
}
});
网友评论