Android 基于物理特性动画 —— 弹簧动画

news2024/12/24 3:53:49

在安卓开发中我们可以通过动画添加视觉提示,向用户通知应用中的动态。当界面状态发生改变时(例如有新内容加载或有新操作可用时),动画尤其有用。动画还为应用增加了优美的外观,使其拥有更高品质的外观和风格。
在这里插入图片描述

首先来简单了解一下动画

Android 动画主要分为两大类:视图动画和属性动画,其中视图动画又包含补间动画和逐帧动画

补间动画

在这里插入图片描述

在这里插入图片描述

逐帧动画

在这里插入图片描述

拆分成帧
在这里插入图片描述

在这里插入图片描述

属性动画

因为上两个动画作用对象局限,仅改变视觉效果且效果单一,为了弥补视图动画的缺陷,于是 Android 在 3.0(API 11)开始提供了一种全新的动画模式:属性动画(Property Animation)

回到正题 —— 运用物理特性让动画更自然

在这里插入图片描述
在这里插入图片描述

对比上面两个图,非基于物理特性的动画是完全静态的,并且具有固定的持续时间。如果目标值发生变化,则需要在目标值更改时取消动画,使用新值作为新起始值重新配置动画,并添加新目标值。在视觉上,此过程会导致动画突然停止,之后会出现不连贯的运动,如上图所示。而使用基于物理特性的动画 API 构建的动画是依靠力来驱动的。目标值的变化会导致力的变化。新力作用于现有速度,从而实现以连续的方式过渡到新目标。此过程使动画看起来更加自然,如下图所示

运用物理特性运动实例有很多下面来学一个经典的 —— 运用弹簧物理学原理为图形运动添加动画

基于物理特性的动画是依靠力来驱动的。弹簧弹力就是这样一种引导相互作用和运动的力。弹簧弹力具有阻尼和刚度这两个属性。在基于弹簧特性的动画中,值和速度是根据施加到每一帧的弹簧弹力计算的。需要应用到三个关键属性(初始速度,弹簧属性-刚度、阻尼比)

控件初始速度

起始速度用于定义在动画开始时动画属性更改的速度。默认起始速度设置为 0 像素/秒。您可以将速度设置为触摸手势的速度,也可以将起始速度设置为固定值。如果您选择提供固定值,我们建议您以“dp/秒”为单位定义该值,然后将其转换为以“像素/秒”为单位。以“dp/秒”为单位定义该值可使速度与密度和外形规格无关。

要设置速度,请调用 setStartVelocity()方法并传递速度(以“像素/秒”为单位)。该方法会返回设置了速度的弹簧弹力对象。

弹簧的刚度

刚度定义了用于衡量弹簧强度的弹簧常量。不在静止位置的坚硬弹簧可对所连接的对象施加更大的力。要为弹簧增加刚度,请执行以下步骤:

1.调用 getSpring()方法来检索要增加刚度的弹簧。 2.调用 setStiffness() 方法并传递要增加到弹簧上的刚度值。该方法会返回设置了刚度的弹簧弹力对象。

刚度必须为正数

系统中提供了以下刚度常量:

STIFFNESS_HIGH
在这里插入图片描述

STIFFNESS_MEDIUM
在这里插入图片描述

STIFFNESS_LOW
在这里插入图片描述

STIFFNESS_VERY_LOW
在这里插入图片描述

弹簧的阻尼比

阻尼比用于描述弹簧振动逐渐衰减的状况。通过使用阻尼比,您可以定义振动从一次弹跳到下一次弹跳所衰减的速度有多快。以下列出了可使弹簧弹力衰减的四种不同方式:

  • 当阻尼比大于 1 时,会出现过阻尼现象。它会使对象快速地返回到静止位置。

  • 当阻尼比等于 1 时,会出现临界阻尼现象。这会使对象在最短时间内返回到静止位置。

  • 当阻尼比小于 1 时,会出现欠阻尼现象。这会使对象多次经过并越过静止位置,然后逐渐到达静止位置。

  • 当阻尼比等于零时,便会出现无阻尼现象。这会使对象永远振动下去。

要为弹簧增加阻尼比,请执行以下步骤: 1.调用 getSpring()方法来检索要增加阻尼比的弹簧。
2.调用 setDampingRatio()方法并传递要增加到弹簧上的阻尼比。该方法会返回设置了阻尼比的弹簧弹力对象。

