Android动画
2015-06-12 09:27
447 查看
前言
Android系统支持原生动画,这为应用开发者开发绚丽的界面提供了极大的方便,有时候动画是很必要的,当你想做一个滑动的特效的时候,如果苦思冥想都搞不定,那么你可以考虑下动画,说不定动画轻易就搞定了。下面再简单回顾下Android中的动画,本文后面会介绍一个稍微复杂点的动画,先上效果图动画分类
View动画:也叫渐变动画,针对View的动画,主要支持平移、旋转、缩放、透明度Drawable动画:也叫帧动画,主要是设置View的背景,可以以动画的形式为View设置多张背景
对象属性动画(Android3.0新加入):可以对对象的属性进行动画而不仅仅是View,动画默认时间间隔300ms,默认帧率10ms/帧。其可以达到的效果是:在一个时间间隔内完成对象从一个属性值到另一个属性值的改变。因此,属性动画几乎是无所不能的,只要对象有这个属性,它都能实现动画效果,但是属性动画从Android3.0才有,这就严重制约了属性动画的使用,这就是开源动画库nineoldandroids的作用,采用nineoldandroids,可以在3.0以前的系统上使用属性动画,nineoldandroids的网址是:http://nineoldandroids.com。
说到属性动画,就不得不提到插值器(TimeInterpolator)和估值算法(TypeEvaluator),下面介绍。
TimeInterpolator和TypeEvaluator
TimeInterpolator中文翻译为时间插值器,它的作用是根据时间流逝的百分比来计算出当前属性值改变的百分比,系统预置的有LinearInterpolator(线性插值器:匀速动画)、AccelerateDecelerateInterpolator(加速减速插值器:动画两头慢中间快)和DecelerateInterpolator(减速插值器:动画越来越慢)等;TypeEvaluator的中文翻译为类型估值算法,它的作用是根据当前属性改变的百分比来计算改变后的属性值,系统预置的有IntEvaluator(针对整型属性)、FloatEvaluator(针对浮点型属性)和ArgbEvaluator(针对Color属性)。可能这么说还有点晦涩,没关系,下面给出一个实例就很好理解了。看上述动画,很显然上述动画是一个匀速动画,其采用了线性插值器和整型估值算法,在40ms内,View的x属性实现从0到40的变换,由于动画的默认刷新率为10ms/帧,所以该动画将分5帧进行,我们来考虑第三帧(x=20 t=20ms),当时间t=20ms的时候,时间流逝的百分比是0.5 (20/40=0.5),意味这现在时间过了一半,那x应该改变多少呢,这个就由插值器和估值算法来确定。拿线性插值器来说,当时间流逝一半的时候,x的变换也应该是一半,即x的改变是0.5,为什么呢?因为它是线性插值器,是实现匀速动画的,下面看它的源码:
public class LinearInterpolator implements Interpolator { public LinearInterpolator() { } public LinearInterpolator(Context context, AttributeSet attrs) { } public float getInterpolation(floatinput) { return input; } }
很显然,线性插值器的返回值和输入值一样,因此插值器返回的值是0.5,这意味着x的改变是0.5,这个时候插值器的工作就完成了。
具体x变成了什么值,这个需要估值算法来确定,我们来看看整型估值算法的源码:
说明:属性动画要求该属性有set方法和get方法(可选);插值器和估值算法除了系统提供的外,我们还可以自定义,实现方式也很简单,因为插值器和估值算法都是一个接口,且内部都只有一个方法,我们只要派生一个类实现接口就可以了,然后你就可以做出千奇百怪的动画效果。具体一点就是:自定义插值器需要实现Interpolator或者TimeInterpolator,自定义估值算法需要实现TypeEvaluator。还有就是如果你对其他类型(非int、float、color)做动画,你必须要自定义类型估值算法。
nineoldandroids介绍
其功能和android.animation.*中的类的功能完全一致,使用方法完全一样,只要我们用nineoldandroids来编写动画,就可以在所有的Android系统上运行。比较常用的几个动画类是:ValueAnimator、ObjectAnimator和AnimatorSet,其中ObjectAnimator继承自ValueAnimator,AnimatorSet是动画集,可以定义一组动画。使用起来也是及其简单的,下面举几个小栗子。栗子1:改变一个对象(myObject)的 translationY属性,让其沿着Y轴向上平移一段距离:它的高度,该动画在默认时间内完成,动画的完成时间是可以定义的,想要更灵活的效果我们还可以定义插值器和估值算法,但是一般来说我们不需要自定义,系统已经预置了一些,能够满足常用的动画。
布局xml如下:
<!-- ?xml version=1.0 encoding=utf-8? --> <framelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <button android:id="@+id/menu" style="@style/MenuStyle" android:background="@drawable/menu" > </button> <button android:id="@+id/item1" style="@style/MenuItemStyle" android:background="@drawable/circle1" android:visibility="gone" > </button> <button android:id="@+id/item2" style="@style/MenuItemStyle" android:background="@drawable/circle2" android:visibility="gone" > </button> <button android:id="@+id/item3" style="@style/MenuItemStyle" android:background="@drawable/circle3" android:visibility="gone" > </button> <button android:id="@+id/item4" style="@style/MenuItemStyle" android:background="@drawable/circle4" android:visibility="gone" > </button> <button android:id="@+id/item5" style="@style/MenuItemStyle" android:background="@drawable/circle5" android:visibility="gone" > </butto<span style="font-family: Arial, Helvetica, sans-serif;">n</span><span style="font-family: 宋体; font-size: 14.44444465637207px; text-indent: 2em;">></span>
</framelayout>
代码如下:
public class MainActivity extends Activity implements OnClickListener { private static final String TAG = MainActivity; private Button mMenuButton; private Button mItemButton1; private Button mItemButton2; private Button mItemButton3; private Button mItemButton4; private Button mItemButton5; private boolean mIsMenuOpen = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) private void initView() { mMenuButton = (Button) findViewById(R.id.menu); mMenuButton.setOnClickListener(this); mItemButton1 = (Button) findViewById(R.id.item1); mItemButton1.setOnClickListener(this); mItemButton2 = (Button) findViewById(R.id.item2); mItemButton2.setOnClickListener(this); mItemButton3 = (Button) findViewById(R.id.item3); mItemButton3.setOnClickListener(this); mItemButton4 = (Button) findViewById(R.id.item4); mItemButton4.setOnClickListener(this); mItemButton5 = (Button) findViewById(R.id.item5); mItemButton5.setOnClickListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { mMenuButton.performClick(); getMenuInflater().inflate(R.menu.main, menu); returnfalse; } @Override public void onClick(View v) { if(v == mMenuButton) { if(!mIsMenuOpen) { mIsMenuOpen = true; doAnimateOpen(mItemButton1,0,5,300); doAnimateOpen(mItemButton2,1,5,300); doAnimateOpen(mItemButton3,2,5,300); doAnimateOpen(mItemButton4,3,5,300); doAnimateOpen(mItemButton5,4,5,300); }else{ mIsMenuOpen = false; doAnimateClose(mItemButton1,0,5,300); doAnimateClose(mItemButton2,1,5,300); doAnimateClose(mItemButton3,2,5,300); doAnimateClose(mItemButton4,3,5,300); doAnimateClose(mItemButton5,4,5,300); } }else{ Toast.makeText(this, 你点击了 + v, Toast.LENGTH_SHORT).show(); } } /** * 打开菜单的动画 * @param view 执行动画的view * @param index view在动画序列中的顺序 * @param total 动画序列的个数 * @param radius 动画半径 */ private void doAnimateOpen(View view, intindex,inttotal,intradius) { if(view.getVisibility() != View.VISIBLE) { view.setVisibility(View.VISIBLE); } doubledegree = Math.PI * index / ((total - 1) * 2); inttranslationX = (int) (radius * Math.cos(degree)); inttranslationY = (int) (radius * Math.sin(degree)); Log.d(TAG, String.format(degree=%f, translationX=%d, translationY=%d, degree, translationX, translationY)); AnimatorSet set = newAnimatorSet(); //包含平移、缩放和透明度动画 set.playTogether( ObjectAnimator.ofFloat(view, translationX, 0, translationX), ObjectAnimator.ofFloat(view, translationY, 0, translationY), ObjectAnimator.ofFloat(view, scaleX, 0f, 1f), ObjectAnimator.ofFloat(view, scaleY, 0f, 1f), ObjectAnimator.ofFloat(view, alpha, 0f, 1)); //动画周期为500ms set.setDuration(1*500).start(); } /** * 关闭菜单的动画 * @param view 执行动画的view * @param index view在动画序列中的顺序 * @param total 动画序列的个数 * @param radius 动画半径 */ private void doAnimateClose(finalView view, intindex,inttotal, intradius) { if(view.getVisibility() != View.VISIBLE) { view.setVisibility(View.VISIBLE); } doubledegree = Math.PI * index / ((total - 1) * 2); inttranslationX = (int) (radius * Math.cos(degree)); inttranslationY = (int) (radius * Math.sin(degree)); Log.d(TAG, String.format(degree=%f, translationX=%d, translationY=%d, degree, translationX, translationY)); AnimatorSet set = newAnimatorSet(); //包含平移、缩放和透明度动画 set.playTogether( ObjectAnimator.ofFloat(view, translationX, translationX, 0), ObjectAnimator.ofFloat(view, translationY, translationY, 0), ObjectAnimator.ofFloat(view, scaleX, 1f, 0f), ObjectAnimator.ofFloat(view, scaleY, 1f, 0f), ObjectAnimator.ofFloat(view, alpha, 1f, 0f)); //为动画加上事件监听,当动画结束的时候,我们把当前view隐藏 set.addListener(newAnimatorListener() { @Override publicvoidonAnimationStart(Animator animator) { } @Override publicvoidonAnimationRepeat(Animator animator) { } @Override publicvoidonAnimationEnd(Animator animator) { view.setVisibility(View.GONE); } @Override publicvoidonAnimationCancel(Animator animator) { } }); set.setDuration(1*500).start(); } }
相关文章推荐
- 关于Android Studio加载第三方jar包无法编译的问题解决。
- Android之应用开发基础
- Android studio 使用问题汇总(1、字体大小问题 2、导入第三方类库问题 3、APK如何发布)
- Android中文API——DatePicker&TimePicker
- Android libmp3lame详解
- Android Studio入门指南
- Android studio运行加速教程
- Android Studio上的几个插件介绍
- android studio如何使用git
- Android studio 导出jar包并混淆和aar
- Android Studio添加插件(Genymotion)
- Android studio Gradle项目结构
- 加速Android Studio/Gradle构建
- Android Studio中获取sha1证书指纹数据的方法
- android 录像和拍照功能
- android studio快捷键集合
- Android Studio的设置教程
- Android studio 安装中遇到一些问题的解决办法
- 谷歌开发工具Android Studio安装使用图文教程
- Android Studio安装及配置心得