Android 属性动画框架 ObjectAnimator、ValueAnimator ,这一篇就够了

前言

我们都知道 Android 自带了 Roate Scale Translate Alpha 多种框架动画,我们可以通过她们实现丰富的动画效果,但是这些宽家动画却有一个致命的弱点,它们只是改变了 View 显示的大小,而没有改变 View 的响应区域。这时以 ObjectAnimator、ValueAnimator 为代表的属性动画也就应运而生了。


简单效果


工作原理

属性动画字如其名,是通过改变 View 的属性值来改变控件的形态,说白了就是通过反射技术来获取控件的一些属性如宽度、高度等的 get 和 set 方法,从而实现所谓的动画效果。所以,这就需要我们的 View (如自定义 View 中)具有 set 和 get 方法,如果没有则会导致程序的 Clash 。
具体步骤

  1. 首先,系统通过 get 方法获得属性值
  2. 系统在时间插值器的作用下,更变属性值
  3. 系统调用 set 方法,将属性值重新赋予控件

由此也可以看出:属性动画直接改变了控件的属性,所以动画结束后控件也就发生了永久性的变化。


使用 ObjectAnimator 实现四种动画

这里我打算通过使用 ObjectAnimator 实现四大动画框架:

  1. alpha
  2. scaleX/scaleY
  3. translateX/translateY
  4. rotation

给大家讲解下 ObjectAnimator 使用

    private void iniAnimation(){
        // 透明度动画
        ObjectAnimator.ofFloat(mAlphaImage, "alpha", 1, 0, 1)
                .setDuration(4000)
                .start();

        // 缩放
        final AnimatorSet animatorSet = new AnimatorSet();
        mScaleImage.setPivotX(mScaleImage.getWidth()+250);
        mScaleImage.setPivotY(mScaleImage.getHeight()+250);
        animatorSet.playTogether(
                ObjectAnimator.ofFloat(mScaleImage, "scaleX", 1, 0)
                        .setDuration(2000),
                ObjectAnimator.ofFloat(mScaleImage, "scaleY", 1, 0)
                        .setDuration(2000)
        );
        animatorSet.start();

        // 平移 translation
        final AnimatorSet translationAnimatorSet = new AnimatorSet();
        translationAnimatorSet.playTogether(
                ObjectAnimator.ofFloat(mTranslationImage, "translationX", 20, 100)
                        .setDuration(2000),
                ObjectAnimator.ofFloat(mTranslationImage, "translationY", 20,100)
                        .setDuration(2000)
        );
        translationAnimatorSet.start();

        // 利用 ObjectAnimator 实现旋转动画
        final AnimatorSet rotateAnimationSet = new AnimatorSet();
        rotateAnimationSet.playTogether(
                ObjectAnimator.ofFloat(mRotationImage, "rotation",0, 360)
                        .setDuration(2000)
        );
        rotateAnimationSet.start();
    }

以上代码就通过了 ObjectAnimator 实现了,四大效果,实现过程基本可以归纳为

  1. 创建 AnimatorSet 对象
  2. 设置,变化发生的轴心(部分需要)
  3. 设置所需要发生改变的动画(通常在 playTogether() 方法中)
  4. 开启动画

最后的运行效果如开头动画所示
同样的,我们可以在一个 playTogether 方法中添加多个动画,这样就能实现多动画组合的效果。这里就不在赘述了,大家可以自己试试看(我 GIF 图中,右下角的动画,就是旋转 + 透明度)


使用 ValueAnimator 实现属性动画

ValueAnimator 是 ObjectAnimator 的父类,他两之间的区别是,ObjectAnimator 在ValueAnimator 的基础上,通过反射技术实现了动画功能,也就像我刚刚所举的例子,子要给了 ObjectAnimator 两个值(from,to),在确定动画类型(“scale,translate”),他就能自动生成动画。
与之形成区别,虽然我们同样需要给 ValueAnimator 传递起始和最终两个值,但是 ValueAnimator 并不会自动去执行什么,而是会通过 addUpdateListener 的监听方法,在时间插值器的作用下,有序的返回一连串数值,然后我们就可以通过这些数值,对控件进行设置。