阻尼比必须为非负数。如果将阻尼比设置为零,弹簧永远不会到达静止位置。换句话说,它会永远振动下去。

系统中提供以下阻尼比常量:

DAMPING_RATIO_HIGH_BOUNCY(高弹跳)
在这里插入图片描述

DAMPING_RATIO_MEDIUM_BOUNCY (中弹跳)
在这里插入图片描述

DAMPING_RATIO_LOW_BOUNCY (低弹跳)
在这里插入图片描述

DAMPING_RATIO_NO_BOUNCY(无弹跳)
在这里插入图片描述

除了上述的三个属性还需要设置监听器来监听运动状态比如用来获取初始速度;设置动画的边界值来规定控件的移动位置;通过调用 start()或 animateToFinalPosition()来启动你的弹簧动画;通过 cancel()方法可在动画当前所在的值处终止弹簧动画或 skipToEnd 方法可使动画跳至最终值,然后终止弹簧动画。

下面用一个实例来展示

添加支持库

打开应用模块的 build.gradle 文件。将支持库添加到 dependencies 部分。

dependencies {
    def dynamicanimation_version = "1.0.0"
    implementation 'androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version'
}

创建布局文件

添加个滑块用于展示运动

<RelativeLayout
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="300dp">

        <View
            android:id="@+id/box"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_centerInParent="true"
            android:layout_margin="20dp"
            android:background="@color/colorAccent" />

    </RelativeLayout>

在这里插入图片描述

设置两个拖动条完成对弹簧两个属性:刚度和阻尼值的改变来观察不同属性下滑块的运动情况

<SeekBar
        android:id="@+id/damping"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:layout_margin="30dp"
        android:progress="30" />

<SeekBar
        android:id="@+id/stiffness"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:layout_margin="30dp"
        android:progress="20" />

在这里插入图片描述

创建 MainActivity

public class MainActivity extends Activity {

    //XY坐标
    private float downX, downY;
    //调整参数的SeekBar
    private SeekBar dampingSeekBar, stiffnessSeekBar;
    //X/Y方向速度相关的帮助类
    private VelocityTracker velocityTracker;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(android.R.id.content).setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE   //不限制滑块的移动面积,可以移出手机面板
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
        stiffnessSeekBar = (SeekBar) findViewById(R.id.stiffness);//通过ID找到刚度拖动条
        dampingSeekBar = (SeekBar) findViewById(R.id.damping);//通过ID找到阻尼拖动条
        velocityTracker = VelocityTracker.obtain();//速度追踪,用于追踪手指滑动过程中的瞬时速度
        final View box = findViewById(R.id.box);//通过ID找到可拖动滑块
        findViewById(R.id.content).setOnTouchListener(new View.OnTouchListener() {//找到滑块所在的控件设置监听器识别滑动手势
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN://当屏幕检测到第一个触点按下之后就会触发到这个事件
                        downX = event.getX();//记录第一次按下的X位置
                        downY = event.getY();//记录第一次按下的Y位置
                        velocityTracker.addMovement(event);
                        return true;
                    case MotionEvent.ACTION_MOVE://当触点在屏幕上移动时触发,触点在屏幕上停留也是会触发的
                        box.setTranslationX(event.getX() - downX);//算出改变的X大小
                        box.setTranslationY(event.getY() - downY);//算出改变的Y大小
                        velocityTracker.addMovement(event);
                        return true;
                    case MotionEvent.ACTION_UP://当触点松开时被触发
                    case MotionEvent.ACTION_CANCEL://不是由用户直接触发,由系统在需要的时候触发
                        velocityTracker.computeCurrentVelocity(1000);//计算出拖动滑块并释放时滑动速度
                        if (box.getTranslationX() != 0) {//X值有变化即滑块有移动
                            SpringAnimation animX = new SpringAnimation(box, SpringAnimation.TRANSLATION_X, 0);//使用SpringAnimation类完成弹簧动画
                            animX.getSpring().setStiffness(getStiffnessSeekBar());//获取拖拉条刚度值
                            animX.getSpring().setDampingRatio(getDampingSeekBar());//获取拖拉条阻尼值
                            animX.setStartVelocity(velocityTracker.getXVelocity());//获取初始速度
                            animX.start();//开始运动
                        }
                        if (box.getTranslationY() != 0) {//Y值有变化即滑块有移动
                            SpringAnimation animY = new SpringAnimation(box, SpringAnimation.TRANSLATION_Y, 0);//使用SpringAnimation类完成弹簧动画
                            animY.getSpring().setStiffness(getStiffnessSeekBar());//获取拖拉条刚度值
                            animY.getSpring().setDampingRatio(getDampingSeekBar());//获取拖拉条阻尼值
                            animY.setStartVelocity(velocityTracker.getYVelocity());//获取初始速度
                            animY.start();//开始运动
                        }
                        velocityTracker.clear();//滑块回到原点速度归零即停止
                        return true;
                }
                return false;
            }
        });
    }


    private float getStiffnessSeekBar() {
        return Math.max(stiffnessSeekBar.getProgress(), 1f);
    }//从SeekBar获取自定义刚度返回刚度

    private float getDampingSeekBar() {
        return dampingSeekBar.getProgress() / 100f;
    }//从SeekBar获取自定义的阻尼返回阻尼值
}

来看运行效果

在这里插入图片描述

可以看出不同的刚度和阻尼下滑块的轨迹不一样,当二者为 0 时会无限震荡下去

作者:刘佳民
原文链接:https://blog.csdn.net/qq_63462634/article/details/127991674?spm=1001.2014.3001.5502

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/59111.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java并发编程—并发和并行、线程上下文

文章目录并发和并行并发和并行的区别上下文切换相关问题为什么循环次数少的情况下&#xff0c;单线程快&#xff1f;什么时候需要用多线程&#xff1f;线程上下文切换消耗的时长&#xff1f;用什么测试的线程上下文&#xff1f;面试回答下面的工具会加分&#xff1a;如何减少上…

DQL简介

学习笔记之DQL 数据查询语言&#xff0c;用来查询数据库中表的记录。 查询关键字&#xff1a;select 基本查询 1查询多个字段 select 字段1&#xff0c;字段2&#xff0c;字段3.. from 表名; select * from 表名;2设置别名 select 字段1 [别名1],字段2[别名2]... from 表名;3…

233搞懂HMM(隐马尔可夫)

文章目录2条性质3个参数3个问题维特比算法参考资料有向图模型&#xff0c;主要用于时序数据建模&#xff0c;在语音识别&#xff0c;自然语言处理等领域&#xff0c;以及在知识图谱命名实体识别中的序列标注&#xff0c;有广泛应用。 HMM模型由两部分组成&#xff0c; 观测变量…

spring boot 应用mybatis

Mybatis入门: Mybatis入门_做测试的喵酱的博客-CSDN博客 目录 一、spring boot 应用mybatis 核心 二、举例&#xff1a; 2.1 背景 2.2 项目结构&#xff1a; 2.3 依赖包 pom 2.4 项目配置文件application.yml 2.5 实例层entity 2.6 mybatis的mapper层 2.7 spring boot…

Android—过渡按钮的简单实现

Android—过渡按钮的简单实现前言准备工作登录页面(activity_main.xml)登录成功页面(activity_new.xml)主要代码给登录按钮设置监听事件(MainActivity.xml)点击登录按钮出现加载动画(TransitionButton.java)当isSuccessful判断为true时(MainActivity.xml)加载动画结束时切入跳转…

C语言笔记-16-Linux基础-文件元数据

C语言笔记-16-Linux基础-文件元数据 文章目录C语言笔记-16-Linux基础-文件元数据前言一、概述二、ln 硬连接三、软连接四、stat 获取元数据总结前言 自学笔记&#xff0c;没有历史知识铺垫&#xff08;省略百度部分&#xff09;C语言笔记-16-Linux基础-文件元数据 一、概述 文…

Kaggle泰坦尼克号-决策树Top 3%-0基础代码详解

Titanic Disaster Kaggle&#xff0c;里的经典入门题目&#xff0c;因为在学决策树所以找了一个实例学习了一下&#xff0c;完全萌新零基础&#xff0c;所以基本每一句都做了注释。 原文链接&#xff1a;Titanic: Simple Decision Tree model score(Top 3%) | Kaggle 目录 1.…

SolidWorks如何绘制环形波纹垫片

环形波纹垫片主要用于螺纹式固定件或者防滑螺纹固定中,那这个环形垫片一般怎么用SolidWorks制作呢?首先我们观察到这样的垫片是上下此起彼伏的波纹状,厚度一般1MM左右,制作起来还是有点小难度,但是通过仔细观察,我们可以看到它的大概走向,如图 也就是特征就是这边凹下去…

获取Android签名MD5的方式

