动画模式在android系统中被分为三类,分别为:

  1. tween(view) animation:补间动画
  2. frame(drawable) animation:逐帧动画
  3. property animation:属性动画

本章节分别对齐进行解读。

1 Tween Animation

1.1 Tween Animation基础

Animation是以XML格式定义的,XML文件存放在路径res/anim下。这里按照XML文档的结构{父节点|子节点|属性}来介绍Tween Animation。先介绍Tween Animation共同的节点属性,如下所示:

Tween Animation由4种基本动画组成:Alpha(渐变透明度)、Scale(缩放)、Translate(位置移动)、Rotate(旋转),同时Animation类还有AlphaAnimation、ScaleAnimation、 TranslateAnimation、RotateAnimation 4个子类与之分别对应,每个子类都在父类的基础上增加了各自独有的属性。分别解读如下:

@1 Alpha属性说明:

@2 Scale属性说明:

@3 Translate属性说明:

@4 Rotate属性说明:

1.2 Tween Animation的用法

Tween Animation的用法有2种:从XML文件中读取 和 代码中设置/读取。

@1 代码中直接从XML资源中读取Animation并使用

用XML定义的动画放在/res/anim/文件夹内,XML文件的根元素可以为<alpha>,<scale>,<translate>,<rotate>, interpolator元素 或<set>(表示以上几个动画的集合,set可以嵌套)。默认情况所有动画是同时进行的,可以通过startOffset属性设置各个动画的开始偏移(开始时间)来达到动画顺序播放的效果。定义好动画XML文件后通过代码对指定的View应用该动画。如下所示:

ImageView XXXImage = (ImageView)findViewById(R.id.spaceshipImage);
Animation yyyAnimation=AnimationUtils.loadAnimation(this,R.anim.yyy);
XXXImage.startAnimation(yyyAnimation);

@2 通过代码设置Tween Animation属性

代码中使用Animation子类来初始化Animation对象。Animation基类包含大量的set/getXXX()函数来设置/读取Animation的属性。相关方法可参照文档:Android Animation XML属性。

Tween Animation关于动画相关的方法可参照文档:Android Animation method解读。

1.3 动画的运行控制与模式

@1 Interpolator

动画的进度使用 Interpolator来控制,interpolator定义一个动画的变化率,用于在运行时控制动画。这使得基本的动画效果(alpha, scale, translate, rotate)得以加速,减速,重复等。Interpolator 是基类,封装了所有 Interpolator 的共同方法,它只有一个方法,即 getInterpolation (float input),该方法提供了几个Interpolator 子类,实现了不同的速度曲线,如下:

说明:对于 LinearInterpolator ,变化率是个常数,即f(x) = x。Interpolator其他的几个子类,也都是按照特定的算法,实现了对变化率。还可以定义自己的Interpolator子类,实现抛物线、自由落体等物理效果。

@2 动画运行模式

  • 独占模式:程序主线程进入一个循环,根据动画指令不断刷新屏幕,直到动画结束。
  • 中断模式:单独线程对时间计数,隔一段时间给主线程发通知,主线程接到通知后更新屏幕。

@3 动画实现原理

  • Transformation记录了仿射矩阵Matrix,动画每触发一次,会对原来的矩阵做一次运算, View的Bitmap与这个矩阵相乘就可实现相应的操作(旋转、平移、缩放等)。
  • 图形变换通过仿射矩阵实现。图形变换是图形学中的基本知识,简单来讲,每种变换都是一次矩阵运算。在 Android中,Canvas 类中包含当前矩阵,当调用Canvas.drawBitmap(bmp, x, y, Paint)绘制时,Android会先把bmp做一次矩阵运算,然后将运算的结果显示在Canvas上。之后只需不断修改Canvas的矩阵并刷新屏幕,View里的对象就会不停的做图形变换,因此就形成了动画。

2 Frame Animation

Android用AnimationDrawable类来定义和使用Frame Animation。它可以在XML Resource定义(还是存放到res/anim文件夹下),也可以使用AnimationDrawable中的API定义。与Tween Animation不同,Frame Animation是顺序播放事先做好的图像,通过一系列Drawable依次显示来模拟动画的效果。在XML中的定义方式如下:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"android:oneshot="true"><item android:drawable="@drawable/XXX1" android:duration="200" />...
</animation-list>

