上篇文章介绍了应用程序内对用户操作响应的相关方法位置,简单的响应逻辑可以是从一个界面Activity跳转到另一个界面Activity,也可以是某些视图View的相对变化。然而不管是启动一个界面执行新界面Activity的生命周期方法,还是视图的相对变化,都需要一段时间,所以在响应的最终结果完成之前是有一段空白时间的。而在这段或长或短的时间里,该怎么给用户展示界面呢?这就用到Android系统推荐的动画流程了。

广义上说,Android系统在屏幕上绘制展示给用户的内容发生变化时,都可以使用相关动画过渡。与用户操作的响应一致,根据动画的作用对象不同,展示动画的效果可以作用于界面Activity,也可以作用于视图View。大多文章是基于动画分类的帧动画、补间动画介绍,而这里将按照动画的作用对象分别展开介绍。

视图动画

视图动画可以作用于任何需要展示动画效果的视图View,视图动画是Android系统最原生的一种动画类型,视图动画的定义类可以查看android.view.animation.Animation,其子类便是视图动画的效果分类,包括渐变效果AlphaAnimation、旋转效果RotateAnimation、缩放效果ScaleAnimation、移动效果TranslateAnimation、和将上述多种效果集合到一起的合集效果AnimationSet

由于视图View既可以在布局文件中静态声明,也可以在代码中动态注册声明,所以类似的,视图动画的声明也可以分为在布局文件中静态声明,和在代码中动态声明两种方式。但是视图动画的效果启动使用,需要根据不同的用户响应决定,所以只能在代码中动态使用。由于视图动画可能包含大量的效果数据,所以一般推荐视图动画静态声明+动态使用的方式。

动态声明的视图动画效果,只需要在代码中定义上述五种动画效果对应的动画类,并设置相关数据参数即可。其中

渐变效果AlphaAnimation (float fromAlpha, float toAlpha)必须要设置fromAlpha参数作为渐变效果的起始透明度,toAlpha参数作为渐变效果的结束透明度。

旋转效果RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)必须要设置fromDegrees参数作为旋转效果的起始旋转角度,和toDegrees参数作为旋转效果的结束旋转角度;其他参数可选,包括屏幕坐标形式的后四个参数,pivotXType参数为pivotXValue参数类型,pivotXValue参数为绕x轴旋转的角度值,同理,pivotYType参数为pivotYValue参数类型,pivotYValue参数为绕y轴旋转的角度值。其中的参数类型包括Animation.ABSOLUTE绝对类型,其参数值表示绝对数值;Animation.RELATIVE_TO_SELF相对自身视图类型,其参数值为相对自身视图在动画效果前的百分值;Animation.RELATIVE_TO_PARENT相对父视图类型,其参数值为相对父视图在动画效果前的百分值。

缩放效果ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)也是以屏幕坐标的形式记录参数,必须要设置fromX参数作为缩放效果开始时在x轴方向的比例,toX参数作为缩放效果结束时在x轴方向的比例,同理,fromY参数作为缩放效果开始时在y轴方向的比例,toY参数作为缩放效果结束时在y轴方向的比例;其他参数可选,其含义与旋转效果的可选参数类似。

移动效果TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta)TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue, int fromYType, float fromYValue, int toYType, float toYValue)同样是以屏幕坐标的形式记录参数,这两个构造方法可以任选一种,其中当八参构造方法中的Type系列参数值为Animation.RELATIVE_TO_SELF时,Value系列参数所表示的数据与四参构造方法的Delta系列参数一致。

合集效果AnimationSet(boolean shareInterpolator)可以根据shareInterpolator参数决定该动画内的一系列动画展示时是否使用当前类对象中定义的插值器,之后可以调用该对象的addAnimation(Animation a)依次放入要执行的系列视图动画对象。