形而上者谓之道&#xff0c;形而下者谓之器 我们在申请百度云/腾讯云等第三方的各种服务时&#xff0c;经常会遇到需要提供包名和签名MD5的情况。这里特地总结一下&#xff1a; 1. 获取MD5的一般方式 1.1 有签名文件(.keystore)的情况下: keytool -list -v -keystore XXX.key…

【沐风老师】3DMAX一键生成圣诞树建模插件使用教程

圣诞节快到了&#xff0c;给大家分享一款3DMax一键生成圣诞树模型插件&#xff1a; 3DMAX一键生成圣诞树建模插件&#xff0c;可以生成定制和随机两种3D圣诞树模型&#xff0c;并自动赋予材质和贴图。 【安装方法】 方法一&#xff1a;解压后直接拖动插件脚本文件到3dMax窗口…

使用springboot实现jsonp|jsonp的实现|JSONP的实现使用springboot

1、服务端&#xff1a; 1.1、项目目录&#xff1a; 1.2、pom文件&#xff1a; <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instan…

从一到无穷大 #3 对象存储.浅谈

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 文章目录引言Windows Azure StorageNosql&#xff1a;TiKV为例总结引言 天才的开源精神对于普…

67-94-hive-函数-开窗函数-常用函数-udf自定义函数

67-hive-函数&#xff1a; UDF:一进一出&#xff0c;普通函数 UDAF:多进一出&#xff0c;聚合函数 UDTF&#xff1a;一进多出&#xff0c;炸裂函数 一、多指的是输入数据的行数。一行变多行&#xff0c;多行变一行。 函数 #查看系统自带的函数 hive> show functions; …

Docker以标准方式安装部署Redis

Docker安装redis的命令很简单&#xff0c;但是很多都是半成品的命令&#xff0c;说白了&#xff0c;就是自己玩玩&#xff0c;一个demo级别的redis而已。 本篇文章以最全的命令方式安装部署Redis。 注意&#xff1a; 本篇只是单机版的&#xff0c;只是公司测试环境使用&…

解决npm的 EACCES: permission denied 问题

居上位而不骄&#xff0c;在下者而不忧。 平时项目开发使用npm都顺风顺水的&#xff0c;but今天新建项目时&#xff0c;就出现了权限错误&#xff0c;具体如下&#xff1a; 但是通过下面的提示就可以轻松解决。 sudo chown -R 502:20 “/Users/cheng.wang/.npm” 官网相关议题…

Redis源码篇(7)——哨兵模式

哨兵模式 哨兵模式即在主从复制的基础上增加哨兵监控以控制主从切换实现高可用的一种模式。 本篇主要介绍sentinel系统初始化&#xff0c;心跳检测&#xff0c;故障转移的过程 初始化 从最开始的 redis-server xxx.conf --sentinel 、 redis-sentinel xxx.conf 命令看起。当一…

CUDA 编程简介

参考资料&#xff1a; NVIDIA CUDA Programming Guide, NVIDIA. (https://docs.nvidia.com/cuda/cuda-c-programming-guide/)国科大《并行与分布式计算》课程、NVIDIA 在线实验平台 文章目录GPU & CUDAG80 Graphics ModeG80 CUDA ModeCUDA Programming ModelCUDA Extends …

重定向转发,接收请求参数及数据回显-P11,12

重定向和转发&#xff1a; 我们的实现本身就是转发 。 想删掉视图解析器的话&#xff0c;就需要在return把路径写全 重定向就改为redirect&#xff1a;而且重定向不走视图解析器&#xff0c;因为是新的请求&#xff0c;新的URL。 接收请求参数&#xff1a; 第一种是默认的方式…

【FreeRTOS(十二)】事件标志组

文章目录事件标志组创建事件标志组 xEventGroupCreate将指定的事件位清零 xEventGroupClearBits将指定的事件位置 1 xEventGroupSetBits获取事件标志组值 xEventGroupGetBits等待指定的事件位 xEventGroupWaitBits代码示例事件标志组 事件标志位 事件位用来表明某个事件是否发…

嵌入式Linux 开发经验:编写用户态应用程序打开 misc 设备

参考文章 VSCode SSH 连接远程ubuntu Linux 主机 ubuntu 20.04 qemu linux6.0.1 开发环境搭建 ubuntu 20.04 qemu linux6.0.1 制作ext4根文件系统 嵌入式Linux 开发经验&#xff1a;platform_driver_register 的使用方法 嵌入式Linux 开发经验&#xff1a;注册一个 misc 设…