说明:必须以<animation-list>为根元素,以<item>表示要轮换显示的图片,duration属性表示各项显示的时间。XML文件要放在/res/drawable/

@2 Drawable Animation使用示例:

定义一帧一帧的动画item,配置如下所示:

<animation-list xmlns:android=”http://schemas.android.com/apk/res/android”
android:oneshot=”true”><item android:drawable=”@drawable/XXX1″ android:duration=”200″ /><item android:drawable=”@drawable/XXX2″ android:duration=”200″ /><item android:drawable=”@drawable/XXX3″ android:duration=”200″ />
</animation-list>

其包含3帧动画,3帧动画中分别应用了drawable中的3张图片:XXX1、XXX2、XXX3,每帧动画持续200毫秒。然后我们将以上XML保存在res/anim/文件夹下,命名为XXX.xml。

编写代码,显示动画的代码如下:

protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);imageView = (ImageView) findViewById(R.id.imageView);imageView.setBackgroundResource(R.drawable.drawable_anim);anim = (AnimationDrawable) imageView.getBackground();
}public boolean onTouchEvent(MotionEvent event) {if (event.getAction() == MotionEvent.ACTION_DOWN) {anim.stop();anim.start();return true;}return super.onTouchEvent(event);
}

注意:

  • 调用Imageview的setBackgroundResource方法,如果直接在XML布局文件中设置其src属性,当触发动画时会ForceClose问题。
  • 在start()前要先stop(),不然第一次动画运行后会停在最后一帧,这样动画就只会触发一次。
  • 不要在onCreate中调用start,因为AnimationDrawable还没有完全跟Window相关联,如果想要界面显示时就开始动画的话,可以在onWindowFoucsChanged()中调用start()。

@3 阅读Android 文档中对AnimationDrawable的介绍,关键内容整理如下:

更多关于AnimationDrawable的介绍,查看文档:Android AnimationDrawable详细解读

注意:Frame Animation 的XML 文件中不定义 interpolator 属性,因为定义它没有任何意义。

3 Animator

Animator代表一个属性动画,但是它只是一个抽象类。我们通常会使用它的子类:AnimatiorSet、ValueAnimator、ObjectAnimator、TimeAnimator。XML文件应放在res/animator/中。

3.1 属性动画的工作方式

@1 属性动画,它更改对象的实际属性。

在Tween Animation中,其改变的是View的绘制效果,View的属性保持不变,比如无论你在对话中如何缩放Button的大小,Button有效点击区域还是没有应用动画时的区域,其位置与大小都不变。在属性动画中,改变的是对象的实际属性,如Button的缩放,Button的位置与大小属性值都改变了。且属性动画不止可以应用于View,还可以应用于任何对象。属性动画只是表示一个值在一段时间内的改变,当值改变时要做什么事情由我们来决定。

@2 在Property Animation中,可以对动画应用以下属性:

3.2 常见属性动画解读&代码使用实例

3.2.1 ValueAnimator动画(代码实现机制)

整个属性动画机制当中最核心的一个类,属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等,是一个非常重要的类。但是ValueAnimator的用法却一点都不复杂,实例(将一个值从0平滑过渡到1,时长300毫秒,就可以这样写)如下:

ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(300);
anim.start();  

3.2.2 ObjectAnimator动画(代码实现机制)

相比于ValueAnimator,ObjectAnimator更常用,ValueAnimator不过是对值进行了平滑的动画过渡。而ObjectAnimator(继承自ValueAnimator)可以直接对任意对象的任意属性进行动画操作。

@1 alpha案例

一个TextView在5秒中内从常规变换成全透明,再从全透明变换成常规,代码如下:

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
animator.setDuration(5000);
animator.start();  

@2 rotation案例

将TextView进行一次360度的旋转,将@1中第二个参数改成"rotation",然后将动画的初始值和结束值分别设置成0和360,代码如下:

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
animator.setDuration(5000);
animator.start();  

@3 translation案例

将TextView先向左移出屏幕,然后再移动回来,代码如下:

float curTranslationX = textview.getTranslationX();
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "translationX",curTranslationX, -500f, curTranslationX);
animator.setDuration(5000);
animator.start(); 

