动画总结(译)

概述

Android为视图和activitys间的转场提供了强大的动画支持。应对不同场景系统提供了三种类型的动画,但是最重要的还是属性动画(Property animation)。属性动画允许我们设置任意的动画属性在动画持续期间来适配这些属性从而达到动画的效果。

这些可以应用于任何的Android应用程序,典型的可以对一个视图进行位置上的,旋转性、膨胀性,和颜色上进行动画效果的展示。

动画可以定义在XML文件中也可以在java代码上来实现它。

原文地址:http://guides.codepath.com/android/Animations
该文档涉及到谷歌官方文档所以在阅读的时候需要梯子查阅。

动画类型

Android中实际上是有两个明确的动画框架:

  • Property Animations – 从Android3.0开始引入的很强大也很灵活的框架
  • View Animations – 比较慢且不够灵活,自从Property动画引入后官方就弃用了这个方法

依靠这个强大的框架,可以进一步将动画分为以下5种类型:

  • Property Animations – 这是一个在两个视图间依靠不同属性进行动画,经常使用它对图片进行旋转对按钮淡入淡出等等。
  • Activity Transitions – Activity之间的转场动画
  • Fragment Transitions – Fragment之间的转场动画
  • Layout Animation – 该类型可以使我们对布局容器或者ViewGroup如ListView产生动画效果。有了Layout Animation可以使容器中的所有视图都能产生动画效果。
  • Drawable Animations – 该类型是使用Drawable来产生动画效果。

Material动画原则

随着5.0版本的发布,谷歌公司也发布了更详细的动画文档,该文档提供了Material设计原则,下面是核心的4条原则:

  • Authentic motion – Material设计的世界里不仅要求设计的漂亮,也要综合考虑应用的空间、关系、功能以及系统意图来进行构建应用。
  • Responsive interaction – 如果一款应用的用户交互做的足够完美业务逻辑合乎用户审美,那么用户会对这款应用感到满意甚至是欣喜。
  • Meaningful transitions – 精心设计的应用会引起用户注意,通过多步骤的操作使用户感到应用思路清晰而不至于混淆某个按钮的意义或者某个键的功能等等。
  • Delightful details – 从应用组件细节入手,如图标的转场变化,所有这些细节都会提升用户体验。

读者可以从这四条原则角度出发仔细的分析一款Material应用。

属性动画

属性动画是3.0版本的新特性,引入这一特性的首要动机可以查阅Android官方博客

视图上的普通动画属性如下表所示:

Property 描述
alpha 透明度
rotation、rotationX、rotationY 旋转
scaleX、scaleY 伸缩
x、y、z 位置
transitionX、transitionY、transitionZ(API21+) 从位置上偏移

为兼容3.0之前的设备可以使用NineOldAndroid来实现所有的属性动画。如果你是一个studio用户可以在gradle文件中添加下面这句话:

1
compile 'com.nineoldandroids:library:2.4.0+'

AndroidViewAnimations这个库使得使用属性动画更简单。

在java中使用ObjectAnimator对象

我们一旦引入了NineOldAndroid,就可以使用ObjectAnimator类来实现动画效果了。

1
2
ObjectAnimator fadeAnim = ObjectAnimator.ofFloat(tvLabel, "alpha", 0.2f);
fadeAnim.start();

这两行代码可以使空间产生变淡的效果。注意alpha是一个string类型的参数ObjectAnimator依赖反射和使用setAlpha)、getAlpha)方法来执行动画效果。



我们也可以使用android4.0 graphics andanimations来执行属性动画:

1
2
ObjectAnimator fadeAltAnim = ObjectAnimator.ofFloat(image, View.ALPHA, 0, 1);
fadeAltAnim.start();

这种方式会提升运行速度,因为该方法不会使用反射机制,属性包括了ALPHA, ROTATION, ROTATION_X, ROTATION_Y, SCALE_X, SCALE_Y, TRANSLATION_X, TRANSLATION_Y, TRANSLATION_Z, X, Y, Z来提升运行效率。

为Animator对象设置duration和repeat属性

上面的代码产生一个20%不透明的效果,我们也可以添加额外的动作,例如duration、repeat等:

1
2
3
4
5
ObjectAnimator scaleAnim = ObjectAnimator.ofFloat(tvLabel, "scaleX", 1.0f, 2.0f);
scaleAnim.setDuration(3000);
scaleAnim.setRepeatCount(ValueAnimator.INFINITE);
scaleAnim.setRepeatMode(ValueAnimator.REVERSE);
scaleAnim.start();

设置插值器(interpolation)

每当我们设置一个属性动画时都要考虑动画运行的速度。换句话说,我们不仅要考虑属性变化也要控制动画运动的轨迹,这样需要为ObjectAnimator制定一个TimeInterpolator对象:

1
2
3
4
ObjectAnimator moveAnim = ObjectAnimator.ofFloat(v, "Y", 1000);
moveAnim.setDuration(2000);
moveAnim.setInterpolator(new BounceInterpolator());
moveAnim.start();

其效果如下:



API中interpolator实现定义了一些属性,常用的如下表所示:

Name 描述
AccelerateInterpolator 加速
BounceInterpolator 跳跃
DecelerateInterpolator 减速
LinearInterpolator 线性

除此之外还有很多其他的时间插值器check

监听动画的生命周期

我们可以添加AnimatorListenerAdapter来管理动画期间的事件例如onAnimationStartonAnimationEnd:

1
2
3
4
5
6
7
8
ObjectAnimator anim = ObjectAnimator.ofFloat(v, "alpha", 0.2f);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
Toast.makeText(MainActivity.this, "End!", Toast.LENGTH_SHORT).show();
}
});
anim.start();

Choreographing Animations

我们可以使用多个ObjectAnimator对象通过AnimatorSet类执行复杂的动画效果:

1
2
3
4
5
6
7
8
9
10
11
AnimatorSet set = new AnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(tvLabel, "scaleX", 1.0f, 2.0f)
.setDuration(2000),
ObjectAnimator.ofFloat(tvLabel, "scaleY", 1.0f, 2.0f)
.setDuration(2000),
ObjectAnimator.ofObject(tvLabel, "backgroundColor", new ArgbEvaluator(),
/*Red*/0xFFFF8080, /*Blue*/0xFF8080FF)
.setDuration(2000)
);
set.start();

其效果如下:



也可以在AnimatorSet中组织多个AnimatorSet一起进行动画:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Define first set of animations
ObjectAnimator anim1 = ObjectAnimator.ofFloat(tvLabel, "scaleX", 2.0f);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(tvLabel, "scaleY", 2.0f);
AnimatorSet set1 = new AnimatorSet();
set1.playTogether(anim1, anim2);
// Define second set of animations
ObjectAnimator anim3 = ObjectAnimator.ofFloat(v, "X", 300);
ObjectAnimator anim4 = ObjectAnimator.ofFloat(v, "Y", 300);
AnimatorSet set2 = new AnimatorSet();
set2.playTogether(anim3, anim4);
// Play the animation sets one after another
AnimatorSet set3 = new AnimatorSet();
set3.playSequentially(set1, set2);
set3.start();

下面是另外一个精心设计过的动画效果

1
2
3
4
5
6
7
8
9
10
11
12
13
// Create two animations to play together
ObjectAnimator bounceAnim = ...;
ObjectAnimator squashAnim = ...;
// Construct set 1 playing together
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).with(squashAnim);
// Create second animation to play after
ObjectAnimator fadeAnim = ObjectAnimator.ofFloat(view1, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
// Play bouncer before fade
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();

查阅属性动画官方文档获取更多信息

在java中使用ViewPropertyAnimator对象

我们可以通过ViewPropertyAnimator更简便的使用属性动画,ViewPropertyAnimator对象是ObjectAnimator对象的最顶层动画效果的属性。该类的执行效率也很高,具体信息可以查阅Android官方博客

为了兼容3.0之前的版本需要适配NineOldAndroid库,下面代码可以并发执行动画:

1
2
Button btnExample = (Button) findViewById(R.id.btnExample);
btnExample.animate().alpha(0.2f).xBy(-100).yBy(100);

为了使任何一个Activity都能使用NineOldAndroid,要确保静态导入ViewPropertyAnimator类:

1
import static com.nineoldandroids.view.ViewPropertyAnimator.animate;

下面我可以在自己的View上执行属性动画了,例如淡化一个按钮:

1
2
3
4
Button btnExample = (Button) findViewById(R.id.btnExample);
// Note: in order to use the ViewPropertyAnimator like this add the following import:
// import static com.nineoldandroids.view.ViewPropertyAnimator.animate;
animate(btnExample).alpha(0);

这样,自动创建和执行动画:



ViewPropertyAnimator类提供了很多属性如不透明,旋转,伸缩,x&y,位置等等。例如下面是一个比较复杂的动画效果:

1
2
3
4
5
6
7
8
animate(btnExample).alpha(0.5f).rotation(90f).
scaleX(2).xBy(100).yBy(100).setDuration(1000).setStartDelay(10).
setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
Toast.makeText(MainActivity.this, "Started...", Toast.LENGTH_SHORT).show();
};
});

