属性动画的基本使用

  • 属性动画简介

Android开发过程中,适当的使用一些动画可以让自己的应用看起来更棒更炫。最初的时候Google为了实现动画,主要提供了两种基本动画:
帧动画:将一个完整的动画拆分成一张张单独的图片,然后再将它们连贯起来进行播放
补间动画:无需逐一定义每一帧,只要定义开始、结束的帧,和指定动画持续时间。
到了Android3.0,Google推出了一种新的动画模式,属性动画。属性动画是对补间动画的进一步完善和强化。

  • 为什么引入属性动画:

关于这个问题,可以借鉴一下郭霖的一段话:
补间动画机制其实还算是比较健全的,可以让我们实现View的移动、缩放、旋转和淡入淡出效果,并且我们还可以借助AnimationSet来将这些动画效果组合起来使用,除此之外还可以通过配置Interpolator来控制动画的播放速度等等等等。那么这里大家可能要产生疑问了,既然之前的动画机制已经这么健全了,为什么还要引入属性动画呢?
其实上面所谓的健全都是相对的,如果你的需求中只需要对View进行移动、缩放、旋转和淡入淡出操作,那么补间动画确实已经足够健全了。但是很显然,这些功能是不足以覆盖所有的场景的,一旦我们的需求超出了移动、缩放、旋转和淡入淡出这四种对View的操作,那么补间动画就不能再帮我们忙了,也就是说它在功能和可扩展方面都有相当大的局限性,那么下面我们就来看看补间动画所不能胜任的场景。
注意上面我在介绍补间动画的时候都有使用“对View进行操作”这样的描述,没错,补间动画是只能够作用在View上的。也就是说,我们可以对一个Button、TextView、甚至是LinearLayout、或者其它任何继承自View的组件进行动画操作,但是如果我们想要对一个非View的对象进行动画操作,抱歉,补间动画就帮不上忙了。可能有的朋友会感到不能理解,我怎么会需要对一个非View的对象进行动画操作呢?这里我举一个简单的例子,比如说我们有一个自定义的View,在这个View当中有一个Point对象用于管理坐标,然后在onDraw()方法当中就是根据这个Point对象的坐标值来进行绘制的。也就是说,如果我们可以对Point对象进行动画操作,那么整个自定义View的动画效果就有了。显然,补间动画是不具备这个功能的,这是它的第一个缺陷。
然后补间动画还有一个缺陷,就是它只能够实现移动、缩放、旋转和淡入淡出这四种动画操作,那如果我们希望可以对View的背景色进行动态地改变呢?很遗憾,我们只能靠自己去实现了。说白了,之前的补间动画机制就是使用硬编码的方式来完成的,功能限定死就是这些,基本上没有任何扩展性可言。
最后,补间动画还有一个致命的缺陷,就是它只是改变了View的显示效果而已,而不会真正去改变View的属性。什么意思呢?比如说,现在屏幕的左上角有一个按钮,然后我们通过补间动画将它移动到了屏幕的右下角,现在你可以去尝试点击一下这个按钮,点击事件是绝对不会触发的,因为实际上这个按钮还是停留在屏幕的左上角,只不过补间动画将这个按钮绘制到了屏幕的右下角而已。正是因为这些原因,功能更为完善和强大的属性动画就应运而生了。

  • 继承关系

继承关系

从图中可以看出,补间动画主要是使用android.view.animation.Animation包下面的五个类来实现不同的动画效果;而属性动画主要是使用android.animation.Animator的ValueAnimator以及其子类ObjectAnimator来实现不同的动画效果。

  • ValueAnimator

从属性动画相关对象的继承关系可以看出,ValueAnimator是比较核心的一个类。官方文档的介绍是:this class provides a simple timing engine for running animations which calculate animated values and set them on target objects…也就是说ValueAnimator对象内部维持了一个简单的时间引擎,计算运行动画的具体值同时把它们设置给目标对象。通俗的讲就是,ValueAnimator的内部使用一种时间循环的机制来计算值与值之间的动画过渡,我们只需要将初始值和结束值或者中间值提供给ValueAnimator,并且设置动画运行时长,那么ValueAnimator就会自动完成从初始值平滑过渡到结束值这样的效果。而且,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等。说的废话比较多,先举个栗子,切身体会一下!

1.效果图

ValueAnimator

