总的来讲,Android动画能够分为两类,最初的传统动画和Android3.0 以后出现的属性动画; 传统动画又包括 帧动画(Frame Animation)和补间动画(Tweened Animation)。java
帧动画更多的依赖于完善的UI资源,他的原理就是将一张张单独的图片连贯的进行播放, 从而在视觉上产生一种动画的效果;有点相似于某些软件制做gif动画的方式。android
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/a_0"
android:duration="100" />
<item
android:drawable="@drawable/a_1"
android:duration="100" />
<item
android:drawable="@drawable/a_2"
android:duration="100" />
</animation-list>
复制代码
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_frame_animation);
ImageView animationImg1 = (ImageView) findViewById(R.id.animation1);
animationImg1.setImageResource(R.drawable.frame_anim1);
AnimationDrawable animationDrawable1 = (AnimationDrawable) animationImg1.getDrawable();
animationDrawable1.start();
}
复制代码
把ui给的帧动画的全部图片按照顺序卸载一个animation-list中,duration为每一张图片显示的时间,推荐60便可,最后找到AnimationDrawable,调用strat方法就行,帧动画不调用start方法只会显示第一帧图片,不会自动播放。git
注意: 帧动画容易引发oom,因此帧动画的全部图片头要进行压缩,再放到工程中,而起尽可能不要有太多张数。推荐一个在线压缩工具。TinyPNG,使用很是方便。程序员
补间动画又能够分为四种形式,分别是 alpha(淡入淡出),translate(位移),scale(缩放大小),rotate(旋转)。 补间动画的实现,通常会采用xml 文件的形式;代码会更容易书写和阅读,同时也更容易复用。github
XML 实现json
首先,在res/anim/ 文件夹下定义以下的动画实现方式bash
alpha_anim.xml 动画实现ide
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromAlpha="1.0"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:toAlpha="0.0" />
复制代码
scale.xml 动画实现工具
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.0"
android:toYScale="1.0"/>
复制代码
而后,在Activity中oop
Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_anim);
img = (ImageView) findViewById(R.id.img);
img.startAnimation(animation);
复制代码
这样就能够实现ImageView alpha 透明变化的动画效果。
也可使用set 标签将多个动画组合
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@[package:]anim/interpolator_resource"
android:shareInterpolator=["true" | "false"] >
<alpha
android:fromAlpha="float"
android:toAlpha="float" />
<scale
android:fromXScale="float"
android:toXScale="float"
android:fromYScale="float"
android:toYScale="float"
android:pivotX="float"
android:pivotY="float" />
<translate
android:fromXDelta="float"
android:toXDelta="float"
android:fromYDelta="float"
android:toYDelta="float" />
<rotate
android:fromDegrees="float"
android:toDegrees="float"
android:pivotX="float"
android:pivotY="float" />
<set>
...
</set>
</set>
复制代码
各个动画属性的含义结合动画自身的特色应该很好理解,就不一一阐述了;这里主要说一下interpolator 和 pivot。
Interpolator 主要做用是能够控制动画的变化速率 ,就是动画进行的快慢节奏。Android 系统已经为咱们提供了一些Interpolator ,好比 accelerate_decelerate_interpolator,accelerate_interpolator等。更多的interpolator 及其含义能够在Android SDK 中查看。同时这个Interpolator也是能够自定义的,这个后面还会提到。
pivot 决定了当前动画执行的参考位置,pivot 这个属性主要是在translate 和 scale 动画中,这两种动画都牵扯到view 的“物理位置“发生变化,因此须要一个参考点。而pivotX和pivotY就共同决定了这个点;它的值能够是float或者是百分比数值。
咱们以pivotX为例:
pivotY 也是相同的原理,只不过变成的纵向的位置。
有时候,动画的属性值可能须要动态的调整,这个时候使用xml 就不合适了,须要使用java代码实现
private void RotateAnimation() {
animation = new RotateAnimation(-deValue, deValue, Animation.RELATIVE_TO_SELF,
pxValue, Animation.RELATIVE_TO_SELF, pyValue);
animation.setDuration(timeValue);
if (keep.isChecked()) {
animation.setFillAfter(true);
} else {
animation.setFillAfter(false);
}
if (loop.isChecked()) {
animation.setRepeatCount(-1);
} else {
animation.setRepeatCount(0);
}
if (reverse.isChecked()) {
animation.setRepeatMode(Animation.REVERSE);
} else {
animation.setRepeatMode(Animation.RESTART);
}
img.startAnimation(animation);
}
复制代码
这里animation.setFillAfter决定了动画在播放结束时是否保持最终的状态;animation.setRepeatCount和animation.setRepeatMode 决定了动画的重复次数及重复方式,具体细节可查看源码理解。
属性动画,顾名思义它是对于对象属性的动画。所以,全部补间动画的内容,均可以经过属性动画实现。
属性动画入门
private void RotateAnimation() {
ObjectAnimator anim = ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);
anim.setDuration(1000);
anim.start();
}
private void AlpahAnimation() {
ObjectAnimator anim = ObjectAnimator.ofFloat(myView, "alpha", 1.0f, 0.8f, 0.6f, 0.4f, 0.2f, 0.0f);
anim.setRepeatCount(-1);
anim.setRepeatMode(ObjectAnimator.REVERSE);
anim.setDuration(2000);
anim.start();
}
复制代码
这两个方法用属性动画的方式分别实现了旋转动画和淡入淡出动画,其中setDuration、setRepeatMode及setRepeatCount和补间动画中的概念是同样的。
能够看到,属性动画貌似强大了许多,实现很方便,同时动画可变化的值也有了更多的选择,动画所能呈现的细节也更多。
固然属性动画也是能够组合实现的
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(myView, "alpha", 1.0f, 0.5f, 0.8f, 1.0f);
ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(myView, "scaleX", 0.0f, 1.0f);
ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(myView, "scaleY", 0.0f, 2.0f);
ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(myView, "rotation", 0, 360);
ObjectAnimator transXAnim = ObjectAnimator.ofFloat(myView, "translationX", 100, 400);
ObjectAnimator transYAnim = ObjectAnimator.ofFloat(myView, "tranlsationY", 100, 750);
AnimatorSet set = new AnimatorSet();
set.playTogether(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
// set.playSequentially(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
set.setDuration(3000);
set.start();
复制代码
能够看到这些动画能够同时播放,或者是按序播放。
ValueAnimator是整个属性动画机制当中最核心的一个类,属性动画的运行机制是经过不断地对值进行操做来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,咱们只须要将初始值和结束值提供给ValueAnimator,而且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮咱们完成从初始值平滑地过渡到结束值这样的效果。除此以外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等,确实是一个很是重要的类。
使用案列
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(300);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentValue = (float) animation.getAnimatedValue();
Log.d("TAG", "cuurent value is " + currentValue);
}
});
anim.start();
复制代码
这个列子表明动画从0到1动画时长为300毫秒,onAnimationUpdate方法中回调的是中间的变化数值,能够基于这个变化值不停的改变view的属性便可。
那么除此以外,咱们还能够调用setStartDelay()方法来设置动画延迟播放的时间,调用setRepeatCount()和setRepeatMode()方法来设置动画循环播放的次数以及循环播放的模式,循环模式包括RESTART和REVERSE两种,分别表示从新播放和倒序播放的意思。这些方法都很简单,我就再也不进行详细讲解了
相比于ValueAnimator,ObjectAnimator可能才是咱们最常接触到的类,由于ValueAnimator只不过是对值进行了一个平滑的动画过渡,但咱们实际使用到这种功能的场景好像并很少。而ObjectAnimator则就不一样了,它是能够直接对任意对象的任意属性进行动画操做的,好比说View的alpha属性。
例子:将一个TextView在5秒中内从常规变换成全透明,再从全透明变换成常规
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
animator.setDuration(5000);
animator.start();
复制代码
将TextView进行一次360度的旋转
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
animator.setDuration(5000);
animator.start();
复制代码
第一个参数为使用动画的view,第二个为动画操做的属性,后面的参数为属性的变化趋势。
注意: 其实ObjectAnimator内部的工做机制并非直接对咱们传入的属性名进行操做的,而是会去寻找这个属性名对应的get和set方法,若是没有get和set方法,属性动画并不会起做用,不信能够本身试试。
实现组合动画功能主要须要借助AnimatorSet这个类,这个类提供了一个play()方法,若是咱们向这个方法中传入一个Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder的实例,AnimatorSet.Builder中包括如下四个方法: after(Animator anim) 将现有动画插入到传入的动画以后执行 after(long delay) 将现有动画延迟指定毫秒后执行 before(Animator anim) 将现有动画插入到传入的动画以前执行 with(Animator anim) 将现有动画和传入的动画同时执行
例子:让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();
复制代码
在不少时候,咱们但愿能够监听到动画的各类事件,好比动画什么时候开始,什么时候结束,而后在开始或者结束的时候去执行一些逻辑处理。这个功能是彻底能够实现的,Animator类当中提供了一个addListener()方法,这个方法接收一个AnimatorListener,咱们只须要去实现这个AnimatorListener就能够监听动画的各类事件了。
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) {
}
});
复制代码
onAnimationStart()方法会在动画开始的时候调用,onAnimationRepeat()方法会在动画重复执行的时候调用,onAnimationEnd()方法会在动画结束的时候调用,onAnimationCancel()方法会在动画被取消的时候调用。
使用这个类就能够解决掉实现接口繁琐的问题了,以下所示:
anim.addListener(new AnimatorListenerAdapter() {
});
复制代码
这里咱们向addListener()方法中传入这个适配器对象,因为AnimatorListenerAdapter中已经将每一个接口都实现好了,因此这里不用实现任何一个方法也不会报错。那么若是我想监听动画结束这个事件,就只须要单独重写这一个方法就能够了
那么TypeEvaluator的做用究竟是什么呢?简单来讲,就是告诉动画系统如何从初始值过分到结束值。
实现位置1平滑过渡到位置2
来先定义一个Point类
public class Point {
private float x;
private float y;
public Point(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
}
复制代码
接下来定义PointEvaluator
public class PointEvaluator implements TypeEvaluator{
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
Point startPoint = (Point) startValue;
Point endPoint = (Point) endValue;
float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());
float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());
Point point = new Point(x, y);
return point;
}
}
复制代码
PointEvaluator编写完成了,接下来咱们就能够很是轻松地对Point对象进行动画操做了,好比说咱们有两个Point对象,如今须要将Point1经过动画平滑过分到Point2
Point point1 = new Point(0, 0);
Point point2 = new Point(300, 300);
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), point1, point2);
anim.setDuration(5000);
anim.start();
复制代码
注意:要能看到动画效果,须要监听动画的变化过程,不停的变化值复制给view的属性才行。
Interpolator 被用来修饰动画效果,定义动画的变化率,可使存在的动画效果accelerated(加速),decelerated(减速),repeated(重复),bounced(弹跳)等。
AccelerateDecelerateInterpolator 在动画开始与结束的地方速率改变比较慢,在中间的时候加速 AccelerateInterpolator 在动画开始的地方速率改变比较慢,而后开始加速 AnticipateInterpolator 开始的时候向后而后向前甩
AnticipateOvershootInterpolator 开始的时候向后而后向前甩必定值后返回最后的值 BounceInterpolator 动画结束的时候弹起
CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线
DecelerateInterpolator 在动画开始的地方快而后慢
LinearInterpolator 以常量速率改变
OvershootInterpolator 向前甩必定值后再回到原来位置
若是android定义的interpolators不符合你的效果也能够自定义interpolators
使用以下:
anim.setInterpolator(new DecelerateAccelerateInterpolator());
复制代码
ViewPropertyAnimator提供了更加易懂、更加面向对象的API,以下所示:
textview.animate().alpha(0f);
复制代码
果真很是简单!不过textview.animate()这个方法是怎么回事呢?animate()方法就是在Android 3.1系统上新增的一个方法,这个方法的返回值是一个ViewPropertyAnimator对象,也就是说拿到这个对象以后咱们就能够调用它的各类方法来实现动画效果了,这里咱们调用了alpha()方法并转入0,表示将当前的textview变成透明状态。
怎么样?比起使用ObjectAnimator,ViewPropertyAnimator的用法明显更加简单易懂吧。除此以外,ViewPropertyAnimator还能够很轻松地将多个动画组合到一块儿,好比咱们想要让textview运动到500,500这个坐标点上,就能够这样写:
textview.animate().x(500).y(500);
复制代码
那么怎样去设定动画的运行时长呢?很简单,也是经过连缀的方式设定便可,好比咱们想要让动画运行5秒钟,就能够这样写:
textview.animate().x(500).y(500).setDuration(5000)
.setInterpolator(new BounceInterpolator());
复制代码
注意:
整个ViewPropertyAnimator的功能都是创建在View类新增的animate()方法之上的,这个方法会建立并返回一个ViewPropertyAnimator的实例,以后的调用的全部方法,设置的全部属性都是经过这个实例完成的。 你们注意到,在使用ViewPropertyAnimator时,咱们自始至终没有调用过start()方法,这是由于新的接口中使用了隐式启动动画的功能,只要咱们将动画定义完成以后,动画就会自动启动。而且这个机制对于组合动画也一样有效,只要咱们不断地连缀新的方法,那么动画就不会马上执行,等到全部在ViewPropertyAnimator上设置的方法都执行完毕后,动画就会自动启动。固然若是不想使用这一默认机制的话,咱们也能够显式地调用start()方法来启动动画。 ViewPropertyAnimator的全部接口都是使用连缀的语法来设计的,每一个方法的返回值都是它自身的实例,所以调用完一个方法以后能够直接连缀调用它的另外一个方法,这样把全部的功能都串接起来,咱们甚至能够仅经过一行代码就完成任意复杂度的动画功能。
该动画主要是靠ui设置师完成,经过安装在AE上的一款名叫bodymovin的插件,可以将AE中的动画工程文件转换成通用的json格式描述文件,bodymovin插件自己是用于在网页上呈现各类AE效果的一个开源库,lottie作的事情就是实现了一个可以在不一样移动端平台上呈现AE动画的方式.从而达到动画文件的一次绘制、一次转换、随处可用的效果. 固然,就如Java一次编译,随处运行同样,lottie自己这个动画播放库并非跨平台的.
Lottie项目地址: github.com/airbnb/lott…
详细使用请参考:www.jianshu.com/p/cae606f45…
对于属性动画的时候,最好写成一个能复用的工具类,方便不一样的地方使用。补间动画虽然xml使用很方便,可是复用性很低,为了项目长远的发展,仍是应该作封装处理,lottie动画要看公司的选择,这个动画节约了程序员不少的时间,程序员能够用更多的时间来作性能的调优和业务的优化。