ViewPropertyAnimator
android 3.0虽然引入的属性动画,既能针对一些系统定义的属性如setAphla()、setScale()做动画,也能自定义属性;我们日常使用中存储需要为这些默认的属性设置动画,但通过属性动画使用显得很繁琐不人性化,于是android 3.1补充了ViewPropertyAnimator这个机制;
ViewPropertyAnimator animator=view.animator();
animator.alpha(0f);
通过ViewProertyAnimator对象的函数来设置需要实现动画的属性,同时也不需要像之前的属性动画调用start()方法开始动画,它是自动开始的(隐式启动的);
关于ViewPropertyAniamtor常用函数
//设置透明度
alpha(float value)
//设置Y轴方向缩放
scaleY(float value)
scaleX(float value)
//X轴方向的移动值
translationX(...)
translationY()
rotationX(...)
rotationY()
//相对于父容器的左上角坐标在X的的最终位置
x(float value)
//相对于父容器的左上角的坐标在Y轴的方向的最终位置
y(float vlaue)
//设置透明度增量
alphaBy(float value)
rotationBy(float value)
rotationXBy()
rotationYBy()
translationXBy()
translationYBy()
scaleXBy()
scaleYBy()
xBy()
yBy()
setInterpolator(TimeInterpolator interpolator)
setStartDelay(long startDelay)
setDuration(long duration)
这里主要说一下x(float value)对应android 3.0中新增加的setX(float value),用于将控件移动到指定位置;这个位置是以父容器左上角为坐标原点的;
和属性动画一样,也可以设置监听器如:
view.animate().scaleY(2).setListener(new Animator.AnimatorListener(){
public void onAimationStart(Animator aniamtor){
}
public viod onAnimationEnd(Animator animator){
}
.......
});
性能的提升
和ObjectAnimator不同的是,ViewPropertyAnimator没有使用反射或者JNI技术,而是根据预设的每一个动画帧计算出对应的所有属性值,并设置给控件,然后调用一次invalidate()函数进行重绘,从而解决了使用ObjectAnimator时每个属性单独计算、单独重绘的问题;
- ObjectAnimator构建动画过程相对于ViewpropertyAnimator根繁琐
- 同时为View多个属性做动画时,后者更方便;
为ViewGroup中的组件添加动画
前面讲的ValueAnimator、ObjectAnimator、AnimatorSet都只能针对一个控件做动画,如果要实现对ViewGroup中的所有控件统一做入场、出厂动画等,是无法实现的;比如:为ListView的item入场、出场、数据变更是添加动画;
android提供了四种方法:
- layoutAnimation标签与LayoutAnimationController
android:layoutAnimation:标签在API1就引入,专门针对ListView添加入场动画所使用的,后者为其代码实现,它可以在ListView创建时对其中的每个Item添加入场动画,而且动画可以自定义;缺点:ListView创建完成后,如果在添加数据,则新添加的数据不会有入场动画;
- gridLayoutAnimation标签与GridLayoutAnimationController
专门针对GridView添加入场动画的,和上面的大同小异,gridView创建完成后,在添加数据,新添加的数据不会有入场动画;
- android:animatedLayoutChanged=false/true属性
所有派生自ViewGroup的控件都具有此属性,只要在布局文件中添加这个属性,就能实现添加、删除其中控件时带有的默认动画,缺点:该动画不能自定义;
- LayoutTransition
android API 11引入,实现ViewGroup动态添加或者删除控件动画,动画可以自定义
LayoutTransition
上面四种方式,无疑LayoutTransition是最强大的,我们看看如何使用:
-
创建实例
-
创建动画并进行设置
-
将layoutTransition设置到ViewGroup
LayoutTransition transitioner=new LayoutTransition(); ObjectAniamtor animator=ObjectANimator.ofFloat(null,"rotation",0f,90f,0f); transitioner.setAnimatior(LayoutTransition.DISAPPEARING,animtor); vp.setLayoutTransition(transition);
需要注意的就是:setAnimator(int transitionType,Animator animator);
第一个参数取值:
APPEARING:元素在容器中出现时定义的动画;
DISAPPEARING:元素在容器中消失时所定义的动画
CHANGE_APPEARING:容器中要显示一个新的元素,其他元素需要变化的元素所应用的动画
CHANGE_DISAPPEARING:容器中某个元素消失时,其他需要变化的元素所应用的动画
这里ChANGE_APPEARING和CHANGE_DISAPPEARING在使用时有许多坑:
- 必须使用PropertyValuesHolder构造的动画才有效果,使用ObjectAnimator构造的动画没有效果;
- 在构造PropertyValuesHolder动画时,“left”、"top"属性的变动是必须的写,即使不需要变动也要写即:PropertyValuesHolder holderLeft=PropertyValuesHolder.ofInt(“left”,0,0);PropertyValuesHolder holderTop=PropertyValuesHolder.ofInt(“top”,0,0);
- 在构造PropertyValuseHolder动画时,所有ofInt、ofFloat()参数值第一个和最后一个必须相同,否则此属性的动画将会被放弃,得不到效果;
这里简单演示下往LinearLayout中添加和删除控件动画效果:
PropertyValuesHolder valuesHolder = PropertyValuesHolder.ofObject("textCharacter", new CharacterEvaluator(), new Character('A'), new Character('Z'));
animator = ObjectAnimator.ofPropertyValuesHolder(view, valuesHolder);
animator.setDuration(20000);
PropertyValuesHolder holder1= PropertyValuesHolder.ofFloat("scaleX", 1f, 0.5f, 1f);
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("rotation", 0, 90f, 150f, 360, 0f);
PropertyValuesHolder holder = PropertyValuesHolder.ofInt("left", 0, 0);
PropertyValuesHolder holder3 = PropertyValuesHolder.ofInt("top", 0, 0);
ValueAnimator animatorIn = ObjectAnimator.ofPropertyValuesHolder(mContainer,holder1,holder,holder3);
ValueAnimator animatorOut = ObjectAnimator.ofPropertyValuesHolder(mContainer,holder2,holder,holder3);
LayoutTransition transition = new LayoutTransition();
transition.setDuration(2000);
transition.setAnimator(LayoutTransition.CHANGE_APPEARING,animatorIn);
transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING,animatorOut);
mContainer.setLayoutTransition(transition);
.....
case R.id.add:
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
Button button = new Button(this);
int i = new Random().nextInt(10);
button.setText(""+i);
button.setTextSize(40);
mContainer.addView(button,0,params);
break;
case R.id.dis:
mContainer.removeViewAt(0);
break;
TransitionLayout的函数
//设置所有动画完成需要的时长
setDuration(long duration);
//针对APPEARING等单个设置时长
setDuration(int transitionType,long duration)
//针对单个Type设置插值器
setInterpolator(int transitionType,TimeInterpolator interpolator)
//针对每个Type设置每个item动画的时间间隔
public void setStagger(int transitionType,long duration)
setDurationDelay(int transitionType,long delay)
同时也提供了监听函数
public void addTransitionListener(TransitionListener listener)
public interface TransitionListener {
//container:当前应用LayoutTransition的容器
//view:当前在做动画的View
public void startTransition(LayoutTransition transition, ViewGroup container,View view, int transitionType);
public void endTransition(LayoutTransition transition, ViewGroup container,View view, int transitionType);
}
就以上面的动画为例,这里的view应该是LinearLayout,如果是APPEARING、DISAPPEARING类型,那么这里View就变成了添加或者删除的那个View了;
sition(LayoutTransition transition, ViewGroup container,View view, int transitionType);
}
就以上面的动画为例,这里的view应该是LinearLayout,如果是APPEARING、DISAPPEARING类型,那么这里View就变成了添加或者删除的那个View了;