动画,顾名思义,一个很神奇的东西,第一次在android中接触这个东西,run以后感觉挺好玩的,但是,长江前浪推后浪,后浪把前浪拍在了沙滩上。Android为我们提供了几种动画类型:View Animation 、Drawable Animation 、Property Animation 。View Animation相当简单,不过只能支持简单的缩放、平移、旋转、透明度基本的动画,且有一定的局限性。比如:你希望View有一个颜色的切换动画;你希望可以使用3D旋转动画;你希望当动画停止时,View的位置就是当前的位置;这些View Animation都无法做到。这就是Property Animation产生的原因,今天我将和大家一起完成属性动画(Property Animation)的学习。
Property Animation,是一个google3.0以后才提出的动画框架,那么有人就会问了,3.0之前的我们就不管了吗,NO,NO~~,有的大神早已经为我们考虑到了这一点,导入Nineoldandroids点击下载动画库,Nineoldandroids包,由Github大牛jake wharton 开发,令Property Animation可以支持到1.x,用法基本完全一致~
导入
1. 属性动画Animator传统动画Animation
2. Animation局限性
3. 相关API
Animation动画简单的来说就是系统不断的调用OnDraw()重绘界面来实现一个动画效果,而属性动画,顾名思义,就是去操纵一个属性(getXX,setXX方法)从而真实改变一个属性实现动画效果。
下面通过一个简单的代码段子咱们来看看这两个家伙到底有什么区别。
布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/ic_launcher" android:onClick="imageClick" android:id="@+id/imageView" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="看上面的图片" android:id="@+id/btnMove" android:onClick="buttonMove" android:layout_gravity="center_horizontal" android:layout_below="@+id/imageView" android:layout_centerHorizontal="true" /> </RelativeLayout>
很简单的布局,就是一个图片,一个按钮
Activity代码
public class MainActivity extends ActionBarActivity implements View.OnClickListener { @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //隐藏标题栏 getSupportActionBar().hide(); setContentView(R.layout.activity_main); } //图片的点击事件 public void imageClick(View v) { Toast.makeText(this, "图片在这里----->OnClick", Toast.LENGTH_SHORT).show(); //TODO } //按钮的点击事件,ImageView移动 public void buttonMove(View v) { //平移动画 TranslateAnimation ta = new TranslateAnimation(0,500,0,0); ta.setDuration(1000); ta.setFillAfter(true); ImageView iv = (ImageView) findViewById(R.id.imageView); iv.startAnimation(ta); } }
界面
点击按钮移动,然后点击图片却没有toast,但是点击图片的原始位置却toast了,这就是视图动画最大的一个缺陷就是只是重绘动画,改变了他的显示位置,但是真真正正响应的事件却没有发生变化,所以这种视图动画不适合做用户交互的动画,他只是可以仅仅实现一些显示给用户的效果。从cpu资源来看,传统的视图动画只是不断的调用onDraw()方法,所以对于系统来说是很耗费资源的。虽然说可以通过各种组合也可以实现各种各样的动画效果,但是和一个属性来说是远远不够的。google给我们提供了一个秘密武器,可以让我们轻轻松松的实现更多,更优秀的动画效果。
下面开始进入我们的三境界:
第一重境界-ObjectAnimator
- 实现Animation框架的功能
- 属性动画常用属性演示
- 动画的监听事件
将前面的代码稍微修改一下,就可以实现了
//按钮的点击事件,ImageView移动 public void buttonMove(View v) { ImageView iv = (ImageView) findViewById(R.id.imageView); //使用属性动画实现平移效果,节省系统资源 ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(iv, "translationX", 0F, 400F); objectAnimator.setDuration(3000); objectAnimator.start(); }
ofFloat参数说明(我们将要操纵的对象,我们将要操纵的属性,一个可变长度的数组)
运行效果也很明显,图片的点击事件始终随着图片的移动而移动。
属性动画更新的过程中,会不断调用setPropName更新元素的属性,所有使用ObjectAnimator更新某个属性,必须得有getter(设置一个属性值的时候)和setter方法~
我们还可以对imageview做什么样的动画哪?只要google给我们提供了get,set方法我们就可以实现,常用的属性会在后面给大家一一列出。
这只是单属性动画效果,那么多属性动画复杂效果是怎么实现的哪?上代码
//使用属性动画实现复杂动画的 public void buttonMove(View v) { ImageView iv = (ImageView) findViewById(R.id.imageView); PropertyValuesHolder pv = PropertyValuesHolder.ofFloat("rotation",0,360F); PropertyValuesHolder pv1 = PropertyValuesHolder.ofFloat("translationX",0,200F); PropertyValuesHolder pv2 = PropertyValuesHolder.ofFloat("translationY",0,200F);ObjectAnimator.ofPropertyValuesHolder(iv,pv,pv1,pv2).setDuration(2000).start();}
效果很明显,三个动画一起执行,这里就不贴图了
这里不知道你有没有想到,之前我们学习Animation动画的时候,学个一个动画集合AnimationSet,那么这个属性动画有没有哪?同样也有,他是AnimatorSet,好了不多说,直接上代码
public void buttonMove(View v) { ImageView iv = (ImageView) findViewById(R.id.imageView); ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(iv,"rotation",0F,200F); ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(iv,"translationX",0,200F); ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(iv,"translationY",0,200F); AnimatorSet set = new AnimatorSet();set.playTogether(objectAnimator1,objectAnimator2,objectAnimator3);setDuration(2000); set.start();}
效果和上述的一样。
代码中有这么一句,
set.playTogether(objectAnimator1,objectAnimator2,objectAnimator3);
三个动画同时进行,但是有些时候需求并不是这样的,我们想要的动画效果,那要怎么实现那,我们来看一下里面还有什么方法。
set.playSequentially(objectAnimator1,objectAnimator2,objectAnimator3);
这一句,顾名思义,动画按照先后顺序来进行,三个动画依次进行,一个完了接着下一个,动画先在原地旋转360°,然后再X轴上移动200的距离,最后在Y轴上移动200的距离。。
还有一种这样的,就是上述的动画我们改一下,我们先让动画在X轴上,Y轴上同时的平移,最后再旋转360°,怎么做哪?
set.play(objectAnimator2).with(objectAnimator3);set.play(objectAnimator1).before(objectAnimator2);
set里面还有一个方法before方法,大家一看便知,这里就让你们自己去试试吧。
通过动画集合框架中的play,playSequentially,playTogether,with,before,after,等方法就可以轻松的实现各种动画。
我们已经见识到了各种动画的强大了,这只是给用户的一个展示效果,如果他没有作用,我们写了也没有什么用啊,那么我们就要给他加各种动画的监听事件,让动画得知在什么时候我们该做什么了,下面我们就来看看动画的监听事件。
布局文件
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" ><Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="click" android:text="click"/></LinearLayout>
布局文件很简单,就只有一个button,一个点击事件
activity文件
/** * Created by THINK on 2015/4/26 23:50. */public class aaa extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.aaa); } public void click(View v) { ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(v,"alpha",0F,1F); objectAnimator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { Toast.makeText(aaa.this,"哎呀,动画结束了",Toast.LENGTH_SHORT).show(); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); objectAnimator.setDuration(2000); objectAnimator.start(); }}
就是一个button的渐显动画,然后添加了动画监听事件,实现四个方法,很简单,动画开始,动画结束,动画取消,重新加载动画时分别调用这四个方法。为了简单看见效果,我在动画结束的时候Toast了一句话。
但是有些人说,这样子看着不顺眼,实现一个动画监听事件还要加四个方法,我们通常只会用到动画结束时的方法,这个样子我们还是有办法的,适配器模式就可以很轻松的实现了。
objectAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); } });
将监听器换成此样子就可以了,而且这里你想要什么样的方法就可以添加如此。
再这里带大家完成一个好玩的例子,算是给第一重境界做个总结吧。大家不知道见过Path这个App的一个button弹出效果吗
如果大家有研究过他的源码,会发现好啰嗦,好麻烦啊,我们刚刚学了属性动画,下面我们就用属性动画来去搞他了。
布局文件xml
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageViewb" android:layout_margin="15dp" android:layout_gravity="left|top" android:src="@mipmap/composer_b" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageViewc" android:layout_margin="15dp" android:layout_gravity="left|top" android:src="@mipmap/composer_c" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageViewd" android:layout_margin="15dp" android:layout_gravity="left|top" android:src="@mipmap/composer_d" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageViewe" android:layout_margin="15dp" android:layout_gravity="left|top" android:src="@mipmap/composer_e" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageViewf" android:layout_margin="15dp" android:layout_gravity="left|top" android:src="@mipmap/composer_f" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageViewg" android:layout_margin="15dp" android:layout_gravity="left|top" android:src="@mipmap/composer_g" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageViewh" android:layout_margin="15dp" android:layout_gravity="left|top" android:src="@mipmap/composer_h" /> <ImageView android:layout_width="60dp" android:layout_height="60dp" android:id="@+id/imageViewa" android:layout_gravity="left|top" android:src="@mipmap/composer_a" /></FrameLayout>
通过使用帧布局,将8个图片依次叠加放置在布局中,然后我们点击上面的图片,会依次实现上面图片的效果,
activity类
/** 1. Created by THINK on 2015/4/27 0:10. */public class AnimActivity extends ActionBarActivity implements View.OnClickListener { private int[] imageRes = {R.id.imageViewa, R.id.imageViewb, R.id.imageViewc, R.id.imageViewd, R.id.imageViewe, R.id.imageViewf, R.id.imageViewg, R.id.imageViewh}; private List<ImageView> imageViewList = new ArrayList<ImageView>(); private boolean falg = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getSupportActionBar().hide(); setContentView(R.layout.anim_layout); initImage(); } private void initImage() { for (int i = 0; i < imageRes.length; i++) { ImageView imageView = (ImageView) findViewById(imageRes[i]); imageView.setOnClickListener(this); imageViewList.add(imageView); } } /** * Called when a view has been clicked. * * @param v The view that was clicked. */ @Override public void onClick(View v) { switch (v.getId()) { case R.id.imageViewa: if (falg){ //点击开始动画 startAnim(); }else{ //点击关闭动画 closeAnim(); } break; default: //点击其他,这就是属性的动画的好处,每个控件的点击都会随着动画的移动而移动。case情况就是按钮的几种效果,这里就不细写了 Toast.makeText(this, v.getId() + "", Toast.LENGTH_LONG).show(); break; } } private void closeAnim() { for (int i = 1; i < imageRes.length; i++) { ObjectAnimator animator = ObjectAnimator.ofFloat(imageViewList.get(i), "translationY", i * 180F, 0F); animator.setDuration(300); animator.setStartDelay(i * 200); animator.setInterpolator(new BounceInterpolator()); animator.start(); } falg = true; } private void startAnim() { for (int i = 1; i < imageRes.length; i++) { ObjectAnimator animator = ObjectAnimator.ofFloat(imageViewList.get(i), "translationY", 0F, i * 150F); animator.setDuration(300); //动画弹出的效果时间间隔 animator.setStartDelay(i*200); //动画的差值器,实现自由落体效果 animator.setInterpolator(new BounceInterpolator()); animator.start(); } falg = false; }}
学过上面的东西,再回来看这些东西就so easy了吧~!,里面的效果还可以丰富,你们先运行一边看看效果去吧~
收放效果都有种自由落体的感觉。
第二重境界-ValueAnimator
- ValueAnimator是什么
- ValueAnimator怎么用
- ValueAnimator实例
ValueAnimator本身不会作用与任何一个属性,也不会提供任何一个动画,简单的来说她就是一个数值发生器,它可以产生你想要的各种数值,类型就是我们之前学的那些,int,float,等等,还可以自定义数值类型。
当我们继续深究其源码的时候,其实ObjectAnimator就是继承与ValueAnimator的。
下面我们写一个计时器的动画效果。
布局文件
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="点我看看" android:id="@+id/btnchange" android:onClick="change" android:layout_below="@+id/btnMove" android:layout_centerHorizontal="true" android:layout_marginTop="65dp" />
Activity文件
public class MainActivity extends ActionBarActivity implements View.OnClickListener { @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getSupportActionBar().hide(); setContentView(R.layout.activity_main); } //计时器 public void change(View v) { final Button btn = (Button) findViewById(R.id.btnchange); ValueAnimator animator = ValueAnimator.ofInt(0, 100); animator.setDuration(5000); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Integer integer = (Integer) animation.getAnimatedValue(); btn.setText("" + integer); } }); animator.start(); }
当我们点击Button的时候,Button上的数字由0到100的一个计时器动画效果,用时5s,数值由0到100,是不是比我们要开线程依次循坏来的简单,来的爽吧。
其中还有这么几个方法
如果我们想要自定义数值类型,就要用到ofObject()这个方法,下面我们来看看。
ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator() { @Override public Object evaluate(float fraction, Object startValue, Object endValue) { return null; } });
可以通过evaluate方法中三个参数的计算实现各种各样的效果,第一个参数时间差值器,范围0~1,第二个和第三个是开始值和结束值。
好了,属性动画到此告一段落,后续可能还会出,下面我们来总结一下:
常用属性
translationX/translationY:移动距离
rotation,rotationX,rotationY:旋转动画距离
scaleX,scaleY:缩放动画
X/Y:坐标移动
alpha:透明动画
虽然动画属性都一样,但是实现的效果和效率却是大大不一样的。
下面我们来看看常用的方法,类:
- ValueAnimator:数值发生器
- ObjectAnimator:通过此操作动画属性,从而实现一个动画效果
- AnimatorUpdateListener:动画监听器
- AnimatorListenerAdapter:动画监听器
- PropertyValuesHolder:多属性动画
- AnimatorSet:集合动画
- TypeEvaluators:值计算器
- Interpolators:差值器
Interpolators图示
希望大家可以自己继续探索属性动画的奥秘,我们一起学习!!!
- 2楼u0135396003小时前
- 哇哇哇~~~大神,我来做沙发~~~~
- 1楼qq_277711455小时前
- 大牛。。。