先是调用了TextView的getTranslationX()方法来获取到当前TextView的translationX的位置,然后ofFloat()方法的第二个参数传入"translationX",后面三个参数用于告诉TextView如何移动。

@4 Scale实例

将TextView在垂直方向上放大3倍再还原,将ofFloat()方法的第二个参数改成了"scaleY",表示在垂直方向上进行缩放,代码如下:

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "scaleY", 1f, 3f, 1f);
animator.setDuration(5000);
animator.start();  

@5  特殊说明

关于 ofFloat()方法的第二个参数传递参数:不局限于alpha、rotation、translationX和scaleY这些值,我们可以传入任意值到ofFloat()方法的第2个参数。因为ObjectAnimator在设计的时候就没有针对于View来进行设计,而是针对于任意对象的,它所负责的工作就是不断地向某个对象中的某个属性进行赋值,然后对象根据属性值的改变再来决定如何展现出来。

3.2.3 组合动画

@1 基本概念

独立动画实现的视觉效果有限,因此将多个动画组合到一起播放就显得尤为重要。实现组合动画主要借助AnimatorSet这个类,这个类提供了一个play()方法,传入Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder实例,AnimatorSet.Builder中包括以下四个方法:

after(Animator anim)    //将现有动画插入到传入的动画之后执行。
after(long delay)       //将现有动画延迟指定毫秒后执行。
before(Animator anim)   //将现有动画插入到传入的动画之前执行。
with(Animator anim)     //将现有动画和传入的动画同时执行。

有这四个方法,我们就可以完成组合动画的逻辑。

@2 使用实例

这里让TextView先从屏幕外移动进屏幕,然后开始旋转360度,旋转的同时进行淡入淡出操作,关键代码如下所示:

ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f);
ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
AnimatorSet animSet = new AnimatorSet();
animSet.play(rotate).with(fadeInOut).after(moveIn);
animSet.setDuration(5000);
animSet.start();     

先创建三个动画对象,然后new出一个AnimatorSet对象后将这三个动画对象进行播放排序,让旋转和淡入淡出动画同时进行,并把它们插入到了平移动画的后面,最后设置动画时长及启动动画。

3.3 属性动画XML使用实例

3.3.1 ValueAnimator动画使用实例

ValueAnimator代码和xml设置中,因为不是操作对象,所以没有setPropertyName,只是根据value进行某种动作需要加监听器,监听值的变化做相应的处理。xm配置如下:

<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"   android:interpolator="@android:anim/accelerate_interpolator"  android:duration="10000"  android:startOffset="1000"  android:repeatCount="infinite"  android:repeatMode="restart"  android:valueFrom="1"  android:valueTo="100"  android:valueType="intType">
</animator>  

加载XML动画,关键代码实现如下:

ValueAnimator valueAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(this, R.animator.animator);
valueAnimator.setTarget(tv_num);
valueAnimator.setEvaluator(new TypeEvaluator<Integer>() {  @Override   public Integer evaluate(float fraction, Integer startValue, Integer endValue) {  System.out.println("时间比率,fraction:" + fraction);  System.out.println("结果值:" + (int)((startValue + fraction * (endValue - startValue)) / 10 * 10));  return (int)((startValue + fraction * (endValue - startValue)) / 10 * 10);  }
});
valueAnimator.addUpdateListener(new AnimatorUpdateListener() {  @Override  public void onAnimationUpdate(ValueAnimator animation) {  //在onAnimationUpdate中 该值返回第一个动画的 当前帧的evaluate 值  System.out.println("animation.getAnimatedValue()==" + animation.getAnimatedValue());  tv_num.setText(animation.getAnimatedValue() + "");  }
});
valueAnimator.start();  

3.3.2 ObjectAnimator动画XML的使用实例

动画XML定义如下:

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"  android:duration="2000"  android:propertyName="scaleX"  android:repeatCount="1"  android:repeatMode="reverse"  android:valueFrom="1.0"  android:valueTo="2.0" >
</objectAnimator> 

加载XML动画,关键代码如下所示:

imageview_scale.setBackground(getResources().getDrawable(R.drawable.a11));
ObjectAnimator scaleAnimator = (ObjectAnimator) AnimatorInflater.loadAnimator(this, R.animator.scale_object_animator);
scaleAnimator.setTarget(imageview_scale);//设置动画作用的目标对象
scaleAnimator.setDuration(1000);
scaleAnimator.setRepeatCount(50);
scaleAnimator.start();  

3.3.3 AnimatorSet 动画集

由ObjectAnimator 和 ValueAnimator 组成,对应的xml中的写法类似为

<set> <objectAnimator /> ... <animator />... </set>

xml定义动画集一般在文件夹res/animator下,这里是res/animator/set_rotate_scale.xml

@1 XML配置文件定义如下:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"   android:ordering="together"><!-- android:ordering  together表示同时运行动画,  sequentially 表示按顺序执行以下动画 -->  <set>  <objectAnimator  android:propertyName="rotationX"  android:repeatCount="50"  android:repeatMode="reverse"  android:valueFrom="0"  android:valueTo="20" />  <objectAnimator  android:propertyName="rotationY"  android:repeatCount="50"  android:repeatMode="reverse"  android:valueFrom="0"  android:valueTo="45"  android:valueType="floatType" />  </set>  <set>  <objectAnimator  android:propertyName="scaleX"  android:repeatCount="50"  android:repeatMode="reverse"  android:valueFrom="1.0"  android:valueTo="2.0" >  </objectAnimator>  <objectAnimator  android:propertyName="scaleY"  android:repeatCount="50"  android:repeatMode="reverse"  android:valueFrom="1.0"  android:valueTo="2.0" >  </objectAnimator>  </set>
</set>

加载XML动画集,代码实现如下:

imageview_rotate.setBackground(getResources().getDrawable(R.drawable.a11));
AnimatorSet animatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.set_rotate_scale);
animatorSet.setTarget(imageview_rotate);
animatorSet.setDuration(1000);
animatorSet.setInterpolator(new BounceInterpolator());//设置end时的弹跳插入器
animatorSet.start();

更多关于动画的内容可查看文档:Android 动画解读

4 Animator监听器

若我们希望监听到动画事件,动画何时开始,何时结束,然后在开始或者结束的时候去执行一些逻辑处理。这个功能是完全可以实现的,Animator类当中提供了一个addListener()方法,这个方法接收一个AnimatorListener,我们只需要去实现这个AnimatorListener就可以监听动画的各种事件了。

只要是继承自Animator的,addListener()这个方法算是个通用的方法,添加一个监听器的代码如下所示:

anim.addListener(new AnimatorListener() {  @Override  public void onAnimationStart(Animator animation) {/*动画开始时*/}  @Override  public void onAnimationRepeat(Animator animation) {/*动画重复时*/}  @Override  public void onAnimationEnd(Animator animation) {/*动画结束时*/}  @Override  public void onAnimationCancel(Animator animation) {/*动画取消时*/}
});  

但是也许很多时候我只想要监听动画响应的单一事件,那么可以使用AnimatorListenerAdapter,使用这个类就可以解决掉实现接口繁琐的问题了,如下所示:

anim.addListener(new AnimatorListenerAdapter() {});  

这里我们向addListener()方法中传入这个适配器对象,由于AnimatorListenerAdapter中已经将每个接口都实现好了,所以这里不用实现任何一个方法也不会报错。那么如果想监听动画结束这个事件,就只需要单独重写这一个方法就可以了,如下所示:

anim.addListener(new AnimatorListenerAdapter() {  @Override  public void onAnimationEnd(Animator animation) {  }
});  