2.具体代码

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f);
valueAnimator.setDuration(3000);
//设置监听,把当前AnimatedValue的值时时显示到EditText上面
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float currentValue = (float) animation.getAnimatedValue();
        StringBuilder sb = new StringBuilder();
        et_Animator.setText(sb.append(currentValue).toString());
    }
});
valueAnimator.start();

ValueAnimator比较常用的方法有:设置AnimatorValue区间范围的三个主要方法
ofFloat(),ofInt(),ofObject()
还有设置延时播放时间的setStartDelay()方法,设置重复次数的setRepeatCount()方法,设置重复模式的setRepeatMode()
暂停动画的pause()方法,恢复动画的resume()等等,还有很多方法,具体大家可以查阅文档,把这个核心类的方法掌握了,使用ObjectAnimator就能更加得心应手,因为从继承关系中我们可以知道ObjectAnimator是ValueAnimator的子类。

  • ObjectAnimator

ObjectAnimator对象应该是我们产生属性动画效果最常用的类了,ValueAnimator仅仅是对数值进行平滑的过渡变化,而如果我们想对一个对象的任意属性进行动画效果,就需要使用ObjectAnimator对象了,还是先举个简单栗子吧。

1.效果图

Alpha动画

2.具体代码

//ofFloat(需要实现动画的控件ID,需要实现的动画效果名称,变化的区间范围)
ObjectAnimator objAnim = bjectAnimator.ofFloat(et_Animator,"alpha",0f, 1f, 0f, 1f);
objAnim.setDuration(6000);
objAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float currentValue = (float) animation.getAnimatedValue();
        StringBuilder sb = new StringBuilder();
        et_Animator.setText(sb.append(currentValue).toString());
    }
});
objAnim.start();

以上代码实现的效果是:在6000毫秒内,让EditText控件平滑的实现了从完全透明>完全不透明>完全透明>完全不透明的过渡效果;并且对整个动画执行过程设置了监听,时时把当前动画的AnimatorValue值显示到EditText控件上面。

根据设置参数的不同,使用ObjectAnimator对象还可以实现translationX(竖直平移),translationY(水平平移),rotation(旋转),scaleX(水平缩放),scaleY(竖直缩放)等其他效果。当然还可以使用AnimatorSet对象来产生组合动画效果。

  • 效果图

