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 ...
随机推荐
- Linux学习之CentOS(八)----文件与目录的默认权限与隐藏权限(转)
文件与目录的默认权限与隐藏权限 一个文件有若干个属性, 包括读写运行(r, w, x)等基本权限,及是否为目录 (d) 与文件 (-) 或者是连结档 (l) 等等的属性! 要修改属性的方法在前面也约略 ...
- 数组中存放对象之java中定义类数组存放类
public class ClassArrayDemo { int age; String name; ClassArrayDemo(int age, String name) { this.age ...
- 关于ES7中的async/await在客户端和服务端上的实践
一.前言 在项目中经常遇到处理异步请求的情况,面对层层的嵌套,回调显示那么苍白无力: async / await是ES7的重要特性之一,也是目前社区里公认的优秀异步解决方案,既然这样就用上吧. 二.配 ...
- swiper实现臭美app滑动效果
一.臭美app效果: 我的需求是这样,上面正常滑动,点击下面的小卡牌,上面的滑动区也随之切换到当前的点击态. 二.实现: css: 主要设置可见区域的几张卡牌的位置,注意的几个位置是,中间的激活态和左 ...
- 关于在同一个DIV下的Hover效果问题
例子: (function bindColumnRowHoverEvent(){ $('.ticket_list_body .work_product').live('mouseenter', fun ...
- Python小代码_14_交换 2 个变量的 3 种方式
a = 4 b = 5 #第一种 c = a a = b b = c print(a, b) #输出结果 #5 4 #第二种 a = a + b b = a - b a = a - b print(a ...
- 解决Popup StayOpen=true时,永远置顶的问题
Popup设置了StayOpen=true时,会置顶显示. 如弹出了Popup后,打开QQ窗口,Popup显示在QQ聊天界面之上. 怎么解决问题? 获取绑定UserControl所在的窗口,窗口层级变 ...
- Promise--优雅的异步回调解决方案
当一个接口需要依赖另一个接口的请求数据时,通常有两种解决方式,一个是将请求数据的接口设为同步,之后调另一个接口,另一个是在请求数据接口的成功回调里调另一个接口. 但是:当一个接口需要依赖很多个接口的请 ...
- c#下winform的ftp上传
/* FTPFactory.cs Better view with tab space=4 Written by Jaimon Mathew (jaimonmathew@rediffmail.com) ...
- C++雾中风景8:Lambda表达式
上一篇C++的博客是Long Long ago了,前文讲到在看Lambda表达式的内容.笔者首次接触Lambda表达式应该是学习Python语言的时候,当时也不太明白这种表达方式的精髓,后续接触了Sc ...