View的动画的分类
- 补间动画BetweenAnimation,也就是我们以前一般的Animation。
- 帧动画FrameAnimation,通过animation-list实现。
- 属性动画PropertyAnimation,从3.0及以后出现的(如果要兼容低版本,可以使用一个民间版第三方的一个jar NineOldAndroid.jar,用法跟系统的用法差不多)。不断地控制控件的属性变化达到动画的效果,一般我们是一些组合的属性动画达到复杂的效果。
属性动画的优势
相对于前面的动画,属性动画更加丰富、好用;属性动画是真实地改变控件的属性,一般的view动画是个假象,平移以后的原来位置还是可以点击的(平移之后的位置不可点击)。
补间动画示例
- 补间动画支持四种类型:平移(Translate)、旋转(Rotate)、缩放(Scale)、不透明度(Alpha)。
- 只是显示的位置变动,View的实际位置未改变,表现为View移动到其他地方,点击事件仍在原处才能响应。
- 组合使用步骤较复杂。
- View Animation 也是指此动画。
一般来说动画都可以在xml中定义,也可以用纯Java实现,但是一般前者用得比较多。
下面以平移动画为例介绍补间动画。
首先在res下创建anim文件夹,创建动画的xml:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500"
android:fillAfter="true"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="50%p"
android:toYDelta="50%p">
</translate>
然后就可以在代码中使用了:
Animation animation = AnimationUtils.loadAnimation(this, R.anim.translate);
iv_icon.startAnimation(animation);
帧动画示例
帧动画一般来说是实现一些复杂的动画,通过图片的变化实现。
- 用于生成连续的Gif效果图。
- DrawableAnimation也是指此动画。
首先创建drawable:
<?xml version="1.0" encoding="utf-8"?>
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true">
<item
android:drawable="@drawable/bga_refresh_mt_refreshing_01"
android:duration="200"/>
<item
android:drawable="@drawable/bga_refresh_mt_refreshing_02"
android:duration="200"/>
<item
android:drawable="@drawable/bga_refresh_mt_refreshing_03"
android:duration="200"/>
<item
android:drawable="@drawable/bga_refresh_mt_refreshing_04"
android:duration="200"/>
<item
android:drawable="@drawable/bga_refresh_mt_refreshing_05"
android:duration="200"/>
<item
android:drawable="@drawable/bga_refresh_mt_refreshing_06"
android:duration="200"/>
<item
android:drawable="@drawable/bga_refresh_mt_refreshing_07"
android:duration="200"/>
<item
android:drawable="@drawable/bga_refresh_mt_refreshing_08"
android:duration="200"/>
</animation-list>
然后在代码中使用(注意:AnimationDrawable播放动画是依附在window上面的,而在Activity onCreate方法中调用时Window还未初始化完毕,所有才会停留在第一帧,要想实现播放必须在onWindowFocusChanged中播放):
iv_icon.setImageResource(R.drawable.frame_anim);
AnimationDrawable drawable = (AnimationDrawable) iv_icon.getDrawable();
drawable.start();
通过AnimationDrawable可以自由地操作动画,这里就不再赘述了。
属性动画详解
- 支持对所有View能更新的属性的动画(需要属性的setXxx()和getXxx())。
- 更改的是View实际的属性,所以不会影响其在动画执行后所在位置的正常使用。
- Android3.0 (API11)及以后出现的功能,3.0之前的版本可使用github第三方开源库nineoldandroids.jar进行支持。
原理:就是一段时间内通过不断改变View的属性,从而形成动画。
常用API
ObjectAnimator :对象动画执行类。
- PropertyValuesHolder : 属性存储器,为两个执行类提供更新多个属性的功能。
- AnimatorListener :动画执行监听,在动画开始、重复、结束、取消时进行回调。
- Keyframe :为 PropertyValuesHolder提供多个关键帧的操作值。
- AnimatorSet :一组动画的执行集合类:设置执行的先后顺序,时间等。
- TimeInterpolator :时间插值,用于控制动画执行过程。
- ValueAnimator :值动画执行类,常配合AnimatorUpdateListener使用。
- AnimatorUpdateListener :动画更新监听。
- TypeEvaluator :类型估值,用于设置复杂的动画操作属性的值。
插值器
常用的插值器有:
![](https://i-blog.csdnimg.cn/blog_migrate/3fe447435180b4b27800fed4adda6ccb.webp?x-image-process=image/format,png)
1.png
坐标图如下:
![](https://i-blog.csdnimg.cn/blog_migrate/91f3e5497abffb354eb3d6cd8e4528a7.webp?x-image-process=image/format,png)
1.png
基本的属性动画
View的属性如果过setXXX的话,就可以实现属性动画。通过ObjectAnimator的ofArgb、ofFloat、ofMultiFloat、MultiInt可以实现颜色、不同精度的动画。
下面是一些常见的属性动画:
//平移
ObjectAnimator oa = ObjectAnimator.ofFloat(iv_icon, "translationX", 0f, 300f);
//设置插值器
oa.setInterpolator(new BounceInterpolator());
oa.setDuration(500);
oa.start();
//旋转
ObjectAnimator oa = ObjectAnimator.ofFloat(iv_icon, "rotationX", 0f, 360f);
oa.setDuration(500);
oa.start();
//缩放
ObjectAnimator oa = ObjectAnimator.ofFloat(iv_icon, "ScaleX", 1f, 0.5f);
oa.setDuration(500);
oa.start();
//渐变
ObjectAnimator oa = ObjectAnimator.ofFloat(iv_icon, "Alpha", 1f, 0.5f);
oa.setDuration(500);
oa.start();
组合属性动画
方法一、设置监听
ObjectAnimator animator = ObjectAnimator.ofFloat(iv_icon, "none", 0f, 100f);
animator.setDuration(300);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//动画在执行的过程当中,不断地调用此方法
animation.getAnimatedFraction()//百分比
//得到duration时间内 values当中的某一个中间值。0f~100f
float value = (float) animation.getAnimatedValue();//
iv_icon.setScaleX(0.5f + value / 200);//0.5~1
iv_icon.setScaleY(0.5f + value / 200);//0.5~1
}
});
//当然也可以监听动画的执行
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) {
}
});
方法二、使用ValueAnimator
实质同方法一。
ValueAnimator animator = ValueAnimator.ofFloat(0f, 200f);
animator.setDuration(200);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//动画在执行的过程当中,不断地调用此方法
animation.getAnimatedFraction();//百分比
//得到duration时间内 values当中的某一个中间值。0f~100f
float value = (float) animation.getAnimatedValue();//
iv_icon.setScaleX(0.5f + value / 200);//0.5~1
iv_icon.setScaleY(0.5f + value / 200);//0.5~1
}
});
animator.start();
方法三、使用PropertyValuesHolder
//float... values:代表关键帧的值
PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("alpha", 1f,0.7f,1f);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleX", 1f,0.7f,1f);
PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("scaleY", 1f,0.7f,1f);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(iv_icon, holder1,holder2,holder3);
animator.setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedValue = (float) animation.getAnimatedValue();
float animatedFraction = animation.getAnimatedFraction();
long playTime = animation.getCurrentPlayTime();
System.out.println("animatedValue:"+animatedValue+", playTime:"+playTime);
}
});
animator.start();
方法四、使用AnimatorSet
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(500);
animatorSet.play(animator1);//执行单个动画
animatorSet.playTogether(animator1,animator2,animator3);//同时执行
animatorSet.playSequentially(animator1,animator2,animator3);//依次执行动画
//真正开始执行
animatorSet.start();
综合案例,实现水平抛出
/**
* x:匀速
* y:加速度 y=1/2*g*t*t
* 使用估值器最好实现。
*/
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(4000);
// valueAnimator.setFloatValues(values)
valueAnimator.setObjectValues(new PointF(0, 0));
//估值器---定义计算规则
valueAnimator.setEvaluator(new TypeEvaluator<PointF>() {
@Override
public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
//拿到每一个时间点的坐标
//x=v*t (s秒)
PointF pointF = new PointF();
float time = fraction * 10;
pointF.x = 100f * time;//初始速度*(执行的百分比*4,即时间t)
pointF.y = 0.5f * 9.8f * time * time;
return pointF;
}
});
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//得到此时间点的坐标
PointF pointF = (PointF) animation.getAnimatedValue();
iv_icon.setX(pointF.x);
iv_icon.setY(pointF.y);
}
});
valueAnimator.start();