Android攻城狮属性动画赏析

Posted 张兮兮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android攻城狮属性动画赏析相关的知识,希望对你有一定的参考价值。

 

 1 import android.support.v7.app.ActionBarActivity;
 2 import android.support.v7.app.ActionBar;
 3 import android.support.v4.app.Fragment;
 4 import android.animation.AnimatorSet;
 5 import android.animation.ObjectAnimator;
 6 import android.animation.PropertyValuesHolder;
 7 import android.os.Bundle;
 8 import android.view.LayoutInflater;
 9 import android.view.Menu;
10 import android.view.MenuItem;
11 import android.view.View;
12 import android.view.ViewGroup;
13 import android.view.animation.TranslateAnimation;
14 import android.widget.ImageView;
15 import android.widget.Toast;
16 import android.os.Build;
17 //显示animation的缺点
18 public class MainActivity extends ActionBarActivity {
19 
20     @Override
21     protected void onCreate(Bundle savedInstanceState) {
22         super.onCreate(savedInstanceState);
23         setContentView(R.layout.fragment_main);
24 
25         
26     }
27 
28     public void click(View view) {
29         Toast.makeText(MainActivity.this, "click", 0).show();
30         
31     }
32     public void move(View view) {
33         //-------------------传统实现----图片在位移,监听的还在原地--
34         
35 //    TranslateAnimation animation=new TranslateAnimation(0, 200, 0,0);
36 //    animation.setDuration(1000);
37 //    animation.setFillAfter(true);//停留在结束的位置
38     ImageView imageView=(ImageView) findViewById(R.id.imageView1);
39 //    imageView.startAnimation(animation);
40     
41     
42         //translationX:在X方向上位移;translationY:在Y方向上位移
43         //rotation:旋转
44     //动画是同时进行的
45     //-----------方式1-----------
46         ObjectAnimator.ofFloat(imageView,"translationX", 0F,200F).setDuration(1000).start();
47         ObjectAnimator.ofFloat(imageView,"rotation", 0F,360F).setDuration(1000).start();
48         ObjectAnimator.ofFloat(imageView,"translationY", 0F,200F).setDuration(1000).start();
49         //-----------方式2-----------
50         PropertyValuesHolder p1=PropertyValuesHolder.ofFloat("rotation", 0F,360F);
51         PropertyValuesHolder p2=PropertyValuesHolder.ofFloat("translationX", 0F,200F);
52         PropertyValuesHolder p3=PropertyValuesHolder.ofFloat("translationY", 0F,200F);
53         ObjectAnimator.ofPropertyValuesHolder(imageView, p1,p2,p3).setDuration(1000).start();
54         
55         //-----------方式3-----------
56         ObjectAnimator animator1=ObjectAnimator.ofFloat(imageView,"translationX", 0F,200F);
57         ObjectAnimator animator2=ObjectAnimator.ofFloat(imageView,"rotation", 0F,360F);
58         ObjectAnimator animator3=ObjectAnimator.ofFloat(imageView,"translationY", 0F,200F);
59         AnimatorSet set=new AnimatorSet();
60         set.playTogether(animator1,animator2,animator3);//一起执行
61         set.playSequentially(animator1,animator2,animator3);//按顺序执行
62         set.play(animator1).with(animator3);//同时xy方向
63         set.play(animator2).after(animator1);//再旋转
64         set.setDuration(1000);
65         set.start();
66         
67         
68         
69     }
70 }

 


Animator 的 set 方法为我们提供了非常丰富的动画控制效果。例如:playTogether()同时播放,playSequentially()按顺序播放。 set还可以做更详细的顺序控制,如图 set.play(animator2).with(animator3); // 动画animator2和animator3同时进行 set.play(animator1).after(animator2); // 动画animator1在animator2(也可以写3)之后进行 这种方式也是属性动画框架中使用最多的一种:通过 ObjectAnimator 进行更精确的属性动画设置,只控制一个对象的一个属性,同时多个 ObjectAnimator 组合到 AnimatorSet 中,形成一个完整的动画效果。而且 AnimatorSet 可以通过调用 play()、with()、after()、before()、playTogether()、playSequentially()等方法,实现更为丰富的动画效果。

//---------------------监听事件---------------------------------------

 1 public class MainActivity extends ActionBarActivity {
 2 
 3     @Override
 4     protected void onCreate(Bundle savedInstanceState) {
 5         super.onCreate(savedInstanceState);
 6         setContentView(R.layout.fragment_main);
 7 
 8         
 9     }
10 
11     public void click(View view) {
12         ObjectAnimator animator=ObjectAnimator.ofFloat(view, "alpha", 0F,1F);
13     animator.setDuration(1000);
14     //-----------------方式2-------------
15 //    animator.addListener(new AnimatorListenerAdapter() {
16 //        @Override
17 //        public void onAnimationEnd(Animator animation) {
18 //            // TODO Auto-generated method stub
19 //            super.onAnimationEnd(animation);
20 //        }
21 //    });
22     
23     //-----------------方式1-------------
24     animator.addListener(new AnimatorListener() {
25         
26         @Override
27         public void onAnimationStart(Animator animation) {
28             // TODO Auto-generated method stub
29             
30         }
31         
32         @Override
33         public void onAnimationRepeat(Animator animation) {
34             // TODO Auto-generated method stub
35             
36         }
37         
38         @Override
39         public void onAnimationEnd(Animator animation) {
40             // TODO Auto-generated method stub
41             Toast.makeText(MainActivity.this,"动画完咯", 1).show();
42         }
43         
44         @Override
45         public void onAnimationCancel(Animator animation) {
46             // TODO Auto-generated method stub
47             
48         }
49     });
50     animator.start();
51     
52     
53     }
54 }
这里列举了几种插值器(以下都只是前缀,例如Accelerate表示AccelerateInterpolator):
Accelerate 加速变化
Decelerate 减速变化
AccelerateDecelerate 先加速再减速
Overshoot 在结束之前会超出预定位置一点点,然后回到预定位置
Bounce 最常见的回弹动画,例如自由落体的小球的回弹效果就是通过这样一个插值器实现的。
//-------------------------菜单展开效果------------------------------
 1 public class MainActivity extends ActionBarActivity implements OnClickListener {
 2     private int[] res = { R.id.imageView8, R.id.imageView2, R.id.imageView3,
 3             R.id.imageView4, R.id.imageView5, R.id.imageView6, R.id.imageView7,
 4             R.id.imageView1 };
 5     private List<ImageView> imageViewlist = new ArrayList<ImageView>();
 6 
 7     private boolean flag = true;
 8 
 9     @Override
10     protected void onCreate(Bundle savedInstanceState) {
11         super.onCreate(savedInstanceState);
12         setContentView(R.layout.fragment_main);
13         for (int i = 0; i < res.length; i++) {
14             ImageView imageView = (ImageView) findViewById(res[i]);
15             imageView.setOnClickListener(this);
16             imageViewlist.add(imageView);
17         }
18 
19     }
20 
21     @Override
22     public void onClick(View v) {
23         // TODO Auto-generated method stub
24         switch (v.getId()) {
25         case R.id.imageView8:
26             if (flag) {
27                 startAnim();
28             } else {
29                 closeAnim();
30             }
31             break;
32 
33         default:
34             Toast.makeText(MainActivity.this, "click" + v.getId(), 1).show();
35             break;
36         }
37     }
38 
39     private void closeAnim() {
40         // TODO Auto-generated method stub
41         for (int i = 1; i < res.length; i++) {
42             ObjectAnimator animator = ObjectAnimator.ofFloat(
43                     imageViewlist.get(i), "translationY", 40 * i, 0F);
44             animator.setDuration(500);
45             animator.setInterpolator(new BounceInterpolator());
46             animator.setStartDelay(i * 300);// 依次弹出
47             animator.start();
48             flag = true;
49         }
50     }
51 
52     private void startAnim() {
53         // TODO Auto-generated method stub
54         for (int i = 1; i < res.length; i++) {
55             ObjectAnimator animator = ObjectAnimator.ofFloat(
56                     imageViewlist.get(i), "translationY", 0F, 40 * i);
57             animator.setDuration(500);
58             animator.setInterpolator(new BounceInterpolator());
59             animator.setStartDelay(i * 300);// 依次弹出
60             animator.start();
61             flag = false;
62         }
63     }
64 
65 }

 

(float) (Math.sin(Math.toRadians((i - 1) * 90 / (6 - 1))) * 200)
其中,6是要展开的图标数,200是半径。
按照上面程序加入translationX,和translationY中可以以扇形展开。
//--------------------ValueAnimator------------------------
1. 之前学过ObjectAnimator是作用于某一控件的某一属性,而ValueAnimator本身不作用于任何属性,本身也不会提供任何动画,简单而言,ValueAnimator是一个数值发生器,可以产生任何你想要的数值,Android系统给它提供了很多数值计算方法。
2. 那么,产生这些数值有什么用呢?其实,在属性动画中,如何产生每一步的具体动画效果,都是通过 ValueAnimator 计算出来的。比如要实现一个0到100的位移动画,随着时间的持续,数值也从0到100递增,有这些值,就可以作用这些属性,让它产生动画效果。
3. 那么,ValueAnimator 是如何产生这些值的呢?
首先,ValueAnimator 会根据动画已经进行的时间和总时间的比值,产生一个0到1的时间因子,有了这样的时间因子,经过相应的变换,就可以根据你的StartValue和EndValue,来生成中间的相应的值。同时,通过插值器的使用,我们还可以进一步控制每一个时间因子的产生值的变化速度,比如我们使用线性插值器,生成数值的时候就是一个线性变化,只要时间相同,增量就相同。
由于 ValueAnimator 本身不响应任何一个动画,也不能控制任何一个属性,所以它并没有 ObjectAnimator 使用得那么广泛。
4. 查看源码,我们可以发现 ObjectAnimator 是继承了 ValueAnimator。之前也说过了,正是由于 ValueAnimator 产生的动画变化的变化值,ObjectAnimator 才可以将它应用于我们的属性。因此,ObjectAnimator 实际上是对ValueAnimator的封装。
5. 那么,如何通过 ValueAnimator 去实现动画效果呢?这就需要使用动画监听事件了,我们可以监听ValueAnimator每一步所产生的值,通过这个值去实现相应的动画效果。

案例:使用ValueAnimator实现计数器:
如图所示的例子中,先使用ValueAnimator.ofInt(0,100)获取0到100之间的所有数字,并设置一个时间为5秒,然后,通过监听器(调用addUpdateListener())的监听事件,获取 ValueAnimator每一步变化所产生的值,通过这些值去设置Button的显示文字。至此,就实现了一个简单的计数器。
 1 public class MainActivity extends ActionBarActivity {
 2     
 3     @Override
 4     protected void onCreate(Bundle savedInstanceState) {
 5         super.onCreate(savedInstanceState);
 6         setContentView(R.layout.fragment_main);
 7 
 8     }
 9 
10     public void click(View view) {
11         
12         ValueAnimator animator1=ValueAnimator.ofObject(new TypeEvaluator<PointF>() {
13 
14             
15             @Override
16             public PointF evaluate(float fraction, PointF startValue,
17                     PointF endValue) {
18                 // TODO Auto-generated method stub
19                 return null;
20             }
21         });
22         
23         
24     //----------------------------------------------------------------    
25         // 计时器的效果:5秒内从0变到100
26         final Button button = (Button) view;
27         ValueAnimator animator = ValueAnimator.ofInt(0, 100);
28         animator.setDuration(5000);
29         animator.addUpdateListener(new AnimatorUpdateListener() {
30 
31             @Override
32             public void onAnimationUpdate(ValueAnimator animation) {
33                 // TODO Auto-generated method stub
34 
35                 Integer value = (Integer) animation.getAnimatedValue();
36                 button.setText("" + value);
37 
38             }
39         });
40         animator.start();
41     }
42 }
除了ValueAnimator.ofInt(),还有其他类型的数字生成器,其中ValueAnimator.ofObject()可以实现自定义的数字生成器。
参数中的fraction就是时间因子(0到1之间变化的数值)。通过fraction、startValue、endValue,通过各种各样的计算方式,就可以生成所有想要产生的值,不光能产生普通数据结构,通过泛型还可以定义更为复杂的数据结构。
ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator() {
   @Override
   public Object evaluate(float fraction, Object startValue, Object endValue) {
      return null;
   }
});
生成泛型PointF(float类型的点坐标):
ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator<PointF>() {
   @Override
   public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
      return null;
   }
});
在方法evaluate()中可以添加各种各样的计算方式。
----------
第二重境界学无止境,ValueAnimator不仅仅可以应用于动画,也可以应用于Android的其他领域。


总结——常用属性
我们通过 ObjectAnimator 可以调用各种属性,只要这个属性具有get/set方法,我们就可以操纵它,如果这个属性没有提供get/set方法,或者我们想自定义一个属性,来让它进行一些改变,那么我们就要定义一个Property(属性),去实现它的set/get方法,就可以操作这样一个属性。
ObjectAnimator常用的一些操作属性:
1. translationX\translationY
2. rotation、rotationX\rotationY,这里的rotation是指3D的旋转。rotationX是水平方向的旋转,rotationY是垂直方向的旋转。
3. scaleX\scaleY  水平、垂直方向的缩放。
4. X\Y  具体会移动到的某个点。
5. alpha  透明度
属性动画框架执行的效率更高、效果更好。

总结——常用方法、类
1. ValueAnimator 数值发生器,可以实现很多很灵活的动画效果
2. ObjectAnimator 是ValueAnimator的一个子类,它封装了ValueAnimator,让我们更轻松地使用属性动画框架。我们通过ObjectAnimator来操作一个对象的属性,让对象产生一个动画效果。
3. AnimatorUpdateListener 监听事件
4. AnimatorListenerAdapter 监听事件
5. PropertyValuesHolder 控制动画集合的显示效果、顺序和流程控制
6. AnimatorSet 控制动画集合的显示效果、顺序和流程控制
7. TypeEvaluators  值计算器
8. Interpolators  插值器
值计算器和插值器用来控制具体产生的数值的一个变化规律以及变化状态。

 

 

 

 

 






















以上是关于Android攻城狮属性动画赏析的主要内容,如果未能解决你的问题,请参考以下文章

Android攻城狮动画组合

Android攻城狮布局动画

Android攻城狮四种基础动画

Android攻城狮OptionsMenu

Android攻城狮CheckBox&RadioGroup&AutoCompleteTextView&MultiAutoCompleteTextView&ToggleB

大数据攻城狮之进阶技能-Github的使用