@

上一章节我们创建了手势容器控件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

[MAUI 项目实战] 手势控制音乐播放器(三): 动画的更多相关文章

  1. 团队项目 NABCD分析java音乐播放器

    NABCD分析java音乐播放器 程设计题目:java音乐播放器 一.课程设计目的 1.编程设计音乐播放软件,使之实现音乐播放的功能. 2.培养学生用程序解决实际问题的能力和兴趣. 3.加深java中 ...

  2. Android开发实战之简单音乐播放器

    最近开始学习音频相关.所以,很想自己做一个音乐播放器,于是,花了一天学习,将播放器的基本功能实现了出来.我觉得学习知识点还是蛮多的,所以写篇博客总结一下关于一个音乐播放器实现的逻辑.希望这篇博文对你的 ...

  3. Android(java)学习笔记234: 服务(service)之音乐播放器

    1.我们播放音乐,希望在后台长期运行,不希望因为内存不足等等原因,从而导致被gc回收,音乐播放终止,所以我们这里使用服务Service创建一个音乐播放器. 2.创建一个音乐播放器项目(使用服务) (1 ...

  4. Android(java)学习笔记177: 服务(service)之音乐播放器

    1.我们播放音乐,希望在后台长期运行,不希望因为内存不足等等原因,从而导致被gc回收,音乐播放终止,所以我们这里使用服务Service创建一个音乐播放器. 2.创建一个音乐播放器项目(使用服务) (1 ...

  5. Andriod小项目——在线音乐播放器

    转载自: http://blog.csdn.net/sunkes/article/details/51189189 Andriod小项目——在线音乐播放器 Android在线音乐播放器 从大一开始就已 ...

  6. Swift实战-豆瓣电台(九)简单手势控制暂停播放(全文完)

    Swift实战-豆瓣电台(九)简单手势控制暂停播放 全屏清晰观看地址:http://www.tudou.com/programs/view/tANnovvxR8U/ 这节我们主要讲UITapGestu ...

  7. Android应用--简、美音乐播放器增加音量控制

    Android应用--简.美音乐播放器增加音量控制 2013年6月26日简.美音乐播放器继续完善中.. 题外话:上一篇博客是在6月11号发的,那篇博客似乎有点问题,可能是因为代码结构有点乱的原因,很难 ...

  8. 自定义css样式结合js控制audio做音乐播放器

    最近工作需求需要播放预览一些音乐资源,所以自己写了个控制audio的音乐播放器. 实现的原理主要是通过js调整audio的对象属性及对象方法来进行控制: 1.通过play().pause()来控制音乐 ...

  9. HTML5项目笔记4:使用Audio API设计绚丽的HTML5音乐播放器

    HTML5 有两个很炫的元素,就是Audio和 Video,可以用他们在页面上创建音频播放器和视频播放器,制作一些效果很不错的应用. 无论是视屏还是音频,都是一个容器文件,包含了一些音频轨道,视频轨道 ...

  10. swift 音乐播放器项目-《lxy的杰伦情歌》开发实战演练

    近期准备将项目转化为OC与swift混合开发.试着写一个swift音乐播放器的demo,体会到了swift相对OC的优势所在.废话不多说.先上效果图: watermark/2/text/aHR0cDo ...

随机推荐

  1. 《动态规划学习笔记》Day1-数字金字塔

    这是一道经典的洛谷水题了,虽说是IOI的(但毕竟很古老了),然后我提供一下我的思路吧. 链接洛谷题面:https://www.luogu.com.cn/problem/P1216 首先,金字塔的输入规 ...

  2. char *setlocale(int category, const char *locale)

    category -- 这是一个已命名的常量,指定了受区域设置影响的函数类别. LC_ALL 包括下面的所有选项. LC_COLLATE 字符串比较.参见 strcoll(). LC_CTYPE 字符 ...

  3. Pycharm 2021.3 的激活破解教程,永久激活,亲测有效

    关注公众号回复 pycharm 即可获取激活脚本和教程 更新时间 2022年1月20日. 不定时更新 激活码可在公众号中回复[激活码]获取.

  4. [CQOI2014]通配符匹配 题解

    第一眼:什么鬼东西ヾ(。`Д´。) 第二眼:显然,这道题要分段处理 类似[TJOI2018]碱基序列\ (建议做一做也是Hash+DP)\ 那你怎么第一眼没看出来 Hash处理+DP==AC 直接上代 ...

  5. doy 18 定时任务

    1.定时任务 1.什么是定时任务 类似日常生活之中的闹钟:主要用于定时执行某些命令,达到定时处理数据的作用. 2.定时任务的软件的种类 1.linux操作系统自带的软件:crontab 2.第三方的定 ...

  6. C# 获取当前路径7种方法及输出

    //获取模块的完整路径.string path1 = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;D:\wor ...

  7. 6、jmeter的配置元件:参数化--CSV文件

    1.参数化一些数据,就需要用到csv文件 Filename:文件位置和文件名 (和jmeter同一个目录就不需要写哪个盘 直接写文件名字就可以了) File  encoding:编码 Variable ...

  8. 解决和根源:Unsolicited response received on idle HTTP channel starting with xxx

    环境:golang,使用http client,服务器:iis +aspx.net动作:head请求或其他此问题见于各种请求情况.核心是,http在活动期间收到了非预期的信息.一开始我也很纳-闷,因为 ...

  9. Matlab %贰

    第二章 APPLICATIONS OF MATLAB IN ENGINEERING MATLAB Script %:注解 %%:分节符 Relational Operators < <= ...

  10. python3判断ip类型

    利用socket库附带的校验功能实现校验.