实例

最近看各大厂商,似乎都迷上了对 FloatingActionButton 进行操作,我就也来趁波热点。


实现方法

这个效果既可以通过动画框架实现,也可通过属性动画实现,这里我给大家讲下实现的方法。
首先是思路
由于这里我们是采用 ValueAnimator 实现的,所以更具 ValueAnimator 的特性,在我们对其设定完时间插值器之后,它会规律的返回一系列数。所以我们只要更具这一系列数对控件的属性进行设置即可。

    private FloatingActionButton fab;
    private ImageView imageView;
    private int buttonSize = 0, imageSize = 0;
    private float startY = 0;
    private float endY   = 0;

    private ValueAnimator createValueAnimate(final View view, int start, int end){
        ValueAnimator valueAnimator = ValueAnimator.ofInt(start, end);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                ViewGroup.LayoutParams params = view.getLayoutParams();
                params.height = (int) animation.getAnimatedValue();
                params.width  = (int) animation.getAnimatedValue();
                view.setLayoutParams(params);
            }
        });
        return valueAnimator;
    }

可以看到我们传入三个参数,这里我做的是缩放动画,所以给的分别是控件,控件当前大小和控件目标大小。然后根据监听器返回的值进行设置即可。
调用方面
我这里实现的是上拉隐藏和下拉显示,所以我们需要判断下 Y轴 滑动方向:

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_UP:
                startY = event.getY();
                if ((startY - endY) < 0){
                    // 缩小
                    animationDown(fab, buttonSize);
                    animationDown(imageView, imageSize);
                }else if ((startY - endY) > 0){
                    // 放大
                    animationUp(fab, buttonSize);
                    animationUp(imageView, imageSize);
                }
                break;

            case MotionEvent.ACTION_DOWN:
                endY   = event.getY();
                break;
        }
        return super.onTouchEvent(event);
    }

    private void animationDown(final View view, int originalSize){
        ValueAnimator animator = createValueAnimate(view, originalSize, 0);
        animator.addListener(new AnimatorListenerAdapter(){
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                view.setVisibility(View.GONE);
            }
        });
        animator.setInterpolator(new BounceInterpolator());
        animator.setDuration(500).start();
    }

    private void animationUp(final View view, int originalSize){
        view.setVisibility(View.VISIBLE);
        ValueAnimator animator = createValueAnimate(view, 0, originalSize);
        animator.setInterpolator(new BounceInterpolator());
        animator.setDuration(500).start();
    }

这里我们会发现,由于是属性动画,所以改变的直接就是控件的大小,这就导致了一个问题,如果是实时的获取控件大小。那么我们在执行完多小动画,也就是 animationDown 后,就无法在获得控件原始大小了。
所以这里我们在 onResume 方法中获取控件大小:

    @Override
    protected void onResume() {
        super.onResume();
        fab.post(new Runnable() {
            @Override
            public void run() {
                buttonSize = fab.getHeight();
            }
        });
        imageView.post(new Runnable() {
            @Override
            public void run() {
                imageSize = imageView.getHeight();
            }
        });
    }

实战演练

属性动画可以作为 ViewGroup 增加活减少控件是的动画,是的界面的变换不是那么的突兀,其实细心的同学可能有发现,android 是自带切换效果的,但是形式比较单一,所以这里我通过自定义 ObjectAnimator 的方法。

最后效果


实现过程其实非常简单:

  1. 首先 实例化出来一个 LayoutTransition 对象
  2. 接着 通过 ObjectAnimator.ofPropertyValuesHolder() 实例化出来一个用于载入动画的
  3. ObjectAnimator 对象
  4. 然后 在 ObjectAnimator.ofPropertyValuesHolder() 中设置一系列的动画效果
  5. 用 setAnimation 方法将该 ObjectAnimator 对象设置为 transition 的动画
  6. 为 ObjectAnimator 对象设置 Duration 执行时间
  7. 设置动画延时 setStartDelay

