Android动画深入分析
动画分类
Android动画可以分3种:View动画,帧动画和属性动画;属性动画为API11的新特性,在低版本是无法直接使用属性动画的,但可以用nineoldAndroids来实现(但是本质还是viiew动画)。学习本篇内容主要掌握以下知识:
1,View动画以及自定义View动画。
2,View动画的一些特殊使用场景。
3,对属性动画做了一个全面的介绍。
4,使用动画的一些注意事项。
view动画
android:shareInterpolator表示集合中的动画是否和集合共享同一个插值器,如果集合不指定插值器,那么子动画就需要单独指定所需的插值器或默认值。
view动画应用场景
<?xml version="1.0" encoding="utf-8"?> <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" android:animationOrder="normal" android:delay="0.3" android:animation="@anim/anim_item"/> //--- animationOrder 表示子元素的动画的顺序,有三种选项: //normal(顺序显示)、reverse(逆序显示)和random(随机显示)。 <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:shareInterpolator="true"> <alpha android:fromAlpha="0.0" android:toAlpha="1.0" /> <translate android:fromXDelta="300" android:toXDelta="0" /> </set>
第一种,在布局中引用LayoutAnimation
<ListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:layoutAnimation="@anim/anim_layout"/>
第二种,代码种使用
Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item); LayoutAnimationController controller = new LayoutAnimationController(animation); controller.setDelay(0.5f); controller.setOrder(LayoutAnimationController.ORDER_NORMAL); listview.setLayoutAnimation(controller);
帧动画
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@mipmap/lottery_1" android:duration="200" /> // ...省略很多 <item android:drawable="@mipmap/lottery_6" android:duration="200" /> </animation-list>
然后
imageView.setImageResource(R.drawable.frame_anim); AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable(); animationDrawable.start();//启动start,关闭stop
属性动画
属性动画作用属性
<set android:ordering=["together" | "sequentially"]> <objectAnimator android:propertyName="string" android:duration="int" android:valueFrom="float | int | color" android:valueTo="float | int | color" android:startOffset="int" android:repeatCount="int" android:repeatMode=["repeat" | "reverse"] android:valueType=["intType" | "floatType"]/> <animator android:duration="int" android:valueFrom="float | int | color" android:valueTo="float | int | color" android:startOffset="int" android:repeatCount="int" android:repeatMode=["repeat" | "reverse"] android:valueType=["intType" | "floatType"]/> <set> ... </set> </set>
<set>
android:valueFrom --------变化开始值
android:valueTo ------------变化结束值
android:valueType -------变化值类型 ,它有两种值:intType和floatType,默认值floatType。
android:duration ---------持续时间
android:valueTo
android:duration
android:startOffset
android:repeatCount
android:repeatMode
android:valueType
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.anim.property_animator); set.setTarget(myObject);//myObject表示作用的对象 set.start();
插值器和估值器
public class IntEvaluator implements TypeEvaluator<Integer> { public Integer evaluate(float fraction, Integer startValue, Integer endValue) { int startInt = startValue; return (int)(startInt + fraction * (endValue - startInt)); } }
上述代码就是计算当前属性所占总共的百分百。
属性动画监听器
public static interface AnimatorListener { void onAnimationStart(Animator animation); //动画开始 void onAnimationEnd(Animator animation); //动画结束 void onAnimationCancel(Animator animation); //动画取消 void onAnimationRepeat(Animator animation); //动画重复播放 }
AnimatorUpdateListener
public static interface AnimatorUpdateListener { void onAnimationUpdate(ValueAnimator animator); }
应用场景
- 给你的对象加上get和set方法,如果你有权限的话
- 用一个类来包装原始对象,间接提高get和set方法
- 采用ValueAnimator,监听动画执行过程,实现属性的改变
有了上面的说明,我们大致明白了,要实现开始说的这个问题的效果,我们需要用一个间接的类来实现get和set方法或者自己实现一个ValueAnimator。
public class ViewWrapper { private View target; public ViewWrapper(View target) { this.target = target; } public int getWidth() { return target.getLayoutParams().width; } public void setWidth(int width) { target.getLayoutParams().width = width; target.requestLayout(); } }
第二种,采用ValueAnimator,监听动画过程。
private void startValueAnimator(final View target, final int start, final int end) { ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { private IntEvaluator mEvaluation = new IntEvaluator();//新建一个整形估值器作为临时变量 @Override public void onAnimationUpdate(ValueAnimator animation) { //获得当前动画的进度值 1~100之间 int currentValue = (int) animation.getAnimatedValue(); //获得当前进度占整个动画过程的比例,浮点型,0~1之间 float fraction = animation.getAnimatedFraction(); //调用估值器,通过比例计算出宽度 int targetWidth = mEvaluation.evaluate(fraction, start, end); target.getLayoutParams().width = targetWidth; //设置给作用的对象,刷新页面 target.requestLayout(); } }); }
属性动画的工作原理
private void start(boolean playBackwards) { if(Looper.myLooper() == null) { throw new AndroidRuntimeException("Animators may only be run on Looper threads"); } else { this.mPlayingBackwards = playBackwards; this.mCurrentIteration = 0; this.mPlayingState = 0; this.mStarted = true; this.mStartedDelay = false; ((ArrayList)sPendingAnimations.get()).add(this); if(this.mStartDelay == 0L) { this.setCurrentPlayTime(this.getCurrentPlayTime()); this.mPlayingState = 0; this.mRunning = true; if(this.mListeners != null) { ArrayList animationHandler = (ArrayList)this.mListeners.clone(); int numListeners = animationHandler.size(); for(int i = 0; i < numListeners; ++i) { ((AnimatorListener)animationHandler.get(i)).onAnimationStart(this); } } } ValueAnimator.AnimationHandler var5 = (ValueAnimator.AnimationHandler)sAnimationHandler.get(); if(var5 == null) { var5 = new ValueAnimator.AnimationHandler(null); sAnimationHandler.set(var5); } var5.sendEmptyMessage(0); } }
private static final ThreadLocal<ArrayList<ValueAnimator>> sAnimations = new ThreadLocal() { protected ArrayList<ValueAnimator> initialValue() { return new ArrayList(); } }; private static final ThreadLocal<ArrayList<ValueAnimator>> sPendingAnimations = new ThreadLocal() { protected ArrayList<ValueAnimator> initialValue() { return new ArrayList(); } }; private static final ThreadLocal<ArrayList<ValueAnimator>> sDelayedAnims = new ThreadLocal() { protected ArrayList<ValueAnimator> initialValue() { return new ArrayList(); } }; private static final ThreadLocal<ArrayList<ValueAnimator>> sEndingAnims = new ThreadLocal() { protected ArrayList<ValueAnimator> initialValue() { return new ArrayList(); } }; private static final ThreadLocal<ArrayList<ValueAnimator>> sReadyAnims = new ThreadLocal() { protected ArrayList<ValueAnimator> initialValue() { return new ArrayList(); } };
这里系统怎么计算每一帧的动画的呢,看看下面的代码
void animateValue(float fraction) { fraction = this.mInterpolator.getInterpolation(fraction); this.mCurrentFraction = fraction; int numValues = this.mValues.length; int numListeners; for(numListeners = 0; numListeners < numValues; ++numListeners) { this.mValues[numListeners].calculateValue(fraction); } if(this.mUpdateListeners != null) { numListeners = this.mUpdateListeners.size(); for(int i = 0; i < numListeners; ++i) { ((ValueAnimator.AnimatorUpdateListener)this.mUpdateListeners.get(i)).onAnimationUpdate(this); } } }
不过我们知道要改变动画,一定调用了get/set方法,那我们重点看下这相关的代码。这段代码在setProperty方法里面
public void setProperty(Property property) { if(this.mValues != null) { PropertyValuesHolder valuesHolder = this.mValues[0]; String oldName = valuesHolder.getPropertyName(); valuesHolder.setProperty(property); this.mValuesMap.remove(oldName); this.mValuesMap.put(this.mPropertyName, valuesHolder); } if(this.mProperty != null) { this.mPropertyName = property.getName(); } this.mProperty = property; this.mInitialized = false; }
这里有一个PropertyValuesHolder,顾名思义这是一个操作数据的类,和我们的adapter的Holder差不多,该方法的get方法主要用到了反射。
private void setupValue(Object target, Keyframe kf) { if(this.mProperty != null) { kf.setValue(this.mProperty.get(target)); } try { if(this.mGetter == null) { Class e = target.getClass(); this.setupGetter(e); } kf.setValue(this.mGetter.invoke(target, new Object[0])); } catch (InvocationTargetException var4) { Log.e("PropertyValuesHolder", var4.toString()); } catch (IllegalAccessException var5) { Log.e("PropertyValuesHolder", var5.toString()); } }
代码就看到这,有兴趣的可以去看下源码
使用属性动画需要注意的事项
Android动画深入分析的更多相关文章
- 《Android开发艺术探索》读书笔记 (7) 第7章 Android动画深入分析
本节和<Android群英传>中的第七章Android动画机制与使用技巧有关系,建议先阅读该章的总结 第7章 Android动画深入分析 7.1 View动画 (1)android动画分为 ...
- Android 动画深入分析
一些娱乐动画安德鲁斯被广泛使用应用上述的.在不牺牲性能,它可以带来非常好的体验,下面会解释具体的实现安卓动画.知识的学校一个明确清晰的白色. 动画类型 Android的animation由四种类型组成 ...
- 第七章:Android动画深入分析
7.1 View动画 View动画的作用对象是View,它支持四种动画效果,分别是平移动画,缩放动画,旋转动画和透明动画. 帧动画也属于View动画,但是帧动画的表现形式和上面的四种变换效果不太一样. ...
- Android 动画animation 深入分析
转载请注明出处:http://blog.csdn.net/farmer_cc/article/details/18259117 Android 动画animation 深入分析 前言:本文试图通过分析 ...
- 深入分析Android动画(二)
上回书说到Android动画的分类以及基本使用,这会书主要说Android属性动画的原理,对于View动画的原理本篇不做深入分析.对于Android动画的基础请看深入分析Android动画(一) 我们 ...
- 深入分析Android动画(一)
动画的分类: ①View动画 View动画顾名思义其作用对象为View,包含平移.缩放.旋转.透明,这四类变化分别对应着Animation的子类TranlateAnimation.ScaleAnima ...
- Android动画效果之自定义ViewGroup添加布局动画
前言: 前面几篇文章介绍了补间动画.逐帧动画.属性动画,大部分都是针对View来实现的动画,那么该如何为了一个ViewGroup添加动画呢?今天结合自定义ViewGroup来学习一下布局动画.本文将通 ...
- Android动画效果之Property Animation进阶(属性动画)
前言: 前面初步认识了Android的Property Animation(属性动画)Android动画效果之初识Property Animation(属性动画)(三),并且利用属性动画简单了补间动画 ...
- Android动画效果之初识Property Animation(属性动画)
前言: 前面两篇介绍了Android的Tween Animation(补间动画) Android动画效果之Tween Animation(补间动画).Frame Animation(逐帧动画)Andr ...
随机推荐
- gulp填坑记(二)——gulp多张图片自动合成雪碧图
为优化图片,减少请求会把拿到切好的图标图片,通过ps(或者其他工具)把图片合并到一张图里面,再通过css定位把对于的样式写出来引用的html里面,对于一些图片较多的项目,这个过程可能要花费我们一天的时 ...
- redis锁处理并发问题
redis锁处理并发问题 redis锁处理高并发问题十分常见,使用的时候常见有几种错误,和对应的解决办法. set方式 setnx方式 setnx+getset方式 set方式 加锁:redis中se ...
- Angular5学习笔记 http请求
在anular4更新到angular5后,有些模块也发生了有些变化,例如http模块. 首先在app.module.ts里面引入HttpClientModule import { HttpClient ...
- Python的一个解释凯撒密码的程序
#!/usr/bin/env python # -*- coding: utf-8 -*- ''' { Title:CaserCode Author:naiquan Type:crypto Detai ...
- 网络编程练习这些就ok
1,什么是C/S架构? C指的是client(客户端软件),S指的是Server(服务端软件) 一个C/S架构就是,实现服务端软件与客户端软件基于网络通信. 互联网中处处是C/S架构 如123 ...
- Node.js 模块系统
为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统. 模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的.换言之,一个 Node.js 文件就是一个模块, ...
- jboss规则引擎KIE Drools 6.3.0 Final 教程(3)
在前2部教程中,介绍了如何在本地运行.drools文件以及使用stateless的方法访问远程repository上的规则. KIE Drools还提供了一种叫有状态-stateful的访问方式. 运 ...
- shell编程--流程控制for,do-while,if-then,break,continue,case等
2.5 流程控制 2.5.1 if语法 1.语法格式 if condition then statements [elif condition then statements. ..] ...
- [ExtJS5学习笔记]第三十四节 sencha extjs 5 grid表格之java后台导出excel
继上次使用js前端导出excel之后,还有一个主要大家比较关注的是后台实现导出excel,因为本人开发使用的java所以这里使用apache的开源项目poi进行后台excel的导出. 本文目录 本文目 ...
- Java使用BigDecimal保留double、float运算精度、保留指定位数有效数字、四舍五入
工具类 package --; import java.math.BigDecimal; /** * Created by kongqw on 2015/12/10. */ public final ...