android中的动画实现方式繁多,在项目中也经常用到动画,网上有很多人也都进行了一些总结,但是感觉还是零零散散,自己总结一下才能加深印象,以后有时间了,也可以从各个分类里进一步去补充完善。
如果喜欢看Google官方英文文档的,可以直接移步Animations and Transitions
这类动画比较简单,一般就是平移、缩放、旋转、透明度,或者其组合,可以用代码或者xml文件的形式,推荐使用xml文件形式,因为可以复用。
四个动画效果实现类:TranslateAnimation、ScaleAnimation、RotateAnimation、AlphaAnimation、AnimationSet,对应的的XML标签为translate、 scale、 rotate、alpha、set,其中set里还可以放set,然后放在放置在res/anim/目录下,关于详细使用这里不再做介绍。
<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>
代码中使用:
ImageView image = (ImageView) findViewById(R.id.image);
Animation hyperspaceJump = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);
image.startAnimation(hyperspaceJump);
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.animator.property_animator);
set.setTarget(myObject);
set.start();
参考网上的一个停止补间动画的正确姿势:
public void stopAnimation(View v) {
v.clearAnimation();
if (canCancelAnimation()) {
v.animate().cancel();
}
animation.setAnimationListener(null);
v.setAnimation(null);
}
/**
* Returns true if the API level supports canceling existing animations via the
* ViewPropertyAnimator, and false if it does not
* @return true if the API level supports canceling existing animations via the
* ViewPropertyAnimator, and false if it does not
*/
public static boolean canCancelAnimation() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
}
如果要做很炫酷的下来刷新或者loading动画,可以考虑使用Airbnb开源的动画框架Lottie
简单讲就是把几个静态的图片快速播放形成动画,可以使用AnimationDrawable,官方推荐使用XML文件,放在res/drawable/路径下,
代码如下所示:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true">
<item android:drawable="@drawable/thrust1" android:duration="200" />
<item android:drawable="@drawable/thrust2" android:duration="200" />
<item android:drawable="@drawable/thrust3" android:duration="200" />
animation-list>
android:oneshot="true"表示只执行一次动画,false表示无限循环,
ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
rocketImage.setBackgroundResource(R.drawable.rocket_thrust);
rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
rocketImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
rocketAnimation.start();
}
});
注意调用AnimationDrawable的start方法时,不能在Activity的onCreat里,因为这时AnimationDrawable还没有完全依附到window上,如果一开始就想执行动画,可以放在onStart方法里
还有一种矢量动画AnimatedVectorDrawable, 感兴趣的可以查看这里
https://developer.android.google.cn/guide/topics/graphics/drawable-animation
属性动画,顾名思义,只要对象里有属性的set和get方法,就可以利用这个属性去做动画。
上面介绍的View Animation都是对View进行的操作,准确的说,是改变View的绘制,并没有改变View对象本身的属性值,且只有一些基本的动画效果,不能改变background color等,属性动画可以对任何对象进行改变(我好像还没遇到这种场景)。官网介绍,相比Property Animation,View Animation启动所需的时间少,要写的代码也少,所以,如果能用视图动画搞定的动画,就没有必要使用属性动画了。
在android.view.animation包里定义的差值器interpolators可以用在属性动画中。
属性动画使用Animator的子类,通常是ValueAnimator和ObjectAnimator ,ValueAnimator只能计算属性值的变化,可以设置监听然后自己处理相关逻辑;ObjectAnimator可以对对象的属性值计算后,直接应用于对象的相应属性。
ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.start();
或者对自定义的类型进行动画:
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
balls.remove(((ObjectAnimator)animation).getTarget());
}
fadeAnim.start();
animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator updatedAnimation) {
// You can use the animated value in a property that uses the
// same type as the animation. In this case, you can use the
// float value in the translationX property.
float animatedValue = (float)updatedAnimation.getAnimatedValue();
textView.setTranslationX(animatedValue);
}
});
ObjectAnimator和AnimatorSet的使用:
ObjectAnimator.ofFloat(targetObject, "propName", 1f)
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();
在一次需要修改多个属性值时,除了可以使用AnimatorSet, 还可以使用语法更简洁的ViewPropertyAnimator,同时ViewPropertyAnimator也更高效,代码对比如下:
Multiple ObjectAnimator objects
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
One ObjectAnimator
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
ViewPropertyAnimator
myView.animate().x(50f).y(100f);
关于ViewPropertyAnimator的更多介绍,可以查看官网介绍 blog post.
这类动画是模仿现实中的弹力效果,每一帧都是通过计算相应的弹力=得到,可以设置弹性动画的阻尼率和刚度来达到不同的弹性效果。
添加依赖
dependencies {
implementation 'com.android.support:support-dynamic-animation:27.1.1'
}
以下是一个应用了链式弹性动画Chained spring的效果图,
弹性动画使用SpringAnimation类,具体可参考官网介绍:Animate movement using spring physics 或者 Android中弹簧动画的那些事 - SpringAnimation
Fling Animation类似于列表ListView在快速滚动时到最后列表停止滚动的效果。
Fling Animation使用FlingAnimation类,具体可参考官网介绍:Move views using a fling animation
当改变一个布局的元素时,android提供了一种预加载动画,使用默认的布局动画,只需要对一个layout设置一个属性,如下所示:
当对这个LinearLayout中添加、删除或者更新子View时,这些子View就会自动添加上默认的动画效果。
private ViewGroup mContainerView;
...
private void addItem() {
View newView;
...
mContainerView.addView(newView, 0);
}
除了默认的布局动画,也可以自定义动画,并使用setAnimator方法设置给ViewGroup,以后有时间可以仔细研究一下,
public void setAnimator (int transitionType,
Animator animator)
转场动画可以在两个布局之间,产生动画效果,步骤如下:
1.根据其实布局和结束布局,创建Scene对象,
2.创建一个Transition对象,用来定义所需的动画类型
3.调用TransitionManager.go(),然后系统就在两个布局之间产生动画
更多内容请参考 Animate layout changes using a transition 和
Create a custom transition animation
从Android5.0(API21)开始,可以使用 Activity transition,所以要注意低版本的效果适配。
当给一个Activity指定了退出的转场动画,在启动一个新的Activity时,将调用动画效果,如果新启动的Activity也设置了进入的转场动画,那么在启动时,也会产生相应的动画,要禁用动画效果时,传一个空的bundle
使用Activity转场动画,要在使用的theme里,将android:windowActivityTransitions设置为true
然后在代码中
// inside your activity (if you did not enable transitions in your theme)
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
// set an exit transition
getWindow().setExitTransition(new Explode());
startActivity(intent,
ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
可以共享一个或者多个元素,简要代码如下,
// get the element that receives the click event
final View imgContainerView = findViewById(R.id.img_container);
// get the common element for the transition in this activity
final View androidRobotView = findViewById(R.id.image_small);
// define a click listener
imgContainerView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(this, Activity2.class);
// create the transition animation - the images in the layouts
// of both activities are defined with android:transitionName="robot"
ActivityOptions options = ActivityOptions
.makeSceneTransitionAnimation(this, androidRobotView, "robot");
// start the new activity
startActivity(intent, options.toBundle());
}
});
多个共享元素时:
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
Pair.create(view1, "agreedName1"),
Pair.create(view2, "agreedName2"));
推荐博文:
【Transition】Android炫酷的Activity切换效果,共享元素
这个放在最后写,因为感觉最牛逼啊,其实和上面介绍到的Layout Transition 布局转场动画很相似,先是用ConstraintLayout写两个布局文件,然后利用TransitionManager调用beginDel ayedTransition()启动一个延时转场动画就行,且ConstraintLayout支持到API 9,TransitionManager支持到API 14,所以多使用ConstraintSet来做动画,兼容性不用担心,除了在两个布局里转场,在一个布局内改变某个View的属性(如边距),其余的View也会自动产生平滑的动画效果,其他什么动画相关代码都不用写,,,,,惊不惊喜!
使用ConstraintLayout制作漂亮的动画
ConstraintLayout 炫酷的动画
利用给Transition设置相应的差值器Interpolator,就能产生更加fashion的效果,感兴趣的同学可以观看以下视频教程:
用四行代码来实现复杂动画 | 中文教学视频
//2018.12.23 更新
MotionLayout 因何而生?
Android 框架已经提供了好几种在 App 里添加动画的方式:
Animated Vector Drawable
Property Animation framework
LayoutTransition animations
Layout transitions with TransitionManager
CoordinatorLayout
下面将揭示 MotionLayout 和上面这些已有方案的不同。
暂时没事时间研究,先把网址贴一下:
『译』ConstrainLayout 2.0 之 MotionLayout(Part1.1)
【翻译】MotionLayout实现折叠工具栏(Part 1)
【翻译】MotionLayout实现折叠工具栏(Part 2)