Android中的动画有三种,分别是补间动画、帧动画、属性动画。
Frame Animation(帧动画)主要用于播放一帧帧准备好的图片,类似GIF图片,优点是使用简单方便、缺点是需要事先准备好每一帧图片;
Tween Animation(补间动画)仅需定义开始与结束的关键帧,而变化的中间帧由系统补上,优点是不用准备每一帧,缺点是只改变了对象绘制,而没有改变View本身属性。因此如果改变了按钮的位置,还是需要点击原来按钮所在位置才有效;
Property Animation(属性动画)是3.0后推出的动画,优点是使用简单、降低实现的复杂度、直接更改对象的属性、几乎可适用于任何对象而仅非View类,缺点是需要3.0以上的API支持,限制较大。Frame Animation(帧动画)
1、介绍
优点:使用简单、方便缺点:容易引起 OOM,因为会使用大量 & 尺寸较大的图片资源
2、使用
方式1:XML实现
步骤1、在 res/anim的文件夹里创建动画效果.xml文件res/drawable/anim_drawable.xml
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <!--图片格式必须是png--> <item android:drawable="@drawable/l1" android:duration="300"/> <item android:drawable="@drawable/l2" android:duration="300"/> <item android:drawable="@drawable/l3" android:duration="300"/> <item android:drawable="@drawable/l4" android:duration="300"/> <item android:drawable="@drawable/l5" android:duration="300"/> <item android:drawable="@drawable/l6" android:duration="300"/> <item android:drawable="@drawable/l7" android:duration="300"/> </animation-list>
步骤2、设置动画资源(图片资源)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/start" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="start"/> <Button android:id="@+id/stop" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="stop"/> <ImageView android:id="@+id/mIvImg" android:layout_marginTop="50dp" android:layout_gravity="center_horizontal" android:layout_width="200dp" android:layout_height="200dp"/> </LinearLayout>
步骤3、在Java代码中载入 & 启动动画
public class FrameAnimationActivity extends Activity{ @BindView(R.id.start) Button start; @BindView(R.id.stop) Button stop; @BindView(R.id.mIvImg) ImageView mIvImg; private AnimationDrawable animationDrawable; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_animationdrawable); ButterKnife.bind(this); mIvImg.setBackgroundResource(R.drawable.anim_drawable); animationDrawable = (AnimationDrawable)mIvImg.getBackground(); } @OnClick({R.id.start,R.id.stop}) public void onClick(View v) { switch (v.getId()){ case R.id.start: start(); break; case R.id.stop: stop(); break; default: break; } } private void start(){ animationDrawable.start(); } private void stop(){ animationDrawable.stop(); } }
方式2:在Java代码中实现
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/start" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="start"/> <Button android:id="@+id/stop" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="stop"/> <ImageView android:id="@+id/mIvImg" android:layout_marginTop="50dp" android:layout_gravity="center_horizontal" android:layout_width="200dp" android:layout_height="200dp"/> </LinearLayout>步骤 2、java代码动态加载
public class FrameAnimationActivity1 extends Activity{ @BindView(R.id.start) Button start; @BindView(R.id.stop) Button stop; @BindView(R.id.mIvImg) ImageView mIvImg; private AnimationDrawable animationDrawable; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_animationdrawable1); ButterKnife.bind(this); } @OnClick({R.id.start,R.id.stop}) public void onClick(View v) { switch (v.getId()){ case R.id.start: start(); break; case R.id.stop: stop(); break; default: break; } } private void start(){ //创建帧动画 animationDrawable = new AnimationDrawable(); //添加帧 animationDrawable.addFrame(getResources().getDrawable(R.drawable.l1), 300); animationDrawable.addFrame(getResources().getDrawable(R.drawable.l2), 300); animationDrawable.addFrame(getResources().getDrawable(R.drawable.l3), 300); animationDrawable.addFrame(getResources().getDrawable(R.drawable.l4), 300); animationDrawable.addFrame(getResources().getDrawable(R.drawable.l5), 300); //设置动画是否只播放一次, 默认是false animationDrawable.setOneShot(false); //根据索引获取到那一帧的时长 int duration = animationDrawable.getDuration(2); //根据索引获取到那一帧的图片 Drawable drawable = animationDrawable.getFrame(0); //判断是否是在播放动画 boolean isRunning = animationDrawable.isRunning(); //获取这个动画是否只播放一次 boolean isOneShot = animationDrawable.isOneShot(); //获取到这个动画一共播放多少帧 int framesCount = animationDrawable.getNumberOfFrames(); //把这个动画设置为background,兼容更多版本写下面那句 mIvImg.setBackground(animationDrawable); mIvImg.setBackgroundDrawable(animationDrawable); animationDrawable.start(); } private void stop(){ animationDrawable.stop(); } }
Tween Animation(补间动画)
View动画是一种渐进式动画,定义动画开始和结束的两帧,并指定动画变化的时间和方式。并通过平移、缩放、旋转和透明度四种效果结合成复杂的动画效果。而在开始和结束帧之间插入的渐变值依据的是插值器。
1、 应用场景
(1)、标准的动画效果补间动画常用于视图View的一些标准动画效果:平移、旋转、缩放 & 透明度;
除了常规的动画使用,补间动画还有一些特殊的应用场景。
(2)、 特殊的应用场景
Activity 的切换效果
Fragement 的切换效果
视图组(ViewGroup)中子元素的出场效果
2、 应用
步骤1、创建动画效果
res/anim/rotate_demo.xml
<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:toDegrees="360"> </rotate>
步骤2、创建资源布局
res/layout/activity_tweenanimation.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/mcreateRotateAnimation" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="旋转"/> <Button android:id="@+id/mcreateScaleAnimation" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="放大缩小"/> <Button android:id="@+id/mcreateTranslateAnimation" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="平移"/> <Button android:id="@+id/mcreateAlphaAnimation" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="透明"/> <Button android:id="@+id/mcreateSetAnimation" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="组合"/> <ImageView android:id="@+id/mTv" android:layout_width="200dp" android:layout_height="200dp" android:src="@drawable/l2"/> </LinearLayout>
步骤3、java代码触发动画
/** * 创建旋转动画 */ private void createRotateAnimation() { // 步骤2:创建 动画对象 并传入设置的动画效果xml文件 Animation ratateAnimation = AnimationUtils.loadAnimation(this, R.anim.rotate_demo); // 步骤3:播放动画 mTv.startAnimation(ratateAnimation); // 步骤4:监听动画 ratateAnimation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { Log.e(tag, "1=================Start"); } @Override public void onAnimationRepeat(Animation animation) { Log.e(tag, "1=================Repeat"); } @Override public void onAnimationEnd(Animation animation) { Log.e(tag, "1=================End"); } }); }
Property Animation(属性动画)
数值发生器 -- ValueAnimator类
定义:属性动画机制中 最核心的一个类实现动画的原理:通过不断控制 值 的变化,再不断 手动 赋给对象的属性,从而实现动画效果。
从上面原理可以看出:ValueAnimator类中有3个重要方法:
ValueAnimator.ofInt(int values)
ValueAnimator.ofFloat(float values)
ValueAnimator.ofObject(int values)
1、ValueAnimator.ofInt(int values)
作用:将初始值 以整型数值的形式 过渡到结束值
即估值器是整型估值器 - IntEvaluator
估值器 -- TypeEvaluator
插值器(Interpolator)决定 值 的变化模式(匀速、加速blabla)
估值器 -- TypeEvaluator
估值器(TypeEvaluator)决定 值 的具体变化数值
举例-- ValueAnimator.ofInt
private void doAnimator() { final int top = m1.getTop(); final int left = m1.getLeft(); final int width = m1.getMeasuredWidth(); final int height = m1.getMeasuredHeight(); ValueAnimator animator = ValueAnimator.ofInt(0, 400,0,300,0,200,0,100,0,50,0,40,0,30,0,20,0,10,0,5,0); // 设置动画运行的时长 animator.setDuration(4000); //多久后开始动画 animator.setStartDelay(0); //循环次数 animator.setRepeatCount(5); //无穷循环 // animator.setRepeatCount(ValueAnimator.INFINITE); //repeat的时候正向重新计算 animator.setRepeatMode(ValueAnimator.RESTART); //repeat的时候反向重新计算 // animator.setRepeatMode(ValueAnimator.REVERSE); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { // 获得改变后的值 int value = (int) valueAnimator.getAnimatedValue(); // 将改变后的值赋给对象的属性值 m1.layout(left,top-value,left+width,top-value+height); } }); animator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { Log.e(tag,"onAnimation Start"); } @Override public void onAnimationEnd(Animator animator) { Log.e(tag,"onAnimation End"); } @Override public void onAnimationCancel(Animator animator) { Log.e(tag,"onAnimation Cancel"); } @Override public void onAnimationRepeat(Animator animator) { Log.e(tag,"onAnimation Repeat"); } }); animator.start(); }
举例-- 插值器和估值器
/** * 抛物线 * @param view */ public void paowuxian(View view) { ValueAnimator valueAnimator = new ValueAnimator(); valueAnimator.setDuration(3000); valueAnimator.setObjectValues(new PointF(0, 0)); valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.setEvaluator(new TypeEvaluator<PointF>() { // fraction = t / duration @Override public PointF evaluate(float fraction, PointF startValue, PointF endValue) { Log.e(tag, fraction * 3 + ""); // x方向200px/s ,则y方向0.5 * 10 * t PointF point = new PointF(); point.x = 200 * fraction * 3; point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3); return point; } }); valueAnimator.start(); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { PointF point = (PointF) animation.getAnimatedValue(); m1.setX(point.x); m1.setY(point.y); } }); valueAnimator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { Log.e(tag,"onAnimation Start"); } @Override public void onAnimationEnd(Animator animator) { Log.e(tag,"onAnimation End"); } @Override public void onAnimationCancel(Animator animator) { Log.e(tag,"onAnimation Cancel"); } @Override public void onAnimationRepeat(Animator animator) { Log.e(tag,"onAnimation Repeat"); } }); }
源码:
https://github.com/yuanhhyuan/UI4
参考文章:
Android 逐帧动画:关于 逐帧动画 的使用都在这里了!
https://www.jianshu.com/p/225fe1feba60
Android 动画:手把手教你使用 补间动画
https://www.jianshu.com/p/733532041f46
Property Animation(属性动画)
https://www.jianshu.com/p/2412d00a0ce4