使用XML

我们也能在XML中使用NineOldAndroid的动画,在XML中描述我们要动画的效果,例如,我们想要淡化一个按钮,可以添加res/animator/fade_out.xml文件:

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="alpha"
android:duration="1000"
android:valueTo="0" />

接着在Activity中加载XML文件并执行:

1
2
3
Animator anim = AnimatorInflater.loadAnimator(this, R.animator.fade_out);
anim.setTarget(btnExample);
anim.start();

就这些东西了,现在执行我们预先定义好的XML动画,下面是更复杂的动画res/animator/multi.xml。该文件中定义的动画可以并行的运用到一个按钮的动画上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together" >
<objectAnimator
android:propertyName="alpha"
android:valueTo="0.5" >
</objectAnimator>
<objectAnimator
android:propertyName="rotation"
android:valueTo="90.0" >
</objectAnimator>
<objectAnimator
android:propertyName="scaleX"
android:valueTo="2.0" >
</objectAnimator>
<objectAnimator
android:propertyName="translationX"
android:valueTo="100.0" >
</objectAnimator>
<objectAnimator
android:propertyName="translationY"
android:valueTo="100.0" >
</objectAnimator>
</set>

1
2
3
4
5
6
7
8
9
10
11
Animator anim = AnimatorInflater.loadAnimator(this, R.animator.multi_button);
anim.setTarget(tvBlah);
anim.setDuration(1000);
anim.setStartDelay(10);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
Toast.makeText(MainActivity.this, "Started...", Toast.LENGTH_SHORT).show();
};
});
anim.start();

效果如下:



更多信息查阅官方文档和Animator Resource

使用ValueAnimator对象来自定义动画

在一些情况下,通过替换动画属性例如上面讲到的alpha来实现动画效果的过程我们可能需要有更好的粒度来控制动画的。这种情况下可以使用ValueAnimator来自定义监听来适应View的动画:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Construct the value animator and define the range
ValueAnimator valueAnim = ValueAnimator.ofFloat(0, 1);
// Animate over the course of 700 milliseconds
valueAnim.setDuration(700);
// Choose an interpolator
valueAnim.setInterpolator(new DecelerateInterpolator());
// Define how to update the view at each "step" of the animation
valueAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedValue = (float) animation.getAnimatedValue();
// Use the animated value to affect the view
}
});
// Start the animation if not already running
if (!valueAnim.isStarted()) {
valueAnim.start();
}

更多信息查阅ValueAnimator。注意,大多数情况我们可以使用上文中展示的ObjectAnimator类来实现,但是对于比较低端的动画,我们没必要直接使用属性动画。

View Animations

视图动画是在属性动画提出前就有了,它的运行速度比较慢且不够灵活。所以3.0之后的设备都被属性动画所取代,这里简单的看一下老版本上使用XML解析的视图动画的原理。

首先,通过Android官方博客给出属性动画引入动机,和属性动画不同视图动画具有以下特点:

  • 老版本的试图动画只支持移动、淡入淡出、伸缩、旋转。然而新版本的提供了更强大框架(例如背景颜色、梯度、甚至在地图上做标记的动画)
  • 老版本只支持View对象(如button,listview,TextView等)但是新的属性动画能支持任意的对象例如Drawable。
  • 老版本的动画当经历了一个移动的动画后不会更新当下的位置,而需要手动添加代码来更新位置。这个问题在新版本中已经修复。

查阅Google I/O talk上对老版本动画的讨论。

老版本的视图动画也存在着错误的想法,那就是不适用硬件(GPU)来驱动动画。这个问题被谷歌工程师们揭穿,当属性动画在3.0版本发布后,动画硬件加速的支持也被添加进去,这样使得动画表现更加出色。

使用XML