用同样的方法设置 remove 动画

        LayoutTransition transition = new LayoutTransition();

        ObjectAnimator appendAnimator = ObjectAnimator.ofPropertyValuesHolder(
                (ImageView) null,
                PropertyValuesHolder.ofFloat("scaleX", 0.0f, 1.0f),
                PropertyValuesHolder.ofFloat("scaleY", 0.0f, 1.0f),
                PropertyValuesHolder.ofFloat("alpha" , 0.0f, 1.0f)
        );
        appendAnimator.setInterpolator(new BounceInterpolator());
        transition.setAnimator(LayoutTransition.APPEARING, appendAnimator);
        transition.setDuration(LayoutTransition.APPEARING, transition.getDuration(LayoutTransition.APPEARING));
        transition.setStartDelay(LayoutTransition.APPEARING, transition.getStartDelay(LayoutTransition.APPEARING));

        ObjectAnimator removeAnimator = ObjectAnimator.ofPropertyValuesHolder(
                (ImageView) null,
                PropertyValuesHolder.ofFloat("scaleX", 1.0f, 0.0f),
                PropertyValuesHolder.ofFloat("scaleY", 1.0f, 0.0f),
                PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.0f)
        );
        removeAnimator.setInterpolator(new BounceInterpolator());
        transition.setAnimator(LayoutTransition.DISAPPEARING, removeAnimator);
        transition.setDuration(LayoutTransition.DISAPPEARING, transition.getDuration(LayoutTransition.DISAPPEARING));
        transition.setStartDelay(LayoutTransition.DISAPPEARING, transition.getStartDelay(LayoutTransition.DISAPPEARING));

最后通过 setLayoutTransition 将这个 LayoutTransition 对象付给你的 ViewGroup 即可

        layout = findViewById(R.id.layout);
        layout.setLayoutTransition(transition);

测试环节

测试是分为添加控件和移除控件,功能在活动中动态的执行:
添加方法

  1. 首先创建好一个控件,这里我拿的是 (ImageView 举例)
  2. 将其 大小、内容等属性设置完成
  3. 调用 LinearLayout 的 addView 方法添加控件到布局的指定位置

移除方法

  1. 首先判断该线下布局中是否有控件
  2. 再有的情况下定点移除控件
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_add_image:
                ImageView imageView = new ImageView(ExtendActivity.this);
                imageView.setScaleType(ImageView.ScaleType.FIT_XY);
                imageView.setImageResource(R.drawable.heart);
                ViewGroup.LayoutParams params = new LinearLayout.LayoutParams(200, 200);
                imageView.setLayoutParams(params);
                layout.addView(imageView,0);
                break;

            case R.id.btn_remove_image:
                int count = layout.getChildCount();
                if (count > 0){
                    layout.removeViewAt(0);
                }
                break;
        }
    }


项目 Demo 点击前往https://github.com/FishInWater-1999/android_view_user_defined_first
到此为止所有属性动画的使用基本介绍完毕
由于是个人学习的总结,如果有问题或是我个人疏漏,希望大家在评论区给我留言
祝大家编程愉快,少码 bug ,哈哈哈

原文地址:https://www.cnblogs.com/yuanhao-1999/p/11049875.html

时间: 2024-11-10 06:29:58

Android 属性动画框架 ObjectAnimator、ValueAnimator ,这一篇就够了的相关文章

【转】android 属性动画之 ObjectAnimator

原文网址:http://blog.csdn.net/feiduclear_up/article/details/39255083 前面一篇博客讲解了 android 简单动画之 animtion,这里来讲解一下android 3.0之后添加的一些动画   animator 中的 ObjectAnimator . 属性动画概念: 所谓属性动画:改变一切能改变的对象的属性值,不同于补间动画:只能改变 alpha,scale,rotate,translate.听着有点抽象,举例子说明 补间动画能实现的