综合栗子

  • 具体代码
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button btn_OperationAnimator;
    private EditText et_Animator;
    private RadioGroup radioGroup;
    private ObjectAnimator objAnim;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_Animator = (EditText) findViewById(R.id.et_Animator);
        radioGroup = (RadioGroup) findViewById(R.id.radioGroup);
        btn_OperationAnimator = (Button) findViewById(R.id.btn_OperationAnimator);

        btn_OperationAnimator.setOnClickListener(this);

    }
    @Override
    public void onClick(View v) {

        int checkedId = radioGroup.getCheckedRadioButtonId();

        switch (checkedId) {

            case R.id.rb_value:
                ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f);
                valueAnimator.setDuration(3000);
                valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float currentValue = (float) animation.getAnimatedValue();
                        StringBuilder sb = new StringBuilder();
                        et_Animator.setText(sb.append(currentValue).toString());
                    }
                });
                valueAnimator.start();
                break;

            case R.id.rb_alpha:
                objAnim = ObjectAnimator.ofFloat(et_Animator,"alpha",0f, 1f, 0f, 1f);
                objAnim.setDuration(3000);
                objAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float currentValue = (float) animation.getAnimatedValue();
                        StringBuilder sb = new StringBuilder();
                        et_Animator.setText(sb.append(currentValue).toString());
                    }
                });
                objAnim.start();
                break;
            case R.id.rb_translationX:
                objAnim = ObjectAnimator.ofFloat(et_Animator,"translationX",0f, 100f, 0f, 200f, 0f);
                objAnim.setDuration(3000);
                objAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float currentValue = (float) animation.getAnimatedValue();
                        StringBuilder sb = new StringBuilder();
                        et_Animator.setText(sb.append(currentValue).toString());
                    }
                });
                objAnim.start();
                break;
            case R.id.rb_translationY:
                objAnim = ObjectAnimator.ofFloat(et_Animator,"translationY",0f, 100f, 0f, 200f, 0f);
                objAnim.setDuration(3000);
                objAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float currentValue = (float) animation.getAnimatedValue();
                        StringBuilder sb = new StringBuilder();
                        et_Animator.setText(sb.append(currentValue).toString());
                    }
                });
                objAnim.start();
                break;
            case R.id.rb_rotation:
                objAnim = ObjectAnimator.ofFloat(et_Animator,"rotation",0f, 180f, 0f, 360f, 0f);
                objAnim.setDuration(6000);
                objAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float currentValue = (float) animation.getAnimatedValue();
                        StringBuilder sb = new StringBuilder();
                        et_Animator.setText(sb.append(currentValue).toString());
                    }
                });
                objAnim.start();
                break;
            case R.id.rb_scaleX:
                objAnim = ObjectAnimator.ofFloat(et_Animator,"scaleX", 4f, 1f, 2f, 1f);
                objAnim.setDuration(3000);
                objAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float currentValue = (float) animation.getAnimatedValue();
                        StringBuilder sb = new StringBuilder();
                        et_Animator.setText(sb.append(currentValue).toString());
                    }
                });
                objAnim.start();
                break;
            case R.id.rb_scaleY:
                objAnim = ObjectAnimator.ofFloat(et_Animator,"scaleY",1f, 5f, 2f, 1f);
                objAnim.setDuration(3000);
                objAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animation) {
                        float currentValue = (float) animation.getAnimatedValue();
                        StringBuilder sb = new StringBuilder();
                        et_Animator.setText(sb.append(currentValue).toString());
                    }
                });
                objAnim.start();
                break;
            case R.id.rb_animatorSet:
                ObjectAnimator objAnim_alpha = ObjectAnimator.ofFloat(et_Animator,"alpha",0f, 1f, 0f, 1f);
                ObjectAnimator objAnim_translationX = ObjectAnimator.ofFloat(et_Animator,"translationX",0f, 100f, 0f, 200f, 0f);
                ObjectAnimator objAnim_translationY = ObjectAnimator.ofFloat(et_Animator,"translationY",0f, 100f, 0f, 200f, 0f);
                ObjectAnimator objAnim_rotation = ObjectAnimator.ofFloat(et_Animator,"rotation",0f, 180f, 0f, 360f, 0f);
                ObjectAnimator objAnim_scaleX = ObjectAnimator.ofFloat(et_Animator,"scaleX", 4f, 1f, 2f, 1f);
                ObjectAnimator objAnim_scaleY = ObjectAnimator.ofFloat(et_Animator,"scaleY",1f, 5f, 2f, 1f);
                AnimatorSet animSet = new AnimatorSet();
                animSet.play(objAnim_alpha)
                        .before(objAnim_rotation)    //在play动画之后执行
                        .after(objAnim_scaleX)       //在play动画之前执行
                        .after(objAnim_scaleY)
                        .with(objAnim_translationX)  //和play动画同时执行
                        .with(objAnim_translationY);
                animSet.setDuration(5000);
                animSet.start();
                break;
        }
    }
}

栗子很简单,算是做个自我巩固以及方便日后回顾,如果不小心帮到别人了那自然也是极好的。最后附上Demo下载

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android属性动画是一种用于在Android应用程序中创建动画效果的框架。它允许您对任意对象的属性进行动画处理,而不仅仅是视图对象。使用属性动画,您可以平滑地改变对象的属性,如位置、大小、颜色等,从而创建流畅的动画效果。 属性动画基本概念是通过改变对象的属性值来实现动画效果,而不是通过改变视图的位置或绘制来实现。这使得属性动画比传统的补间动画更加灵活和强大。 要使用属性动画,您需要创建一个Animator对象,并指定要动画化的目标对象和属性。然后,您可以定义动画的持续时间、插值器和监听器等属性。最后,启动动画并观察目标对象的属性值的平滑变化。 以下是一个简单的示例,演示如何使用属性动画来平滑地改变视图对象的透明度: ```java // 创建一个属性动画对象,指定要改变的属性为视图对象的透明度 ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha",***.setDuration(1000); // 设置插值器,控制动画的变化速率 animator.setInterpolator(new AccelerateDecelerateInterpolator()); // 启动动画 animator.start(); ``` 在上面的示例中,我们创建了一个ObjectAnimator对象,指定要改变的属性为视图对象的透明度。然后,我们设置了动*** 除了ObjectAnimator,Android还提供了一些其他类型的属性动画,如ValueAnimator和AnimatorSet。这些类可用于更复杂的动画效果,如同时播放多个动画或在动画中修改多个属性。 希望这个简介能帮助您理解Android属性动画基本概念和用法。如果您有更多问题,请随时提问!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值