[MAUI 项目实战] 手势控制音乐播放器(三): 动画

news/2024/2/29 4:29:51

文章目录

    • 吸附动画
      • 确定位置
      • 平移动画
    • 回弹动画
      • 使用自定义缓动函数
      • 多重动画
    • 点击动画
    • 项目地址

上一章节我们创建了手势容器控件PanContainer,它对拖拽物进行包装并响应了平移手势和点击手势。

拖拽物现在虽然可以响应手势操作,但视觉效果较生硬,一个优秀的设计要求UI界面交互流畅,页面元素显得灵动,则少不了动画(Animation)。

本章节我们对拖拽物加入过渡动画

吸附动画

还记的上一章节所描述的拖拽物(pan)和坑(pit)吗?“”吸附“”这是一个非常拟物的过程,当拖拽物品接近坑区域的边缘时,物体就会由于重力或是引力作用会滑落,吸附在坑里。

接下来对势容器控件PanContainer添加这一效果,打开PanContainer.xaml.cs,创建一个bool类型的可绑定对象AutoAdsorption,用于控制是否开启吸附动画。

添加如下代码:


public static readonly BindableProperty AutoAdsorptionProperty =
BindableProperty.Create("AutoAdsorption", typeof(bool), typeof(PanContainer), default(bool));public bool AutoAdsorption
{get { return (bool)GetValue(AutoAdsorptionProperty); }set{SetValue(AutoAdsorptionProperty, value);OnPropertyChanged();}
}

确定位置

吸附动画触发时,首先要确定拖拽物的中心点是否在坑区域内,如果在,则拖拽物的中心点移动到坑区域的中心点,否则拖拽物的中心点移动到手指的位置。

在平移手势的PanUpdated响应事件处理方法中,添加如下代码:

private async void PanGestureRecognizer_OnPanUpdated(object sender, PanUpdatedEventArgs e)
{var isInPit = false;var isAdsorbInPit = false;...//GestureStatus.Running中if (isYin && isXin){isInPit = true;if (AutoAdsorption){isAdsorbInPit = true;translationX = (pitRegion.EndX + pitRegion.StartX - Content.Width) / 2;translationY = (pitRegion.EndY + pitRegion.StartY - Content.Height) / 2;}...

isAdsorbInPit是是否执行吸附动画的标志位。

平移动画

在触发吸附动画后,我们需要对拖拽物进行平移动画,使其移动到坑区域的中心点。

使用的用TranslateTo方法执行的,该方法会在200ms内逐渐更改拖拽物的TranslationX和 TranslationY属性

if (AutoAdsorption)
{if (isAdsorbInPit){if (!IsRuningTranslateToTask){IsRuningTranslateToTask = true;await Content.TranslateTo(translationX, translationY, 200, Easing.CubicOut).ContinueWith(c => IsRuningTranslateToTask = false); ;}isAdsorbInPit = false;}else{Content.TranslationX = translationX;Content.TranslationY = translationY;}
}
else
{Content.TranslationX = translationX;Content.TranslationY = translationY;
}

执行效果如下:

在这里插入图片描述

IsRuningTranslateToTask是是否正在执行吸附动画的标志位。若正在执行,则不再执行新的吸附动画。

回弹动画

当手指释放拖拽物时,我们需要对拖拽物进行回弹动画,使其回到原来的位置。

同样的,我们通过动画改变TranslationX和 TranslationY属性,但是为了有一个回弹的效果,要用到缓动函数Easing类。

Easing 类,使用该类可以指定一个传输函数,用于控制动画在运行时如何加快或减慢速度。

MAUI中提供了以下几种缓动函数:

缓动函数描述
BounceIn在开始时弹跳动画
BounceOut在结尾处弹跳动画
CubicIn缓慢加速动画
CubicInOut在开头加速动画,并在结束时减速动画
CubicOut会快速减速动画
Linear使用恒定的速度,是默认值
SinIn可平滑地加速动画
SinInOut在开头平滑地加速动画,并在动画结束时平滑减速
SinOut平滑地减速动画
SpringIn会导致动画快速加速到末尾
SpringOut会导致动画快速减速到末尾

它们的函数曲线如下:

在这里插入图片描述

使用自定义缓动函数

我们需要一个拉扯回弹的效果,可以通过自定义缓动函数实现。

我用python拟合了一个适合拖拽物回弹的曲线。模拟一种弹性拉扯的效果。

在这里插入图片描述

写入代码后测试一下效果:

var mySpringOut =(double x) => (x - 1) * (x - 1) * ((5f + 1) * (x - 1) + 5) + 1;
await Content.TranslateTo(PositionX, PositionY, 200, mySpringOut);

在这里插入图片描述

多重动画

在回弹的同时,大小要恢复到原来的大小,我们可以通过动画改变Scale属性来实现。

改变大小和改变位置的动画是同时进行的,我们通过创建Animation对象,添加子动画来实现。详情请参考Animation子动画。

 Content.AbortAnimation("ReshapeAnimations");
var parentAnimation = new Animation();
var mySpringOut =(double x) => (x - 1) * (x - 1) * ((5f + 1) * (x - 1) + 5) + 1;var scaleUpAnimation1 = new Animation(v => Content.TranslationX = v, Content.TranslationX, PositionX, mySpringOut);
var scaleUpAnimation2 = new Animation(v => Content.TranslationY = v, Content.TranslationY, PositionY, mySpringOut);
var scaleUpAnimation5 = new Animation(v => Content.Scale = v, Content.Scale, 1.0);parentAnimation.Add(0, 1, scaleUpAnimation1);
parentAnimation.Add(0, 1, scaleUpAnimation2);
parentAnimation.Add(0, 1, scaleUpAnimation5);parentAnimation.Commit(this, "RestoreAnimation", 16, (uint)PanScaleAnimationLength);

在开始拖拽的时候,也加上缩小的动画,这样拖拽的时候,拖拽物会缩小,释放的时候会恢复原来的大小。

Content.AbortAnimation("ReshapeAnimations");
var scaleAnimation = new Animation();
var scaleUpAnimation0 = new Animation(v => Content.Scale = v, Content.Scale, PanScale);
scaleAnimation.Add(0, 1, scaleUpAnimation0);scaleAnimation.Commit(this, "ReshapeAnimations", 16, (uint)PanScaleAnimationLength);

注意,放大和缩小是两个成对的动画,他们共同持有一个handler即ReshapeAnimations,不能同时进行,所以在开始一个动画前,要先调用Content.AbortAnimation(“ReshapeAnimations”)以终止之前的动画。

最终运行效果:

在这里插入图片描述

点击动画

点击时为了模拟水波纹效果,可以使用多重动画来实现。

在点击时,我们分三次连续的缩小,放大再缩小,这样就会有一个水波纹的效果。

在点击手势的OnTapped响应事件处理方法中,添加如下代码:

private void TapGestureRecognizer_OnTapped(object sender, EventArgs e)
{var scaleAnimation = new Animation();var scaleUpAnimation0 = new Animation(v => Content.Scale = v, 1.0, 0.9);var scaleUpAnimation1 = new Animation(v => Content.Scale = v, 0.9, 1.1);var scaleUpAnimation2 = new Animation(v => Content.Scale = v, 1.1, 1.0);scaleAnimation.Add(0, 0.3, scaleUpAnimation0);scaleAnimation.Add(0.3, 0.6, scaleUpAnimation1);scaleAnimation.Add(0.6, 1, scaleUpAnimation2);scaleAnimation.Commit(this, "ReshapeAnimations", 16, 400);this.OnTapped?.Invoke(this, EventArgs.Empty);
}

最终运行效果:

在这里插入图片描述

下一章将结合手势容器实现一个圆形进度条。

项目地址

Github:maui-samples


http://www.ppmy.cn/news/41992.html

相关文章

vue 报错 error:03000086:digital envelope routines::initialization error解决方案

目录 1. 引言: 2. 更换版本出现问题: 3. 出现原因: 4. 解决办法: -> 4. 1 删了 再换回16.15版本 -> 4.2 指令修改(好使) ---> 4.2.1效果如图 -> 4.3 其他指令就别试了 压根不好使 1. 引言: npm出现问题 , 卸载后 装了个新node 18.15版本 2. 更换版本…

springboot+vue动物园管理系统java

本系统使用的角色主要有系统管理员、注册用户,本系统分为系统前台和系统后台,首先在系统前台,游客用户可以经过账号注册,管理员审核通过后,用账号密码登录系统前台,查看论坛交流、动物展览、原生动物展览、…

webgl-画任意多边形

注意: let canvas document.getElementById(webgl) canvas.width window.innerWidth canvas.height window.innerHeight let radio window.innerWidth/window.innerHeight; let ctx canvas.getContext(webgl) 由于屏幕长宽像素不一样,导致了长宽像素…

04 | 连接池:别让连接池帮了倒忙

04 | 连接池:别让连接池帮了倒忙 连接池一般对外提供获得连接、归还连接的接口给客户端使用,并暴露最小空闲连接数、最大连接数等可配置参数,在内部则实现连接建立、连接心跳保持、连接管理、空闲连接回收、连接可用性检测等功能。 注意鉴…

分享57个Python源码,总有一款适合您

Python源码 分享57个Python源码,总有一款适合您 57个Python源码下载链接:https://pan.baidu.com/s/1YZcrJAYFFy3OrdEN5IxnQQ?pwd6666 提取码:6666 采集代码下载链接:采集代码.zip - 蓝奏云 下面是文件的名字,我放了…

[牛客复盘] 牛客小白月赛70 20230407

[牛客复盘] 牛客小白月赛70 20230407 一、本周周赛总结A、 小d和答案修改2. 思路分析3. 代码实现B、小d和图片压缩1. 题目描述2. 思路分析3. 代码实现C、小d和超级泡泡堂1. 题目描述2. 思路分析3. 代码实现D、小d和孤独的区间1. 题目描述2. 思路分析3. 代码实现E、小d的博弈1. …

wsl使用vscode搭建自己的MySQL

装wsl装MySQL装wsl 我已经装好了,就不说了 装MySQL 安装 MySQL 服务器:终端命令行输入sudo apt install mysql-server 安装完成后,MySQL 服务器会自动启动并在 Ubuntu 启动时启动。您可以使用以下命令检查 MySQL 服务器是否正在运行:sudo ser…

Geoserver启动时提示:The GEOSERVER_HOME variable is not defined

场景 GeoServer简介、下载、配置启动、发布shapefile全流程(图文实践): GeoServer简介、下载、配置启动、发布shapefile全流程(图文实践)_霸道流氓气质的博客-CSDN博客 在下载解压之后点击启动bat时提示: The GEOSERVER_HOME environment variable is not defin…

ASP.NET Core MVC 从入门到精通之接化发(一)

随着技术的发展,ASP.NET Core MVC也推出了好长时间,经过不断的版本更新迭代,已经越来越完善,本系列文章主要讲解ASP.NET Core MVC开发B/S系统过程中所涉及到的相关内容,适用于初学者,在校毕业生&#xff0c…

python学习(1) - 基础数据结构(列表元组集合字典)

文章首发于:欢迎大佬们前来逛逛 文章目录列表元组和序列集合字典循环技巧列表 列表是最简单的数据类型,相当于数组。 列表的基础操作函数列表模拟栈队列列表推导式 以下是列表的常见操作: l [1, 2, 3, 4, 5]# 往末尾添加一个元素 l.append…

前端常用设计模式学习之适配器模式-1分钟快速理解-适配器模式是一种结构性设计模式,它允许将不兼容的对象包装成一个兼容的接口,从而使它们能够在一起工作。

前端常用设计模式学习之适配器模式 适配器模式是一种结构性设计模式,它允许将不兼容的对象包装成一个兼容的接口,从而使它们能够在一起工作。 在前端开发中,适配器模式常常用于将旧版代码与新版代码兼容。例如,我们在使用新版 AP…

TiDB进阶篇-TiDB Server架构

简介 较深入的介绍TiDB Server。 TiDB Server 架构 图解 1.下面是负责SQL语句的解析和优化。 2.下面试负责TiKV存储多版本,过期版本的清理作用。 3.复杂SQL的拆分(如果是点查那么就不需要经过DistSQL)。 4.事务相关。 5.负责PD和TiKV的通信…

Windows10系统安装perl命令

文章目录1,下载ActivePerl 5.28(基于Windows 10系统):1.1,Perl 主页: https://www.perl.org/get.html1.2,选择windows1.3,选择Binaries---activeperla版本1.3,直接选择windows 5.36版…

natapp + nginx 实现内网穿透

环境是我本地的win10 第一步:下载nginx压缩包并解压(这个自行百度吧) 第二步: 修改nginx的配置文件: 在最下方添加: #testserver {listen 8081;#你要映射的端口server_name localhost; #使用本地IPlocation / {proxy_pass…

减半技术实现求a的n次幂

目录 减半技术实现求a的n次幂 程序设计 程序分析 减半技术实现求a的n次幂 【问题描述】给定两个正整数a和n,采用减半技术求a的n次幂;其中a<100,b<20; 【输入形式】两个整数a,n(a与n中间用空格隔开); 【输出形式】一个整数 【样例输入1】2 3 【样例输出1】8 【样…

TiDB实战篇-TiDB配置

简介 熟系TiDB的配置相关。 TiDB的大体参数 系统配置对应的是TiDB-Server,PD和TiKV和TiDB-Server基本在集群配置里面配置。 系统配置 系统变量 | PingCAP 文档中心 集群配置 PD 配置文件描述 | PingCAP 文档中心 配置的存储位置 系统配置存储在TiKV中的&#xff0c;集…

接口自动化测试面试常问的题目及答案,你都会了吗?

目录 前言 接口自动化测试的优势是什么&#xff1f; 你使用过哪些接口自动化测试工具&#xff1f; 你如何设计一个接口自动化测试用例&#xff1f; 接口自动化测试中常见的测试类型有哪些&#xff1f; 你如何解决接口自动化测试中遇到的问题&#xff1f; 如何进行接口自动…

竞赛雷速登,绝顶我为峰

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 【题目背景】 为庆祝华中农业大学第十二届程序设计竞赛&#xff08;校赛&#xff09;线下举办&#xff0c;特出此题&#xff0c;仅表感激涕零之情。 希望参赛选手认真思考&#xff1…

【ERNIE Bot】百度 | 文心一言初体验

文章目录一、前言二、文心一言介绍三、申请体验⌈文心一言⌋四、⌈文心一言⌋初体验1️⃣聊天对话能力2️⃣文案创作能力3️⃣文字转语音能力✨4️⃣AI绘画能力✨5️⃣数理推理能力6️⃣代码生成能力7️⃣使用技巧说明五、总结一、前言 ​ 最近有关人工智能的热门话题冲上热榜…

Baumer工业相机堡盟工业相机如何通过BGAPISDK里的图像处理库进行图像的转换(C#)

Baumer工业相机堡盟工业相机如何通过BGAPISDK里的图像处理库进行图像转换&#xff08;C#&#xff09;Baumer工业相机Baumer工业相机的SDK里图像格式转换的技术背景Baumer工业相机通过BGAPI SDK进行图像转换调用BGAPI SDK的图像转换库ImageProcessor调用BGAPI SDK建立图像调用BG…
最新文章