通过定义我们视图动画的XML文件来替代属性动画的XML。首先,我们在res/anim目录下定义我们的动画,你也可以通过这个链接看到很多流行的动画。

下面res/anim/fade_out.xml例子是一个淡化的动画效果:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true" >
<alpha
android:duration="1000"
android:fromAlpha="1.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:toAlpha="0.0" />
</set>

在Activity为视图加载这个动画:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Inflate animation from XML
Animation animFadeOut = AnimationUtils.loadAnimation(this, R.anim.fade_out);
// Setup listeners (optional)
animFadeOut.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
// Fires when animation starts
}
@Override
public void onAnimationEnd(Animation animation) {
// ...
}
@Override
public void onAnimationRepeat(Animation animation) {
// ...
}
});
// start the animation
btnExample.startAnimation(animFadeOut);

其效果如下:



更多信息查看Animation Resource和这篇博文

Activity Transitions

除了属性动画,我们也可以通过Activity来管理动画和转场,我们通过Intent触发一个转场动画。基本方法是通过startActivity传递Intent来调用overPaddingTransition)方法:

1
2
3
Intent i = new Intent(MainActivity.this, SecondActivity.class);
startActivity(i);
overridePendingTransition(R.anim.right_in, R.anim.left_out);

第一个参数是enter的动画,第二个参数是exit的动画效果,具体的动画可以通过XML文件定义:更多效果
下面是enter的动画XML,res/anim/right_in.xml

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator">
<translate
android:fromXDelta="100%p"
android:toXDelta="0"
android:duration="500"/>
</set>

上述代码将延X轴从屏幕的右侧滑入(100%p的意思是,将要启动的Activity的位置与屏幕的宽相等<也就是屏幕最右侧滑入>),接下来我们定义res/anim/left_out.xml文件:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator">
<translate
android:fromXDelta="0"
android:toXDelta="-100%p"
android:duration="500"/>
</set>

这几行代码将导致旧的Activity从屏幕左侧滑出。当这些动画一起执行时,将产生旧Activity从左侧滑出新Activity从右侧滑入的效果。为了控制返回键也产生相反的动画效果需要创建left_in.xmlright_out.xml文件。

left_in.xml:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator">
<translate
android:fromXDelta="-100%p"
android:toXDelta="0"
android:duration="500"/>
</set>

right_out.xml:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator">
<translate
android:fromXDelta="0"
android:toXDelta="100%p"
android:duration="500"/>
</set>

接下来我们使用overridePendingTransition方法来驱动这个动画:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class SecondActivity extends Activity {
// onBackPressed is what is called when back is hit, call `overridePendingTransition`
@Override
public void onBackPressed() {
finish();
overridePendingTransition(R.anim.left_in, R.anim.right_out);
}
// to handle activity transitions for Up navigation add it to the onOptionsItemSelected
// as below
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
// This refers to the Up navigation button in the action bar
if (id == android.R.id.home) {
finish();
overridePendingTransition(R.anim.left_in, R.anim.right_out);
return true;
}
return super.onOptionsItemSelected(item);
}
}

其效果如下:



你也可以看到一些复杂转场的例子,具体如下:

Fragment Transition

和Activity转场类似我们可以在Fragment中通过FragmentTransition类中调用setCustomAnimations方法实现转场。动画可以简单的通过XML文件设置就和前文提到的一样,例如,我们要实现Fragment右进左出的效果,首先需要自定义res/anim/slide_in_left.xml文件

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="-50%p" android:toXDelta="0"
android:duration="@android:integer/config_mediumAnimTime"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="@android:integer/config_mediumAnimTime" />
</set>

接着,res/anim/slide_out_right.xml文件

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="50%p"
android:duration="@android:integer/config_mediumAnimTime"/>
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:duration="@android:integer/config_mediumAnimTime" />
</set>

现在我们需要配置Fragment的转场,在replace方法之前配置好,具体如下:

1
2
3
4
5
6
7
8
// Create the transaction
FragmentTransaction fts = getSupportFragmentManager().beginTransaction();
// Configure the "in" and "out" animation files
fts.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);
// Perform the fragment replacement
ft.replace(R.id.fragment_container, newFragment, "fragment");
// Start the animated transition.
ft.commit();

其效果如下:



在兼容性上需要注意,要是在Fragment上使用转场不应该使用support Fragment,具体详情移步stackOverflow

注意Android内置了一些动画XMl,R.anim可以通过android.R.anim来引用:

1
2
3
4
FragmentTransaction fts = getSupportFragmentManager().beginTransaction();
fts.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
fts.replace(R.id.fragment_container, newFragment, "fragment");
fts.commit();

更多关于Fragment转场可以查看这篇文章,也可以阅读一下animation的源码

官方的Fragment flip教程教你一步一步实现flip的动画效果。

扩展须知,如果你将动画运用到DialogFragment上可以查看这篇StackOverflow

Layout Animations

开始时的动画

当一个布局第一次绘制在屏幕上时候可以为其指定动画效果。可以在布局文件中设置android:layoutAnimation属性来指定动画

首先,定义动画res/anim/slide_right.xml,一个往右滑动的动画

1
2
3
4
5
6
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator">
<translate android:fromXDelta="-100%p"
android:toXDelta="0"
android:duration="1000" />
</set>

接下来需要创建特定的layoutAnimation来引用动画文件

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="30%"
android:animationOrder="reverse"
android:animation="@anim/slide_right"
/>

最后将layoutAnimation放置到布局文件中:

1
2
3
<LinearLayout
...
android:layoutAnimation="@anim/layout_bottom_to_top_slide" />

现在,当你启动应用时,布局中的视图将从屏幕右侧滑入。更多关于布局动画的信息查看linkyan的博文或者这篇布局动画教程ui Action 教程

动画变化

Layout Change Animation运行我们使用任意的布局或者ViewGroup如ListView都能使用动画。有了布局动画的enable,所有在布局容器中的视图都将自动产生动画效果。这个对ListView尤为重要因为可以使得每一个item的添加和删除产生动画效果。

为了使默认的动画可用,我们要在ViewGroup中设置animateLayoutChanges属性:

1
2
3
4
5
6
7
8
9
<LinearLayout
...
android:animateLayoutChanges="true">
<ListView android:id="@+id/list"
android:animateLayoutChanges="true"
...
/>
</LinearLayout>

android:animateLayoutChanges使得默认动画可用。

动图(.gif)

在很多需求中我们会看到显示动态图的要求,最简单就是GIF格式的图片。底层可以调用AnimationDrawable的XML文件来描述这个动图的每一帧的序列,来实现动态图的展示效果。

最简单的方法来显示GIF图就是使用第三方库,Glide是一个显示本地或者远程的gif图的库。该库是扩展了ImageView类,首先在gradle文件中依赖该库:

1
2
3
4
dependencies {
...
compile 'com.github.bumptech.glide:glide:3.6.0'
}

接着设置ImageView,例如在activity_main.xml文件中:

1
2
3
4
5
<ImageView
android:id="@+id/ivGif"
android:contentDescription="Gif"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

对于本地的GIF图片可以放置在res/raw目录下,接下来转化和加载GIF图片:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// MainActivity.java
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Find the ImageView to display the GIF
ImageView ivGif = (ImageView) findViewById(R.id.ivGif);
// Display the GIF (from raw resource) into the ImageView
Glide.with(this).load(R.raw.my_gif).asGif().into(imageView);
// OR even download from the network
// Glide.with(this).load("http://i.imgur.com/l9lffwf.gif").asGif().into(imageView);
}
}

其效果如下:



你也可以使用其他优秀的库来实现动态图的展示,例如android-gif-drawable,当然也可以使用WebView来加载动图。

Lollipop 动画

在5.0版本中有许多新的动画特性被引入:

颗粒效果(Particle Effect)

使用第三方库Leonids可以实现如下图所示的颗粒效果的动画。颗粒效果常常被运用在游戏中,如火焰或者烟雾的效果,当然这种效果也可以运用在普通的应用中,如小米MIUIV6系统Launcher卸载应用的效果。



由于它主要是运用在游戏中,所以所有的游戏引擎也都支持了颗粒系统了,但是依旧没有构建在标准的android UI系统中。更多关于颗粒效果的动画移步该库的官方博客

  • AndroidViewAnimations – Common property animations made easy.
  • ListViewAnimations – List view item animations made simple including insertion and deletion.
  • NineOldAndroids – Compatibility library supporting property animations all the way back to Android 1.0.
  • Leonids – Simple particle effects for Android.

参考