这里提到的插值器,是实现了android.view.animation.Interpolator接口的类,这些插值器类计算了视图动画效果中从开始到结束之间那段时间的效果展示,在上述视图动画效果Animation对象中,可以通过调用setInterpolator(Interpolator i)方法设置,如果不设置会默认使用android.view.animation.LinearInterpolator线性插值器。

上述五种效果类的构造方法中,还有一种(Context context, AttributeSet attrs)参数的构造方法,使用该构造方法可以通过参数二attrs传入静态声明的动画资源文件,从而在代码中使用实例化对象。

静态声明的视图动画文件,必须保存在res/anim/资源目录下,符合xml格式的文件。该文件的根标签必须是五种视图动画效果之一,包括渐变效果<alpha></alpha>、旋转效果<scale></scale>、缩放效果<rotate></rotate>、移动效果<translate></translate>、合集效果<set></set>。而其中的必选参数和可选参数也都与代码动态声明中的相对应。

最终都可以在代码中得到上述五种视图动画类的实例化对象。可以调用setAnimationListener(Animation.AnimationListener listener)设置动画执行的监听,在实现的android.view.animation.Animation.AnimationListener接口实例中,可以分别实现onAnimationStart(Animation animation)动画开始前、onAnimationRepeat(Animation animation)动画重复时、onAnimationEnd(Animation animation)动画结束时的回调监听。在启动动画展示的地方,调用startNow()方法可以立即开始;或者先调用setStartTime(long startTimeMillis)设置启动的延时时间,再调用start()方法开始计时,等延时时间之后开始展示动画。

图片动画

位图动画

在AndroidSDK提供的系统视图中,有一种类似幕布绘制图像的系列视图,像android.widget.ImageView,这种具有绘制像素位图功能的视图,更适合在其中绘制展示多张图片连续组合的帧动画。本质上图片动画只是一系列图片的组合,所以其声明和使用方式更随意,不仅可以在代码中动态声明+动态使用的方式,也可以直接在资源文件中静态声明+静态使用。不过因为图片动画需要加载大量的图片,所以在代码中动态声明使用的方式是在应用程序运行过程中执行的,可能会影响用户的流畅度,所以推荐图片动画使用静态声明+静态使用的方式。

动态声明的图片动画可以使用android.graphics.drawable.AnimationDrawable类实例化加载位图组成的帧动画。之后依次调用该对象的addFrame(Drawable frame, int duration)方法增加要展示的每一帧图片,其中参数一frame即指定了要加载的图片资源,参数二duration则表示当前图片资源帧在整个动画播放中的时长,单位是毫米。也可以调用该对象的setOneShot(boolean oneShot)设置当前系列帧的图片动画是否只播放一遍。最终在需要启动图片动画的位置,调用该对象的start(),而在需要停止图片动画的位置,调用对象的stop()

这里需要注意的是,图片动画启动的start()方法必须要在界面Activity的声明周期方法执行完onCreate()之后调用。

静态声明的图片动画文件,必须保存在res/drawable/目录下,符合xml格式的文件。该文件的根标签必须是<animation-list></animation-list>,在该标签中可以使用android:oneshot属性值为truefalse,来表示当前系列帧的图片动画是否只播放一遍。而其中的每一帧图片使用<item />中的android:drawable属性值作为drawable资源文件引用,同时要通过android:duration属性值设置当前图片帧的展示时长,根据人眼的识别速度,通常设置在1000(单位毫秒)以下。之后如果想静态使用,可以在要显示动画的视图中,通过设置其android:backgroud属性,并将静态声明的资源文件名作为drawable资源类型赋值,即可关联使用。如果想动态使用,首先在代码中找到要显示动画的视图对应的对象,调用该对象的setBackgroundResource(int res),同样将静态声明的资源文件名作为R.drawable资源类型赋值,也可关联使用。最终,在需要启动图片动画的代码中,通过调用视图对象的getBackgroud()方法获取到图片动画的接口android.graphics.drawable.Animatable对象,就可以在需要启动和停止图片动画的位置分别调用start()stop()方法。

矢量图动画

另外, 在Android5.0 即API 21及以上的版本中,通过在项目modle中增加项目依赖库support-vector-drawableanimated-vector-drawable,以支持在资源文件中定义绘制矢量图,在AndroidStudio创建默认项目时,所使用的默认应用icon就是矢量图对象,其优势就是缩放仍不失真、体积小等,这里不详介绍。针对这种矢量图对象,也可以更加快速的增加矢量图动画。由于矢量图只能在资源文件中静态声明,相应的,矢量图动画也只能在资源文件中静态声明。这种动画效果主要依赖于android.graphics.drawable.AnimatedVectorDrawable类或最新包向下兼容的androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat类。

矢量图的声明是在res/drawable/资源目录下,以<vector></vector>标签所包裹的一层表示普通矢量图,可以在该标签内部增加<group></group>标签包裹一组动画效果,设置其android:name属性标记该组动画名称,同时使用视图动画相关属性值作为视图动画效果展示,包括渐变、旋转、缩放、平移。也可以在<group>标签内部,继续使用<path></path>标签定义一系列路径,同样需要设置其android:name属性标记该组路径名称。

矢量动画的声明是在res/animator/资源目录下,以<objectAnimator></objectAnimator>为根标签包裹的动画效果,通过设置其android:propertyName属性值,可以描述视图动画效果中的渐变、缩放、旋转、平移等效果,其内部属性与静态声明的视图动画中的属性类似。而以<set></set>为根标签则可以包裹一系列上述四种动画效果所表示的<objectAnimator></objectAnimator>标签。

最后是将矢量图与矢量动画关联使用,需要在res/drawable资源目录下创建新的xml资源文件,以<animated-vector></animated-vector>作为根标签,并设置其android:drawable属性并引用上述普通矢量图资源文件为drawable资源类型赋值。在根标签内通过<target android:name="" android:animation="" />分别为矢量图定义中的android:name属性值与矢量图声明中的资源文件相关联。最终在引用普通矢量图资源文件的位置改为引用动画矢量图资源文件。

界面动画

界面动画仅在Android5.0即 API 21 及以上的版本中支持。界面动画作用于界面Activity,只有在两个界面Activity相互启动切换时,才需要展示界面动画,因此界面动画的展示对象主要分三种,包括作为旧界面Activity在退出时动画效果,作为新界面Activity在进入动画效果,和两个界面之间如果有相同内容的同类视图,称之为共享视图,其在界面切换时的动画效果。而关于这些对象的动画效果,AndroidSDK提供了一些统一的动画效果可供选择,包括针对退出和进入动画的淡入淡出效果的android.transition.Fade类、移动效果android.transition.Slide类、爆炸效果android.transition.Explode类;还有针对共享视图的视图动画效果。或者也可以继承android.transition.Transition实现自定义动画效果。

由于界面Activity的定义是在清单文件中静态注册的,所以界面动画的使用也可以在注册时采用静态声明使用的方式。在静态使用时用到了<activity android:style/>样式属性,该属性值是已经定义了<style></style>标签的xml格式的样式资源文件。在<style>样式标签中,必须包含属性parent="android:Theme.Material"或其子样式名。

要想启动界面动画,首先在该样式中增加一条开关控制。

<item name="android:windowActivityTransitions">true</item>

之后重写该样式标签中的<item>标签,根据name属性值控制不同的动画对象,而根据<item></item>标签值指定不同的动画效果。这里将不同动画对象对应关系列为下列表格。

动画对象 name值
作为新界面进入动画 android:windowEnterTransition
作为旧界面退出动画 android:windowExitTransition
作为新界面进入时共享视图动画 android:windowSharedElementEnterTransition
作为旧界面退出时共享视图动画 android:windowSharedElementExitTransition

