当前位置:

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

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

Android Studio macOS版
Android Studio macOS版

Android Studio 是 Google 面向安卓应用开发提供的官方集成开发环境,基于 IntelliJ IDEA 构建。它整合智能代码编辑、Gradle 构建、界面预览、设备模拟、性能分析、调试测试及 APK 分析等工具。

立即下载
Mac 2026-10-13
数据库 编程开发 服务器管理 集成开发环境

本节引言: 本节给带来的是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了没,内容还是比较简单 的,而且例子比较有趣,相信大家会喜欢,嗯,就说这么多,谢谢~

    感谢郭神的文章~

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    系统应用 Android
    相关文章 更多
    Ducter 0.0.44:Android新增“用这台手机”,敏感动作逐次确认
    Ducter 0.0.44:Android新增“用这台手机”,敏感动作逐次确认

    Ducter 0.0.44在Android设备卡加入“用这台手机”,提供设置引导和占用提示。每次借用手机均需确认,发送、付款与删除等待用户Go;官方说明银行、钱包、密码和身份验证器应用不在可操作范围,iPhone不支持此路径。

    作业帮APP下载_安卓苹果官方正版链接
    作业帮APP下载_安卓苹果官方正版链接

    作业帮安卓下载可从https://oia.zybang.com/download/进入,苹果官方应用ID为803781859。先核对系统,再检查主APP名称及广州极目未来文化科技有限公司,并查看设备兼容性;家长版、口算和直播课应使用各自安装渠道。

    WPS移动版表格文字怎么自动换行并对齐
    WPS移动版表格文字怎么自动换行并对齐

    WPS移动版表格可从单元格格式进入对齐页,开启自动换行并设置水平、垂直对齐。本文说明选区、行高、列宽和合并单元格的影响,以及保存后如何检查长文字是否完整显示。

    手机WPS怎么把多张图片合并成一个PDF文档
    手机WPS怎么把多张图片合并成一个PDF文档

    手机WPS可通过“图片转PDF”一次选择多张照片,检查页序、方向和版式后,选择保存位置并输出为一个多页PDF。服务页搜索和旧版应用页入口不同,保存前应核对合并方式及当前账号权益,生成后重新打开确认页数和内容完整。

    一文看懂灵活计算器手机端和电脑端的使用区别
    一文看懂灵活计算器手机端和电脑端的使用区别

    想知道灵活计算器在手机和电脑上怎么用最高效?本文详解两端在输入节奏、布局整理及账号同步上的核心区别,助你避免数据丢失,建立顺畅的跨设备记账习惯。

    Android安装包无法打开?灵活计算器APK安装排查指南
    Android安装包无法打开?灵活计算器APK安装排查指南

    遇到灵活计算器APK无法打开或解析错误?本文详解Android侧载安装的排查逻辑,涵盖来源验证、权限配置、空间清理及旧版本冲突处理,帮助用户安全解决安装问题并正确恢复会员权益。

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

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

    Windows
    Windows

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

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。

    即将离开本站
    您即将前往第三方网站,请确认是否继续?