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 ...
随机推荐
- jQuery extend 方法使用 (转)
方法介绍 jQuery 的 API 手册中,extend 方法挂载在 jQuery 和 jQuery.fn 两个不同的对象上,但在 jQuery 内部代码实现的是相同的,只是功能各不相同. 先看看官方 ...
- Socket.io应用之联网拖拽游戏
服务器端代码: const express=require('express'); const http=require('http'); const sio=require('socket.io') ...
- 【问底】徐汉彬:亿级Web系统搭建——单机到分布式集群
http://www.csdn.net/article/2014-11-06/2822529/3 大规模流量的网站架构,从来都是慢慢"成长"而来.而这个过程中,会遇到很多问题,在不 ...
- 未能加载 global.asax的类的解决方案
“/suitecallback”应用程序中的服务器错误. 分析器错误 说明: 在分析向此请求提供服务所需资源时出错.请检查下列特定分析错误详细信息并适当地修改源文件. 分析器错误消息: 未能加载类型“ ...
- 无忧代理免费ip爬取(端口js加密)
起因 为了训练爬虫技能(其实主要还是js技能-),翻了可能有反爬的网站挨个摧残,现在轮到这个网站了:http://www.data5u.com/free/index.shtml 解密过程 打开网站,在 ...
- jQuery 效果 – 滑动
jQuery 滑动方法可使元素上下滑动. 点击这里,隐藏/显示面板 一寸光阴一寸金,因此,我们为您提供快捷易懂的学习内容. 在这里,您可以通过一种易懂的便利的模式获得您需要的任何知识. 实例 jQue ...
- JavaScript Boolean(布尔)对象
Boolean(布尔)对象用于将非布尔值转换为布尔值(true 或者 false). Boolean(布尔)对象是三种包装对象:Number.String和Boolean中最简单的一种,它没有大量的实 ...
- Android 学习笔记一 自定义按钮背景图
入门学到的一些组件都是比较规矩的,但在实际应用中,我们需要更多特色的组件,例如一个简单的Button,所以我们必须要自定义它的属性. 遇到的问题:用两张图片来代替按钮,分别表示点击前后 解决方法:用I ...
- 浏览器加载和渲染html的顺序(html/css/js)
最近在学习前端的技术,把html.js.css的基础知识看了看.感觉越看越觉得前端并不比后端容易,技术含量还是相当大的.今天突然想弄明白浏览器到底是怎么加载和渲染html的?html中的DOM.js文 ...
- linux TCP数据包封装在SKB的过程分析
在linux中 tcp的数据包的封装是在函数tcp_sendmsg开始的,在函数tcp_sendmsg中用到skb = sk_stream_alloc_skb(sk, select_size(sk, ...