既然界面动画是通过样式定义的方式静态声明,那肯定也能在界面Activity创建后的方法回调中通过代码动态声明使用。这里用到了android.view.Window类,因为样式的修改要在界面加载布局之前,所以在setContentView()方法之前,通过调用getWindow()方法可以得到Window对象。

首先同样需要调用该对象的requestFeature(Window.FEATURE_CONTENT_TRANSITIONS)方法开启界面动画开关。

之后调用该对象的系列方法来控制不同动画对象,根据传入的Transition对象的实例指定不同的动画效果。不同动画对象的对应关系如下表。

动画对象 Window类调用方法
作为新界面进入动画 setEnterTransition()
作为旧界面退出动画 setExitTransition()
作为新界面进入时共享视图动画 setSharedElementEnterTransition()
作为旧界面退出时共享视图动画 setSharedElementExitTransition()

针对共享视图的动画,还需要分别在两个布局文件中标记共享视图,使用android:transitionName属性指定相同的共享视图名字。

在声明界面动画效果后,还需要在该界面作为新界面被启动的位置或者该界面作为旧界面启动其他界面的位置,将原有的startActivity(Intent intent)方法修改为startActivity(Intent intent, Bundle bundle)方法。其中的intent参数还是之前要启动界面的意图信息,bundle参数则是新增的控制界面动画的数据包。可以通过ActivityOptions.makeSceneTransitionAnimation(this).toBundle()系列方法获取当前界面声明的界面动画效果,其结果值作为android.os.Bundle对象传入即可。

如果在界面动画中有单个共享视图动画,可以参考ActivityOptions.makeSceneTransitionAnimation(Activity activity, View sharedElement, String sharedElementName)方法。

如果在界面动画中有多个共享视图动画,可以参考ActivityOptions.makeSceneTransitionAnimation(Activity activity, Pair...<View, String> sharedElements)方法。

除了上面作用于三种对象的基本动画类型,Android系统还提供了一种作用于任何对象的属性动画,该动画具有更全面的功能,详情可期待下篇文章。

Android系统编程入门系列之界面Activity响应丝滑的传统动画的更多相关文章

  1. Android系统编程入门系列之界面Activity响应多元的属性动画

    在响应丝滑动画一篇文章中,分别介绍了作用于普通视图.绘制视图的绘制对象.和界面这三种对象的动画效果,但是都有一些使用的局限性.比如这些动画都只是以屏幕上绘制更新的方式绘制动画,并没有真实改变作用对象的 ...

  2. Android系统编程入门系列之界面Activity绘制展示

    上篇文章介绍了界面Activity的启动方式和生命周期,本篇将继续介绍在界面Activity中的内容是如何绘制展示给用户的. 在Android系统上运行新创建的界面Activtiy,给用户展示的是空白 ...

  3. Android系统编程入门系列之界面Activity交互响应

    在上篇文章中已经了解到界面Activity的绘制完全依赖其加载的视图组件View,不仅如此,用户的每次触摸操作都可以在界面Activity内接收并响应,也可以直接传递给其中的某个视图View响应.本文 ...

  4. Android系统编程入门系列之加载界面Activity

    上回说到应用初始化加载及其生命周期,在Android系统调用Applicaiton.onCreate()之后,继续创建并加载清单文件中注册的首个界面即主Activity,也可称之为入口界面.主Acti ...

  5. Android系统编程入门系列之应用环境及开发环境介绍

        作为移动端操作系统,目前最新的Android 11.0已经发展的比较完善了,现在也到了系统的整理一番的时间,接下来的系列文章将以Android开发者为中心,争取用归纳总结的态度对初级入门者所应 ...

  6. Android系统编程入门系列之硬件交互——多媒体摄像头

    多媒体系列硬件 多媒体包括图片.动画.音频.视频,这些多媒体素材的采集(输入)主要依靠摄像头和麦克风等硬件设备转化为基础数据,而他们的播放渲染(输出),则需要依靠具有相关功能的编解码软件.当然随着硬件 ...

  7. Android系统编程入门系列之加载服务Service

    之前几篇文章简单梳理了在Android系统的四大组件之一,最主要的界面Activity中,使应用程序与用户进行交互响应的相关知识点,那对于应用程序中不需要与用户交互的逻辑,又要用到哪些内容呢?本文开始 ...

  8. Android系统编程入门系列之服务Service齐头并进多线程任务

    在上篇文章中初步了解了Android系统的四大组件之一的服务Service,在服务内可以执行无用户交互的耗时操作任务,但是包括之前关于界面系列文章在内,生命周期方法都是在主线程内被系统回调的.如果直接 ...

  9. Android系统编程入门系列之广播接收者BroadcastReceiver实现进程间通信

    在前边几篇关于Android系统两个重要组件的介绍中,界面Activity负责应用程序与用户的交互,服务Service负责应用程序内部线程间的交互或两个应用程序进程之间的数据交互.看上去这两大组件就能 ...

随机推荐

  1. 深度学习调用TensorFlow、PyTorch等框架

    深度学习调用TensorFlow.PyTorch等框架 一.开发目标目标 提供统一接口的库,它可以从C++和Python中的多个框架中运行深度学习模型.欧米诺使研究人员能够在自己选择的框架内轻松建立模 ...

  2. kube-proxy IPVS 模式的工作原理

    原文链接:https://fuckcloudnative.io/posts/ipvs-how-kubernetes-services-direct-traffic-to-pods/ Kubernete ...

  3. robotframework用户关键字创建过程

    robotframework是一个关键字驱动框架,核心在于关键字的应用.系统本身通过各种库自带了大量关键字,同时支持用户自定义关键字.关键字可以简单理解为各种处理数据的方法. 关键字区别与用户参数. ...

  4. Java后端精选技术:SpringBoot配置读取

    在早前的博客中曾经写过 Spring 程序通过 Bean 映射实现配置信息的读取. 在SpringBoot 框架中读取配置的方式变得非常多样,这导致读者在搜寻资料时反而容易迷糊. 到底,SpringB ...

  5. linux下 大日志文件查看与搜索---less

    场景 有一个几十m的大日志文件,里边的记录是按时间排序的. 现在需要找到其中,不知道在什么位置的一条错误消息.这时候,想把内容拷出来都费劲,就算拷出来了,一般的编辑器也难以hold住这么大的文件.这时 ...

  6. 在vs中调试关闭之后不关闭页面

    在vs中调试api时会自动打开一个新的浏览器窗口,在关闭这个浏览器窗口时,会关闭调试.关闭调试时也会关闭浏览器窗口. 设置成调试时在已有的浏览器中打开调试页面,关闭调试也不会关掉浏览器窗口,反之亦然 ...

  7. bootstrap validate 验证插件

    1.需要引入bootstrapValidator.min.js 2.在需要验证的控件中添加 class="form-control" 3.js中写验证的方法 $('#psasave ...

  8. SpringBoot统一处理返回结果和异常情况

    如果文章有帮助到你,还请点个赞或留下评论 原因 在springboot项目里我们希望接口返回的数据包含至少三个属性: code:请求接口的返回码,成功或者异常等返回编码,例如定义请求成功. messa ...

  9. 从零玩转人脸识别之RGB人脸活体检测

    从零玩转RGB人脸活体检测 前言 本期教程人脸识别第三方平台为虹软科技,本文章讲解的是人脸识别RGB活体追踪技术,免费的功能很多可以自行搭配,希望在你看完本章课程有所收获. ArcFace 离线SDK ...

  10. CentOS-配置JDK(压缩包)

    卸载openjdk $ rpm -qa | grep jdk 以上命令用来检查linux上是否安装openjdk,如果安装需要将其全部卸载掉,卸载命令: $ rpm -e --nodeps java- ...