Android属性动画之ObjectAnimator

相信对于Android初学者,对于Android中的动画效果一定很感兴趣,今天为大家总结一下刚刚学到的属性动画案例. 首先和一般的Android应用一样,我们先建一个工程,为了方便,我们的布局文件中就只添加一个ImageView和button按钮,代码如下: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.andr

android 属性动画之 ObjectAnimator

前面一篇博客讲解了 android 简单动画之 animtion,这里来讲解一下android 3.0之后添加的一些动画   animator 中的 ObjectAnimator . 1.alpha //第一个参数为 view对象,第二个参数为 动画改变的类型,第三,第四个参数依次是开始透明度和结束透明度. ObjectAnimator alpha = ObjectAnimator.ofFloat(text, "alpha", 0f, 1f); alpha.setDuration(20

Android属性动画之ObjectAnimator控制

Android为我们提供了大量的动画效果,如何通过这些动画来达到我们需要的效果呢?今天就为大家总结一下ObjectAnimator动画控制事件. 该项目的的布局文件只有两个控件:ImageView和Button,在这里就不在赘述了,下面我们来看一下activity的实现: public class TwoActivity extends Activity{ private Button button;private ImageView imageView; @Override protected

Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/43536355 大家好,在上一篇文章当中,我们学习了Android属性动画的基本用法,当然也是最常用的一些用法,这些用法足以覆盖我们平时大多情况下的动画需求了.但是,正如上篇文章当中所说到的,属性动画对补间动画进行了很大幅度的改进,之前补间动画可以做到的属性动画也能做到,补间动画做不到的现在属性动画也可以做到了.因此,今天我们就来学习一下属性动画的高级用法,看看如何实现一些补间动画

Android属性动画之ValueAnimator的介绍

之前两篇博客,介绍的是ObjectAnimator作用与某一个控件的某一个属性.但我们的ValueAnimator它本身并不会作用与任何一个属性,它本身也不会提供任何一种动画.它简单的来说,就是一个数值发生器,它可以产生你想要的各种数值.其实,在Android属性动画中,如何产生每一步具体实现动画效果,都是通过ValueAnimator计算出来的. 比如我们现在要实现一个从0~100的位移动画,ValueAnimator会根据动画持续的总时间产生一个0~1时间因子,有了这样一个时间因子.通过相应

Android属性动画ValueAnimator源码简单分析

Android开发的过程中经常要用到属性动画,经常都是网上扒下来看下怎么用,但是经常不知道为什么要这么用,手一哆嗦一不小心就点到源码里面去了.我们就来看看Android属性动画ValueAnimator类源码的简单实现,从而对ValueAnimator类有个大概的了解. 在Android开发过程中做动画效果的时候用到ValueAnimator的时候最简单的方法我们是这么干的 // ValueAnimator ValueAnimator valueAnimator = ValueAnimator.

Android属性动画Property Animation系列一之ObjectAnimator

转载请注明出处 http://blog.csdn.net/feiduclear_up/article/details/45915377 前面一篇博客解读了Android属性动画Property Animation系列一之ValueAnimator的相关知识点以及怎么使用.这篇博客继续解读Android 属性动画 ObjectAnimator 类的使用. ObjectAnimator 相比ValueAnimator类,ObjectAnimator更加实用,因为它真正可以作用在一个对象上.不过Obj

Android 属性动画 源码解析 深入了解其内部实现

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/42056859,本文出自:[张鸿洋的博客] 1.概述 Android中想做很炫酷的动画效果,相信在很多时候你都可以选择使用属性动画,关于属性动画如何使用,我们已经很详细的写过两篇博客讲解.如果你还不了解,请参考: Android 属性动画(Property Animation) 完全解析 (上) Android 属性动画(Property Animation) 完全解析 (下)