android 动画后动画效果,Android动画分析(对任意属性做动画效果)

上篇文章中,我们曾经提到过,ObjectAnimator实现动画效果是,可以这样写:

ObjectAnimator

.ofFloat(myView, "rotationX", 0.0F, 360.0F)

.setDuration(500)//

.start();

上篇文章说过,第二个参数是指属性的名字,例如rotationX,但是如果我们随便写个值的话,轻者则无动画效果,重者可能会崩溃,为什么呢?今天就来说说原因

举个例子,给Button加一个动画,让这个Button的宽度从当前宽度增加到500,也许你可能会这样想:

ObjectAnimator

.ofFloat(mButton, "width", 500)

.setDuration(500)//

.start();

可是,当运行时,你会发现没有任何效果,为什么呢?其实,我们如果知道属性动画的原理,就很容易理解了

属性动画原理

属性动画要求做动画效果的属性需要提供get和set的方法,属性动画根据外界传递的该属性的初始值和最终值,以动画的效果多次去调用set方法,每次传递set方法的值都不一样,随着时间的推移,越来越接近最终值,所以,总的来说,需要动画生效,需满足两个条件:

(1)对象的属性必须提供set和get方法

(2)set方法可以带来效果,比如我setWidth后,宽度会带来UI的变化,否则你也看不出变化是吧

在回到我们的例子上,有人可能会说,Button提供了setWidth方法啊,为什么还是不行呢?别着急,我们来看看setWidth的源码:

/**

* Makes the TextView exactly this many pixels wide.

* You could do the same thing by specifying this number in the

* LayoutParams.

*

* @see #setMaxWidth(int)

* @see #setMinWidth(int)

* @see #getMinWidth()

* @see #getMaxWidth()

*

* @attr ref android.R.styleable#TextView_width

*/

@android.view.RemotableViewMethod

public void setWidth(int pixels) {

mMaxWidth = mMinWidth = pixels;

mMaxWidthMode = mMinWidthMode = PIXELS;

requestLayout();

invalidate();

}

Button是继承TextView,setWidth是TextView和子类专属的方法,我们从源码中不难看出,它的作用不是设置宽度,而是设置最大宽度和最小宽度,也就是说跟我们想要设置Button宽度是两个东西,具体来说,TextView的宽度对应的是xml中的android:layout_width,而setWidth对应的是xml中的android:width,所以没有动画效果也是正常的,那如果我的需求就是类似这样的情况,我们怎么办呢?别着急,谷歌早就帮我们想好了

类似这样的情况,官方文档告诉我们有3种解决方法:

(1)给属性加上get和set的方法

(2)用一个类来封装原始对象,并提供get和set方法

(3)采用ValueAnimator,监听动画过程,自己实现属性的变化

首先我们来分别看看这几个方法:

方法1:

我们首先就可以排除了,我们不可能去修改Button的源码,给它加上get和set方法

方法2:

是一个很有用的解决方法,也是最普遍的,很方便也很好理解,我们看看例子

public class MyButton {

private View mView;

public MyButton(View view) {

this.mView = view;

}

public int getWidth() {

return mView.getWidth();

}

public void setWidth(int width) {

mView.getLayoutParams().width = width;

mView.requestLayout();

}

}

我们先定义一个类来封装我们的Button,然后提供get和set方法,再来我们就可以调用了:

MyButton button =new MyButton(new Button(this));

ObjectAnimator.ofInt(button,"width",500).setDuration(500).start();

没错,就是如此简单

方法3

如果大家对ValueAnimator熟悉的话就知道,它不作用于任何对象,也就是说直接使用它是没有动画效果的,我们需要它对一个值做动画,然后监听变化过程,在变化过程中修改我们对象的属性值,就相当于我们对象做动画了

ValueAnimator animator = ValueAnimator.ofInt(1, 100);

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

//获取当前动画进度值,1-100之间

int value = (int) animation.getAnimatedValue();

//获取当前进度占整个动画过程比例,0-1之间

float fraction = animation.getAnimatedFraction();

//直接调用估值器,通过比例计算宽度,然后再赋值给Button

IntEvaluator evaluator =new IntEvaluator();

mButton.getLayoutParams().width=evaluator.evaluate(fraction,mButton.getWidth(),500);

mButton.requestLayout();

}

});

animator.setDuration(500).start();

它在500ms内将一个数从1到100,然后动画的每一帧都会回调onAnimationUpdate方法,因此,我们可以获取当前的值和当前值所占的比例,在计算出Button当前的宽度应该是多少,比如时间过了一半,当前值是50,比例是0.5,假设Button的起始宽度是100,最终宽度是500,那么Button增加的宽度也应该占总增加宽度的一半,总增加的宽度是500-100=400,所以这时候Button应该增加的宽度是400*0.5=200,那么当前Button的宽度应该为初始宽度+增加宽度(100+200=300),这个计算IntEvaluator 估值器已经帮我们实现了,因此我们直接用就可以了

注意事项

动画可以为我们带来很多炫酷的效果,但同时也有很多需要注意的地方,主要分为这几类:

OOM

这个问题主要出现在帧动画中,因为帧动画是用多张图片轮播实现动画效果,那么如果图片过大就很容易出现OOM

内存泄漏

在属性动画中,有一类无限循环的动画,这类动画需要在Activity退出的时候及时停止,否则会导致无法释放从而导致内存泄漏,View动画没存在这问题

兼容性

动画是3.0以下的系统兼容性会存在问题,因此需要做好兼容工作

View动画的问题

View动画是对view的影像做动画,并不是真正的去改变view的状态,因此有时候会出现动画完成后view无法隐藏的现象,即setVisibility(GONE)失效,这时候只要调用view.clearAnimation()清除view动画即可

不要使用px

在进行动画过程中,单位尽量用dp,使用px可能导致在不同设备上效果不一样

动画过后交互

view动画还是属性动画效果完成后,view的位置是不会发生改变的,也就是说view的位置还是在原来的位置,尽管view的视觉已经改变,位置是不发生变化,仅仅只是视觉的变化

好了,这篇文章到这就结束了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值