Android APP完整基础教程(13)应用资源-动画相关推荐

  1. Android APP完整基础教程(17)图形系统-SurfaceView

    1 SurfaceView的绘图机制 @1 理解SurfaceView 为什么要使用SurfaceView,而不是直接使用View? 这里要考虑到动态场景和静态场景的差异,相对于动态场景: View组 ...

  2. 2022 最新 Android 基础教程,从开发入门到项目实战【b站动脑学院】学习笔记——第二章:Android App 开发基础

    第 2 章 Android App开发基础 本章介绍基于Android系统的App开发常识,包括以下几个方面:App开发与其他软件开发有什么不一 样,App工程是怎样的组织结构又是怎样配置的,App开 ...

  3. Android APP 快速开发教程(安卓)

    Android APP 快速开发教程(安卓) 前言 本篇博客从开发的角度来介绍如何开发一个Android App,需要说明一点是,这里只是提供一个如何开发一个app的思路,并不会介绍很多技术上的细节, ...

  4. 《Android 移动应用基础教程(Android Studio)(第2版)》【课本客观题】+【学习通2023春】【参考答案】

    文章目录 超星学习通智能终端软件开发(基于Android Studio环境)章节作业(39) 一 二 三 四 五 六 课本一 课本二 课本三 课本四 课本五 课本六(无) 课本七 课本八 课本九 课本 ...

  5. Android App开发基础

    Android App开发基础 App的开发特点 (1)App的运行环境 1.使用数据线把手机连到电脑上 2.在电脑上安装手机的驱动程序 3.打开手机的开发者选项并启用USB调试 4.将连接的手机设为 ...

  6. 《Android移动应用基础教程》(Android Studio)(第二版)黑马程序员 课后习题答案

    <Android移动应用基础教程>(Android Studio)(第二版)黑马程序员 课后习题答案 目录 第1章 Android基础入门 第2章 Android常见界面布局 第3章 An ...

  7. 傻瓜式Android APP开发入门教程

    这篇文章主要介绍了Android APP开发入门教程,从SDK下载.开发环境搭建.代码编写.APP打包等步骤一一讲解,非常简明的一个Android APP开发入门教程,android各种机子和rom的 ...

  8. android移动应用基础教程--qq账号与密码

    android移动应用基础教程--qq账号与密码 android移动应用基础教程p115案例 实战演练-保存QQ账号密码. activity_main.xml <?xml version=&qu ...

  9. 创建android程序时 默认使用布局是,《Android移动应用基础教程》中国铁道出版社课后习题(附答案)...

    <Android移动应用基础教程>中国铁道出版社课后习题(附答案) 第2章Android UI开发 一.填空题 1.Android中的布局分为6种,分别是RelativeLayout.Li ...

最新文章

  1. 测试三相无刷电机驱动器 XXD2212 电调
  2. LINUX挂接移动硬盘
  3. 动态规划套路:最大子数组和
  4. R语言观察日志(part10)--file函数
  5. java课程设计 博客园_java课程设计
  6. 解析可变参数函数的实现原理(printf,scanf)
  7. 工作325:uni-日期小于10补0
  8. QML笔记-使用Row的时候要注意的地方(一定要指明高度和宽度)
  9. python元组和列表都支持的方法是_Python进阶1-元组和列表
  10. 江门计算机职称考试时间,江门职称计算机考试时间
  11. cmake构建NNIE工程
  12. linux 提取有效源码,MPSOC之4——petalinux提取源码
  13. ESP8266-01/01S配对阿里云生活物联网教程(超详细)
  14. 2021 泰迪杯 C 题
  15. 从零开始研发GPS接收机连载——1、想法的萌发
  16. 短视频制作难度大吗?怎么剪辑短视频?
  17. 《激荡三十年》十八、青春飞扬——互联网的崛起
  18. 计算机连接未识别的网络,电脑网络连接出现未识别的网络怎么办
  19. springboot网上电子书店下载购买系统-图书商城网站961h3-java-ssm二级分类
  20. (十九)jmeter3.0插件管理---学习笔记

热门文章

  1. 织梦 php MIP改造,织梦dedecms MIP改造图片img转img-mip处理方法
  2. k米魔云8服务器系统在哪购买,线上KTV“K米·魔云6”上市发布会在贵州举行
  3. 从技术到管理,数据人如何开展工作?
  4. 禁止输入空格键demo效果示例(整理)
  5. Fabric源码流程分析之Orderer篇
  6. Automatic Head and Neck Tumor Segmentation in PET/CT with Scale Attention Network(HECKTOR2020第四名)
  7. matlab中继电器叫什么,解析汽车继电器中继电器各脚的区别及接线
  8. RSA PKCS1和PKCS8的ASN格式
  9. 论文研究 | 机器视觉下的普通国省干线公路落物识别
  10. 微信小程序携带参数的页面跳转