本文原创:转载请声明出处
Android动画共有三大类:
1.补间动画(Tween 动画),补间动画仅仅提供了四种动画API类,都是Animation的子类,分别为:渐变(AlphaAtion),缩(ScaleAnimation),旋转(RotateAnimation),位移(TranslateAnimation)。这种动画都只是针对View作为对象在视觉上发生的改变,实质上View的属性并未发生改变,比如说位移动画,当你把View移动到别的位置的时候,View的点击事件不会跟着移动,还在View原先所在的地方。
xml指定动画效果:
res下创建anim文件夹创建translate.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromXDelta="0" android:fromYDelta="0" android:toXDelta="400" android:toYDelta="0" /> </set>书写布局文件,用原生的ImageView就好,我这儿是用了一个自定义的ImageView
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:dragon="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#0000FF"> <!-- xmlns:dragon="http://schemas.android.com/apk/res-auto" 注意看上面的这句话,是用于引用自定义的属性,不可丢 --> <com.picovr.animatordemo.CircleImage android:id="@+id/iv_animator" android:layout_width="120dp" android:layout_height="120dp" android:src="@drawable/e" dragon:borderColor="#000000" dragon:borderWidth="4dp" dragon:hasBorder="true" /> </RelativeLayout>关联ImageView和动画集,并启动动画
private void animation(final View view) { Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.translate); animation.setDuration(5 * 1000); animation.setFillAfter(true); view.startAnimation(animation); }
Java代码指定动画效果:
书写布局文件,跟xml方式的布局一样,有一个ImageView就行
java代码
iv_animator = ((CircleImage) findViewById(R.id.iv_animator)); WindowManager windowManager = (WindowManager) getSystemService(Service.WINDOW_SERVICE); Display defaultDisplay = windowManager.getDefaultDisplay(); Point point = new Point(); defaultDisplay.getSize(point); screenWidth = point.x; screenHeight = point.y; TranslateAnimation animation = new TranslateAnimation(0, screenWidth - iv_animator.getWidth(), 0, 0); animation.setDuration(10 * 1000); animation.setFillAfter(true); iv_animator.startAnimation(animation);
另外,可以对图片写个监听,在监听方法中打log,让图片移走之后,点击图片原先所在位置和移动之后的位置,观察log,有礼物。
效果附上
2.帧动画(Frame动画),一组图片,以电影集的形式播放出来,这种动画极容易引起OOM,在使用时一定注意,性能的优化。
drawable下创建animation.xml文件,这里指定播放的图片和播放时长
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item
android:drawable="@drawable/a"
android:duration="1500" />
<item
android:drawable="@drawable/b"
android:duration="1500" />
<item
android:drawable="@drawable/c"
android:duration="1500" />
<item
android:drawable="@drawable/timg"
android:duration="1500" />
<item
android:drawable="@drawable/timgs"
android:duration="1500" />
<item
android:drawable="@drawable/d"
android:duration="1500" />
<item
android:drawable="@drawable/e"
android:duration="1500" />
<item
android:drawable="@drawable/f"
android:duration="1500" />
<item
android:drawable="@drawable/g"
android:duration="1500" />
</animation-list>
书写布局文件,这儿来一个ImageView,用原生的ImageView即可,我这儿是用了一个自定义的ImageView
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dragon="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0000FF">
<!-- xmlns:dragon="http://schemas.android.com/apk/res-auto" 注意看上面的这句话,是用于引用自定义的属性,不可丢 -->
<com.picovr.animatordemo.CircleImage
android:id="@+id/iv_animator"
android:layout_width="320dp"
android:layout_height="320dp"
android:layout_centerInParent="true"
dragon:borderColor="#000000"
dragon:borderWidth="4dp"
dragon:hasBorder="true" />
</RelativeLayout>
调用API关联上ImageView和动画集,并启动动画
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv_animator = ((CircleImage) findViewById(R.id.iv_animator));
iv_animator.setImageResource(R.drawable.animation_list);
final AnimationDrawable animation = (AnimationDrawable) iv_animator.getDrawable();
animation.start();
iv_animator.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("MainActivity", "onClick :");
animation.stop();
}
});
}
3.属性动画(Property动画),这种动画跟帧动画在视觉上效果差不多,但是不同的是它直接以View的某一个属性作为对象改变,产生视觉上的改变,并且View的属性会跟着改变。属性动画的机制其实就是对值的不断操作,给定一个初始值,一个结束值,过度时长,然后一点点平滑的过度的一个过程。
ValueAnimator详解:
ValueAnimator是直接对值进行操作,比起ObjectAnimator更接近底层,实现简单动画很简单,提供ofFloat方法,和ofInt方法,指定一组数值,动画效果其实就是这一组数值的一个过度过程。代码说话:
/** * 本来是一个自由落体运动的动画,重复模式,就变成来回晃荡了 * * @param view */ public void verticalRun(final View view) { //ofFloat中给定了两个值,起始值为0,结束值为屏幕高度减去视图的高度,这儿其实参数可以不止两个 ValueAnimator animator = ValueAnimator.ofFloat(0, screenHeight - view.getHeight()); //设定执行动画的对象 animator.setTarget(view); //过度时长 animator.setDuration(2000); //重复次数 animator.setRepeatCount(10); //重复的模式,这儿反着播放模式 animator.setRepeatMode(ValueAnimator.REVERSE); animator.start(); //监听动画的改变 animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { //这个值就是当前动画所在的值 float values = (float) animation.getAnimatedValue(); Log.i("MainActivity", "onAnimationUpdate values :" + values); view.setTranslationY(values); } }); }效果:
ObjectAnimator详解:
ObjectAnimator是平时我们用的比较多的,ObjectAnimator直接针对任意对象的任意属性进行操作。针对对象的某个属性,其实就是通过属性对应的get,set方法直接对属性进行操作。ofFloat,ofInt方法中的第二个参数,就是需要改变的属性。ObjectAnimator其实是继承了ValueAnimation,相当于封装了一层,更能表达面向对象的思想。当然了,既然他继承了ValueAnimation,那他们的用法就及其相似了,但是针对简单动画来说ObjectAnimator用起来会更简单,不一定要想ValueAnimator那样一定要在监听中去操作。
旋转动画
public void rotationY(final View view) { //ObjectAnimator提供ofFloat方法可以很快实现动画,Y方向旋转180度 ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 0.0F, 180.0F).setDuration(1000); //X方向旋转180度 // ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 0.0F, 180.0F).setDuration(1000); animator.start(); }
位移动画
public void translateX(final View view) { //ObjectAnimator提供ofFloat方法可以很快实现动画,Y方向旋转180度 ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", 0.0F, 360.0F).setDuration(1000); //X方向旋转180度 // ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationY", 0.0F, 180.0F).setDuration(1000); animator.start(); }从上面的代码来看就知道,对于一些简单的动画, ObjectAnimator用起来代码明显精简了很多,用起来更简便,更有利于开发,但是很多复杂的动画还是得用ValueAnimation来完成。
效果附上
ObjectAnimator也可以像ValueAnimator那样通过动画监听方法实现动画
public void rotateyAnimRun(final View view) { ObjectAnimator anim = ObjectAnimator.ofFloat(view, "dragon", 1.0F, 0.0F, 1.0F).setDuration(500); anim.start(); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float cVal = (Float) animation.getAnimatedValue(); view.setAlpha(cVal); view.setScaleX(cVal); view.setScaleY(cVal); } }); }
效果附上
用PropertyValueHolder实现动画集合
public void propertyValuesHolder(View view) { PropertyValuesHolder pvhalpha = PropertyValuesHolder.ofFloat("alpha", 1f, 0f, 1f); PropertyValuesHolder pvhscaleX = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f); PropertyValuesHolder pvhscaleY = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f); PropertyValuesHolder pvhTranslate = PropertyValuesHolder.ofFloat("translationX", 0f, 360f); ObjectAnimator.ofPropertyValuesHolder(view, pvhalpha, pvhscaleX, pvhscaleY, pvhTranslate).setDuration(3 * 1000).start(); }效果附上
这种方式作出来的动画组,是所有动画同时进行的。这毕竟很局限,比如说我想要一个动画先执行,然后第二个动画和第三个动画同时在第一个动画执行2秒之后开始执行,那就不行了。其实Android团队也考虑到了,给我们提供了更丰富的API AnimatorSet动画集合。
public void animatorSet(final View view) { //制作三个动画 ObjectAnimator translationX = ObjectAnimator.ofFloat(view, "translationY", 0.0F, screenHeight - view.getHeight()); ObjectAnimator rotation = ObjectAnimator.ofFloat(view, "rotation", 0f, 360f); ObjectAnimator alpha = ObjectAnimator.ofFloat(view, "alpha", 1f, 0.4f, 1f); AnimatorSet animatorSet = new AnimatorSet(); AnimatorSet.Builder builder = animatorSet.play(rotation); //让alpha动画跟rotation动画同时在translate动画之后执行 builder.with(alpha).after(translationX); animatorSet.setDuration(3 * 1000).start(); }
效果: