当前位置:

首页 > 系统应用 > 8.4.3 Android动画合集之属性动画-初见

8.4.3 Android动画合集之属性动画-初见

本文目录

    本节引言: 本节给带来的是Android动画中的第三种动画——属性动画(Property Animation), 记得在上一节8.4.2 Android动画合集之补间动画为Fragment 设置过渡动画的时候,说过,App包和V4包下的Fragment调用setCustomAnimations()对

    本节引言:

    本节给带来的是Android动画中的第三种动画——属性动画(Property Animation), 记得在上一节8.4.2 Android动画合集之补间动画为Fragment 设置过渡动画的时候,说过,App包和V4包下的Fragment调用setCustomAnimations()对应的 动画类型是不一样的,v4包下的是Animation,而app包下的是Animator;

    Animation一般动画就是我们前面学的帧动画和补间动画!Animator则是本节要讲的属性动画!

    关于属性动画,大牛郭大叔已经写了三篇非常好的总结文,写得非常赞,就没必要重复造轮子了, 不过这里还是过一遍,大部分内容参考的下面三篇文章:

    Android属性动画完全解析(上),初识属性动画的基本用法

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

    Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法

    写的非常好,或者说你可以直接跳过本文去看上面的三篇文章~

    当然,你愿意看我叨叨逼的话,也很欢迎,好了,开始本节内容吧~

    1.属性动画概念叨叨逼

    不BB,直接上图,就是这么暴力~

    2.ValueAnimator简单使用

    使用流程:

    • 1.调用ValueAnimator的ofInt(),ofFloat()或ofObject()静态方法创建ValueAnimator实例
    • 2.调用实例的setXxx方法设置动画持续时间,插值方式,重复次数等
    • 3.调用实例的addUpdateListener添加AnimatorUpdateListener监听器,在该监听器中 可以获得ValueAnimator计算出来的值,你可以值应用到指定对象上~
    • 4.调用实例的start()方法开启动画! 另外我们可以看到ofInt和ofFloat都有个这样的参数:float/int... values代表可以多个值!

    使用示例:

    代码实现:

    布局文件:activity_main.xml,非常简单,四个按钮,一个ImageView

    
    

    接着到MainActivity.ja va, 首先需要一个修改View位置的方法,这里调用moveView()设置左边和上边的起始坐标以及宽高!

    接着定义了四个动画,分别是:直线移动,缩放,旋转加透明,以及圆形旋转!

    然后通过按钮触发对应的动画~

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button btn_one;
        private Button btn_two;
        private Button btn_three;
        private Button btn_four;
        private LinearLayout ly_root;
        private ImageView img_babi;
        private int width;
        private int height;
    @Override
        public void onCreate(Bundle sa vedInstanceState) {
            super.onCreate(sa vedInstanceState);
            setContentView(R.layout.activity_main);
            bindViews();
        }
    private void bindViews() {
            ly_root = (LinearLayout) findViewById(R.id.ly_root);
            btn_one = (Button) findViewById(R.id.btn_one);
            btn_two = (Button) findViewById(R.id.btn_two);
            btn_three = (Button) findViewById(R.id.btn_three);
            btn_four = (Button) findViewById(R.id.btn_four);
            img_babi = (ImageView) findViewById(R.id.img_babi);
    btn_one.setOnClickListener(this);
            btn_two.setOnClickListener(this);
            btn_three.setOnClickListener(this);
            btn_four.setOnClickListener(this);
            img_babi.setOnClickListener(this);
        }
    @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn_one:
                    lineAnimator();
                    break;
                case R.id.btn_two:
                    scaleAnimator();
                    break;
                case R.id.btn_three:
                    raAnimator();
                    break;
                case R.id.btn_four:
                    circleAnimator();
                    break;
                case R.id.img_babi:
                    Toast.makeText(MainActivity.this, "不愧是coder-pig~", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    //定义一个修改ImageView位置的方法
        private void moveView(View view, int rawX, int rawY) {
            int left = rawX - img_babi.getWidth() / 2;
            int top = rawY - img_babi.getHeight();
            int width = left + view.getWidth();
            int height = top + view.getHeight();
            view.layout(left, top, width, height);
        }
    //定义属性动画的方法:
    //按轨迹方程来运动
        private void lineAnimator() {
            width = ly_root.getWidth();
            height = ly_root.getHeight();
            ValueAnimator xValue = ValueAnimator.ofInt(height,0,height / 4,height / 2,height / 4 * 3 ,height);
            xValue.setDuration(3000L);
            xValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    // 轨迹方程 x = width / 2
                    int y = (Integer) animation.getAnimatedValue();
                    int x = width / 2;
                    moveView(img_babi, x, y);
                }
            });
            xValue.setInterpolator(new LinearInterpolator());
            xValue.start();
        }
    //缩放效果
        private void scaleAnimator(){
    //这里故意用两个是想让大家体会下组合动画怎么用而已~
            final float scale = 0.5f;
            AnimatorSet scaleSet = new AnimatorSet();
            ValueAnimator valueAnimatorSmall = ValueAnimator.ofFloat(1.0f, scale);
            valueAnimatorSmall.setDuration(500);
    ValueAnimator valueAnimatorLarge = ValueAnimator.ofFloat(scale, 1.0f);
            valueAnimatorLarge.setDuration(500);
    valueAnimatorSmall.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float scale = (Float) animation.getAnimatedValue();
                    img_babi.setScaleX(scale);
                    img_babi.setScaleY(scale);
                }
            });
            valueAnimatorLarge.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float scale = (Float) animation.getAnimatedValue();
                    img_babi.setScaleX(scale);
                    img_babi.setScaleY(scale);
                }
            });
    scaleSet.play(valueAnimatorLarge).after(valueAnimatorSmall);
            scaleSet.start();
    //其实可以一个就搞定的
    //        ValueAnimator vValue = ValueAnimator.ofFloat(1.0f, 0.6f, 1.2f, 1.0f, 0.6f, 1.2f, 1.0f);
    //        vValue.setDuration(1000L);
    //        vValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    //            @Override
    //            public void onAnimationUpdate(ValueAnimator animation) {
    //                float scale = (Float) animation.getAnimatedValue();
    //                img_babi.setScaleX(scale);
    //                img_babi.setScaleY(scale);
    //            }
    //        });
    //        vValue.setInterpolator(new LinearInterpolator());
    //        vValue.start();
        }
    //旋转的同时透明度变化
        private void raAnimator(){
            ValueAnimator rValue = ValueAnimator.ofInt(0, 360);
            rValue.setDuration(1000L);
            rValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int rotateValue = (Integer) animation.getAnimatedValue();
                    img_babi.setRotation(rotateValue);
                    float fractionValue = animation.getAnimatedFraction();
                    img_babi.setAlpha(fractionValue);
                }
            });
            rValue.setInterpolator(new DecelerateInterpolator());
            rValue.start();
        }
    //圆形旋转
        protected void circleAnimator() {
            width = ly_root.getWidth();
            height = ly_root.getHeight();
            final int R = width / 4;
            ValueAnimator tValue = ValueAnimator.ofFloat(0,
                    (float) (2.0f * Math.PI));
            tValue.setDuration(1000);
            tValue.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    // 圆的参数方程 x = R * sin(t) y = R * cos(t)
                    float t = (Float) animation.getAnimatedValue();
                    int x = (int) (R * Math.sin(t) + width / 2);
                    int y = (int) (R * Math.cos(t) + height / 2);
                    moveView(img_babi, x, y);
                }
            });
            tValue.setInterpolator(new DecelerateInterpolator());
            tValue.start();
        }
    }

    好的,使用的流程非常简单,先创建ValueAnimator对象,调用ValueAnimator.ofInt/ofFloat 获得,然后设置动画持续时间,addUpdateListener添加AnimatorUpdateListener事件监听, 然后使用参数animation的getAnimatedValue()获得当前的值,然后我们可以拿着这个值 来修改View的一些属性,从而形成所谓的动画效果,接着设置setInterpolator动画渲染模式, 最后调用start()开始动画的播放~

    卧槽,直线方程,圆的参数方程,我都开始方了,这不是高数的东西么, 挂科学渣连三角函数都忘了...

    例子参考自github:MoveViewValueAnimator

    3.ObjectAnimator简单使用

    和ValueAnimator相比,ObjectAnimator用起来明显更顺手。它最大的特点就在于,可以直接 对任意对象的任意属性进行动画操作。注意,这里说的是任意对象,并不局限于View。它的思路其实很好理解:持续给对象的某个属性赋新值,再根据这个属性值的变化决定最终该怎么呈现出来。比如,给TextView加上这样一段动画: ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f);
    这段代码做的事情,就是不断修改alpha的值,让它从1f过渡到0f;而对象会随着属性值的变化刷新界面,于是就形成了淡入淡出的效果。这里有个很容易让人误解的点:TextView类里其实并没有alpha这个属性。ObjectAnimator的内部机制并不是去直接找成员变量,而是寻找传输的属性名对应的get和set方法~,而非找这个属性值! 要是不信,完全可以去翻一翻TextView的源码,看看里面到底有没有alpha这个属性。 接下来,就用ObjectAnimator把四种补间动画的效果一步步实现出来。

    运行效果图:

    代码实现:

    布局直接用的上面那个布局,加了个按钮,把ImageView换成了TextView,这里就不贴代码了, 直接上MainActivity.ja va部分的代码,其实都是大同小异的~

    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        private Button btn_one;
        private Button btn_two;
        private Button btn_three;
        private Button btn_four;
        private Button btn_five;
        private LinearLayout ly_root;
        private TextView tv_pig;
        private int height;
        private ObjectAnimator animator1;
        private ObjectAnimator animator2;
        private ObjectAnimator animator3;
        private ObjectAnimator animator4;
        private AnimatorSet animSet;
    @Override
        protected void onCreate(Bundle sa vedInstanceState) {
            super.onCreate(sa vedInstanceState);
            setContentView(R.layout.activity_main);
            bindViews();
            initAnimator();
        }
    private void bindViews() {
            ly_root = (LinearLayout) findViewById(R.id.ly_root);
            btn_one = (Button) findViewById(R.id.btn_one);
            btn_two = (Button) findViewById(R.id.btn_two);
            btn_three = (Button) findViewById(R.id.btn_three);
            btn_four = (Button) findViewById(R.id.btn_four);
            btn_five = (Button) findViewById(R.id.btn_five);
            tv_pig = (TextView) findViewById(R.id.tv_pig);
    height = ly_root.getHeight();
            btn_one.setOnClickListener(this);
            btn_two.setOnClickListener(this);
            btn_three.setOnClickListener(this);
            btn_four.setOnClickListener(this);
            btn_five.setOnClickListener(this);
            tv_pig.setOnClickListener(this);
        }
    //初始化动画
        private void initAnimator() {
            animator1 = ObjectAnimator.ofFloat(tv_pig, "alpha", 1f, 0f, 1f, 0f, 1f);
            animator2 = ObjectAnimator.ofFloat(tv_pig, "rotation", 0f, 360f, 0f);
            animator3 = ObjectAnimator.ofFloat(tv_pig, "scaleX", 2f, 4f, 1f, 0.5f, 1f);
            animator4 = ObjectAnimator.ofFloat(tv_pig, "translationY", height / 8, -100, height / 2);
        }
    @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn_one:
                    animator1.setDuration(3000l);
                    animator1.start();
                    break;
                case R.id.btn_two:
                    animator2.setDuration(3000l);
                    animator2.start();
                    break;
                case R.id.btn_three:
                    animator3.setDuration(3000l);
                    animator3.start();
                    break;
                case R.id.btn_four:
                    animator4.setDuration(3000l);
                    animator4.start();
                    break;
                case R.id.btn_five:
                    //将前面的动画集合到一起~
                    animSet = new AnimatorSet();
                    animSet.play(animator4).with(animator3).with(animator2).after(animator1);
                    animSet.setDuration(5000l);
                    animSet.start();
                    break;
                case R.id.tv_pig:
                    Toast.makeText(MainActivity.this, "不愧是coder-pig~", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    }

    用法也非常简单,上面涉及到的组合动画我们下面讲~

    4.组合动画与AnimatorListener

    从上面两个例子中我们都体验了一把组合动画,用到了AnimatorSet这个类!

    我们调用的play()方法,然后传入第一个开始执行的动画,此时他会返回一个Builder类给我们:

    接下来我们可以调用Builder给我们提供的四个方法,来组合其他的动画:

    • after(Animator anim) 将现有动画插入到传入的动画之后执行
    • after(long delay) 将现有动画延迟指定毫秒后执行
    • before(Animator anim) 将现有动画插入到传入的动画之前执行
    • with(Animator anim) 将现有动画和传入的动画同时执行

    嗯,很简单,接下来要说下动画事件的监听,上面我们ValueAnimator的监听器是 AnimatorUpdateListener,当值状态发生改变时候会回调onAnimationUpdate方法!

    除了这种事件外还有:动画进行状态的监听~ AnimatorListener,我们可以调用addListener方法 添加监听器,然后重写下面四个回调方法:

    • onAnimationStart():动画开始
    • onAnimationRepeat():动画重复执行
    • onAnimationEnd():动画结束
    • onAnimationCancel():动画取消

    确实如此,如果这里打算直接用AnimatorListener,那它的四个方法都得老老实实重写一遍。不过,和前面手势那一节的处理方式一样,Android其实早就准备好了一个适配器类:AnimatorListenerAdapter。这个类已经把接口里的各个方法都提前实现过了,所以这里只挑需要的那一个回调方法来写就行,省事不少。

    5.使用XML来编写动画

    使用XML来编写动画,画的时间可能比Ja va代码长一点,但是重用起来就轻松很多! 对应的XML标签分别为:<animator><objectAnimator><set> 相关的属性解释如下:

    • android:ordering:指定动画的播放顺序:sequentially(顺序执行),together(同时执行)
    • android:duration:动画的持续时间
    • android:propertyName="x":这里的x,还记得上面的"alpha"吗?加载动画的那个对象里需要 定义getx和setx的方法,objectAnimator就是通过这里来修改对象里的值的!
    • android:valueFrom="1" :动画起始的初始值
    • android:valueTo="0" :动画结束的最终值
    • android:valueType="floatType":变化值的数据类型

    使用例子如下:

    ①从0到100平滑过渡的动画:

    ②将一个视图的alpha属性从1变成0:

    ③set动画使用演示:

    
        
            
            
        
        
    

    加载我们的动画文件:

    AnimatorSet set = (AnimatorSet)AnimatorInflater.loadAnimator(mContext, 
                 R.animator.property_animator);  
    animator.setTarget(view);  
    animator.start();  

    6.本节示例代码下载:

    AnimatorDemo1.zip

    AnimatorDemo2.zip

    本节小结:

    好的,本节给大家捋了一捋安卓中属性动画的基本用法,不知道你get了没,内容还是比较简单 的,而且例子比较有趣,相信大家会喜欢,嗯,就说这么多,谢谢~

    感谢郭神的文章~

    本文内容来源于网友投稿,如有侵权请联系删除。
    作者最新文章
    系统应用 Android
    相关文章 更多
    docker容器自动重启怎么解决 排查原因与修复方法
    docker容器自动重启怎么解决 排查原因与修复方法

    遇到Docker容器频繁自动重启?本文提供从查看容器日志、解读退出代码到配置Restart Policy的完整排查与修复方案,确保服务稳定性。

    Linux设置静态路由命令与永久生效教程
    Linux设置静态路由命令与永久生效教程

    学习如何在Linux中使用命令行添加临时静态路由,并通过修改网络配置文件实现重启后依然有效的永久静态路由设置,涵盖CentOS和Ubuntu的不同配置方法。

    摄像头连接电脑后怎么打开查看实时画面教程
    摄像头连接电脑后怎么打开查看实时画面教程

    摄像头连接电脑后不知如何查看画面?本教程演示如何使用Windows自带的“相机”应用快速调取实时视频流,无需下载额外软件,步骤简单直观,适用于大多数USB及内置摄像头。

    如何在 windows 11 关闭自动关机
    如何在 windows 11 关闭自动关机

    针对 Windows 11 电脑在无人操作时自动关机或重启的问题,本文详解如何通过任务计划程序禁用更新重启任务,并调整电源睡眠策略,从根源解决非预期的自动关机现象。

    android页面跳转屏幕方向改变变量如何解决
    android页面跳转屏幕方向改变变量如何解决

    详解Android应用中处理屏幕旋转导致Activity重建时的变量保存方法,包括使用onSaveInstanceState捆绑包和Jetpack ViewModel架构组件的最佳实践。

    电脑摄像头怎么测试人脸识别功能及效果判断方法
    电脑摄像头怎么测试人脸识别功能及效果判断方法

    详细讲解在Windows电脑上测试摄像头人脸识别功能的步骤,包括开启Windows Hello、录入面部数据、不同环境下的效果验证及常见问题排查,帮助用户确认设备兼容性与识别准确率。

    docker 容器无法启动的配置检查命令及排查方法
    docker 容器无法启动的配置检查命令及排查方法

    当 Docker 容器启动后立即退出时,不要盲目重启。本文详解如何通过 docker logs 查看标准输出错误,利用 docker inspect 检查挂载与网络配置,并修正入口点脚本权限问题,提供一套高效的因果排查流程。

    安卓手机投屏到电脑win10怎么设置教程
    安卓手机投屏到电脑win10怎么设置教程

    详解如何利用Windows 10自带功能将安卓手机画面投射至电脑屏幕,涵盖开启步骤、连接技巧及延迟分析,适合临时演示与多屏协作场景。

    移动硬盘解除加密怎么操作?详细步骤教程
    移动硬盘解除加密怎么操作?详细步骤教程

    详细介绍如何在Windows系统中为移动硬盘解除BitLocker加密,包括解锁驱动器、关闭加密功能及监控解密进度的完整操作流程,帮助用户安全移除数据保护。

    android下载文件夹在哪里打开及查找方法
    android下载文件夹在哪里打开及查找方法

    想知道Android手机的下载文件夹在哪里?本文提供多种简单方法,教你如何通过系统文件管理器、第三方应用或电脑连接,快速定位并打开Download文件夹,轻松管理下载的文件。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    macOS软件
    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    Mac软件 更多
    photoshop
    photoshop
    Windows、macOS 、 iPad

    Photoshop 2026 是 Adobe 推出的专业图像处理与视觉设计软件,支持 Windows、macOS 和 iPad 等平台,广泛应用于摄影修图、电商设计、平面海报、数字绘画及视觉合成等创作场景。

    Blender
    Blender
    Windows、macOS 和 Linux

    Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。

    灵活计算器
    灵活计算器
    macOS/iOS/Android

    灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

    WINDOWS 更多
    3dmax(3ds max)
    3dmax(3ds max)
    Windows

    Autodesk 3ds Max 是一款专业的三维建模、动画与渲染软件,广泛应用于建筑可视化、游戏开发、影视动画、广告设计和产品展示等领域。

    photoshop
    photoshop
    Windows、macOS 、 iPad

    Photoshop 2026 是 Adobe 推出的专业图像处理与视觉设计软件,支持 Windows、macOS 和 iPad 等平台,广泛应用于摄影修图、电商设计、平面海报、数字绘画及视觉合成等创作场景。

    Blender
    Blender
    Windows、macOS 和 Linux

    Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。