[MAUI 项目实战] 手势控制音乐播放器(一): 概述与架构
这是一篇系列博文。请关注我,学习更多.NET MAUI开发知识!
- [MAUI 项目实战] 手势控制音乐播放器(一): 概述与架构
- [MAUI 项目实战] 手势控制音乐播放器(二): 手势交互
- [MAUI 项目实战] 手势控制音乐播放器(三): 动画
- [MAUI 项目实战] 手势控制音乐播放器(四):圆形进度条
在之前的博文中提到这个项目,它是为音乐播放器专门开发的基于手势控制的UI界面。
此UI界面可以让用户在不看屏幕的情况下,通过手势来控制音乐播放器的各种操作,如播放、暂停、下一首、上一首。

手势来控制的交互方式适合不方便看手机屏幕时简单的音乐播放需求,在驾车、运动等场景下有较好的用户体验。

架构
跨平台
使用.NET MAU实现跨平台支持,本项目可运行于Android、iOS平台。


播放内核
播放内核使用MatoMusic.Core,查看此博文[MAUI 项目实战] 音乐播放器(二):播放内核
此项目重点关注的是手势交互UI,播放内核的实现将不再赘述。
手势原理
在播放界面的8个方向,分别放置控制区域,通过拖拽圆形专辑(pan)到控制区域(pit),实现对应的控制操作。此示例实现了快进,快退,下一曲,上一曲,播放/暂停操作,pan和pit将在下一章节介绍。
拖拽平移和控制区域的关系,可以抽象成四个状态,分别是Out,In,Over,Start。
手势状态类型PanType定义如下:
- In:pan进入pit时触发,
- Out:pan离开pit时触发,
- Over:释放pan时触发,
- Start:pan开始拖拽时触发
public enum PanType
{
Out, In, Over, Start
}
对拖拽手势的处理,由手势容器控件PanContainer封装,实现方式将在下一章节介绍。
一次有效的控制,经过Start -> In -> Out -> Over的状态变化,并且手指释放位置是在pit的范围内。
当整个控制触发完成后,控件将触发OnfinishedChoise事件。
基本控制
在页面中订阅这个事件,在事件方法中实现控制逻辑。
如上一曲操作,订阅事件后,实现如下逻辑:
private void DefaultPanContainer_OnOnfinishedChoise(object sender, PitGrid e)
{
CurrentPitView = e;
switch (CurrentPitView.PitName)
{
case "LeftPit":
MusicRelatedViewModel.PreAction(null);
break;
...
}
}
控件会将当前触发的pit传递给事件方法,通过pit的名称,可以判断当前触发的是哪个控制区域。
控件在经过pit时会启用广播事件,使用CommunityToolkit库的 WeakReferenceMessenger实现了消息机制,订阅此事件消息可以接收到控件运动的细节,在事件方法中实现自己的逻辑,如界面元素样式的改变。
public NowPlayingPage()
{
InitializeComponent();
WeakReferenceMessenger.Default.Register<PanActionArgs, string>(this, TokenHelper.PanAction, PanActionHandler);
...
}
如在拖拽开始时,显示控制区域的提示信息,拖拽结束时,隐藏提示信息。
private async void PanActionHandler(object recipient, PanActionArgs args)
{
var parentAnimation = new Animation();
Animation scaleUpAnimation1;
Animation scaleUpAnimation2;
switch (args.PanType)
{
case PanType.Over:
scaleUpAnimation1 = new Animation(v => this.PitContentLayout.Opacity = v, PitContentLayout.Opacity, 0, Easing.CubicOut);
scaleUpAnimation2 = new Animation(v => this.TitleLayout.Opacity = v, TitleLayout.Opacity, 1, Easing.CubicOut);
parentAnimation.Add(0, 1, scaleUpAnimation1);
parentAnimation.Add(0, 1, scaleUpAnimation2);
parentAnimation.Commit(this, "RestoreAnimation", 16, 250);
...
快进/快退
拖拽停留在左右控制区域超过一定时间,将触发“快进”或“快退”
播放界面拥有一个定时器,用于拖拽快进、快退功能
private IDispatcherTimer _dispatcherTimer;
拖拽进入控制区域时,启动定时器,停留在左右控制区域大于2s时将触发定时器Tick事件,执行快进或快退操作。
private async void PanActionHandler(object recipient, PanActionArgs args)
{
switch (args.PanType)
{
...
case PanType.In:
switch (args.CurrentPit?.PitName)
{
case "LeftPit":
_dispatcherTimer =Dispatcher.CreateTimer();
_dispatcherTimer.Interval=new TimeSpan(0, 0, 2);
_dispatcherTimer.Tick+= async (o, e) =>
{
this.TipLabel.Text = FaIcons.IconFastBackward;
this.TipTextLabel.Text = "快退";
_runCount++;
await MusicRelatedViewModel.StartFastSeeking(-2);
};
_dispatcherTimer.Start();
this.TipTextLabel.Text = "上一曲";
break;
...
_runCount是个全局变量,记录是否已经执行过快进或快退操作,当退出控制区域时,如果已经执行过快进或快退操作,将停止快进或快退操作,并将计时器停止。
case PanType.Out:
this.PitTipLayout.Children.Clear();
if (this._runCount > 0)
{
MusicRelatedViewModel.EndFastSeeking();
}
if (_dispatcherTimer!=null)
{
_dispatcherTimer.Stop();
}
_runCount = 0;
this.TipTextLabel.Text = string.Empty;
break;
同理,在松手时,应该停止快进或快退操作,并将计时器停止。
case PanType.Over:
...
MusicRelatedViewModel.EndFastSeeking();
if (_dispatcherTimer!=null)
{
_dispatcherTimer.Stop();
}
_runCount = 0;
沉浸模式
_dispatcherTimer2是控制界面进入“沉浸模式”的定时器,当界面无操作5s之后界面将进入沉浸模式,隐藏标题栏。
private void SetupFullScreenMode(int delay = 5)
{
_dispatcherTimer2 =Dispatcher.CreateTimer();
_dispatcherTimer2.Interval=new TimeSpan(0, 0, delay);
_dispatcherTimer2.Tick+= (o, e) =>
{
this.MainCircleSlider.BorderWidth = 3;
this.TitleLayout.FadeTo(0);
};
_dispatcherTimer2.Start();
}
有操作进行时,恢复到正常模式。
case PanType.Start:
...
if (_dispatcherTimer2.IsRunning)
{
_dispatcherTimer2.Stop();
}
SetupNormalMode();
break;
下一章将逐步展开手势控制的实现细节。
项目地址
[MAUI 项目实战] 手势控制音乐播放器(一): 概述与架构的更多相关文章
- 团队项目 NABCD分析java音乐播放器
NABCD分析java音乐播放器 程设计题目:java音乐播放器 一.课程设计目的 1.编程设计音乐播放软件,使之实现音乐播放的功能. 2.培养学生用程序解决实际问题的能力和兴趣. 3.加深java中 ...
- Android开发实战之简单音乐播放器
最近开始学习音频相关.所以,很想自己做一个音乐播放器,于是,花了一天学习,将播放器的基本功能实现了出来.我觉得学习知识点还是蛮多的,所以写篇博客总结一下关于一个音乐播放器实现的逻辑.希望这篇博文对你的 ...
- Android(java)学习笔记234: 服务(service)之音乐播放器
1.我们播放音乐,希望在后台长期运行,不希望因为内存不足等等原因,从而导致被gc回收,音乐播放终止,所以我们这里使用服务Service创建一个音乐播放器. 2.创建一个音乐播放器项目(使用服务) (1 ...
- Android(java)学习笔记177: 服务(service)之音乐播放器
1.我们播放音乐,希望在后台长期运行,不希望因为内存不足等等原因,从而导致被gc回收,音乐播放终止,所以我们这里使用服务Service创建一个音乐播放器. 2.创建一个音乐播放器项目(使用服务) (1 ...
- Andriod小项目——在线音乐播放器
转载自: http://blog.csdn.net/sunkes/article/details/51189189 Andriod小项目——在线音乐播放器 Android在线音乐播放器 从大一开始就已 ...
- Swift实战-豆瓣电台(九)简单手势控制暂停播放(全文完)
Swift实战-豆瓣电台(九)简单手势控制暂停播放 全屏清晰观看地址:http://www.tudou.com/programs/view/tANnovvxR8U/ 这节我们主要讲UITapGestu ...
- Android应用--简、美音乐播放器增加音量控制
Android应用--简.美音乐播放器增加音量控制 2013年6月26日简.美音乐播放器继续完善中.. 题外话:上一篇博客是在6月11号发的,那篇博客似乎有点问题,可能是因为代码结构有点乱的原因,很难 ...
- 自定义css样式结合js控制audio做音乐播放器
最近工作需求需要播放预览一些音乐资源,所以自己写了个控制audio的音乐播放器. 实现的原理主要是通过js调整audio的对象属性及对象方法来进行控制: 1.通过play().pause()来控制音乐 ...
- HTML5项目笔记4:使用Audio API设计绚丽的HTML5音乐播放器
HTML5 有两个很炫的元素,就是Audio和 Video,可以用他们在页面上创建音频播放器和视频播放器,制作一些效果很不错的应用. 无论是视屏还是音频,都是一个容器文件,包含了一些音频轨道,视频轨道 ...
- swift 音乐播放器项目-《lxy的杰伦情歌》开发实战演练
近期准备将项目转化为OC与swift混合开发.试着写一个swift音乐播放器的demo,体会到了swift相对OC的优势所在.废话不多说.先上效果图: watermark/2/text/aHR0cDo ...
随机推荐
- Alibaba Cloud Linux 3.2104 64位安装mysql5.6.45
1 .安装cmake wget http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz tar -zxvf cmake-2.8.10.2.tar.g ...
- python中的变量定义
1 变量名:由下划线.字母和数字组成 2 python中变量名的特殊含义: xx:标准的标识符,共有的 _xx:只是在from - import *时是不会被导入的,其他导入方式会被引入 隐藏变量还有 ...
- 剑指offer----1.二维数组查找
题目:在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. ...
- [Python]Running multiprocessing
import multiprocessing as mp import time def name_and_time(name,num): print(f"Hello {name}, cur ...
- Angular 管道和路由
管道pipe: 要在HTML模板中指定值转换,请使用管道运算符(|). {{interpolated_value | pipe_name}} 您可以链接管道,发送一个管道功能的输出以被另一个管道功能转 ...
- python中and和or表达式的返回值
a or b 首先明确运算顺序, 从左至右 # 其次只要存在真就会返回真, and返回的是最后一个真, or返回的是第一个真 # 再次, a,b中存在假, 则and返回第一个假, or返回最后一个假 ...
- Leecode 206.反转链表(Java)
想法: 1.设链表长度为n,如5,头节点head,则最后一个元素位置为head-1. 错误,发现行不通,此为链表非数组,存储位置不连续 2.设两个指针p,q,让p,q指向head,再 ...
- BeanFactory与FactoryBean区别
1. BeanFactory BeanFactory,以Factory结尾,表示它是一个工厂类(接口),用于管理Bean的一个工厂.在Spring中,BeanFactory是IOC容器的核心接口,也是 ...
- 文件搜索失败:cannot update repo 'Media": No LRO_ URLS, LRO_MIRRORLISTURL nOr LRO _METALINKURL specified
配置yum源 1.产看当前系统版本 cat /etc/redhat-release 2.进入/etc/yum.repos.d目录,新建bak目录,将系统自带的yum移到bak目录 cd /etc/yu ...
- 有时候用uniapp写项目时发现,Map组件在安卓真机可以缩放和移动,但是在ios真机就不行
如果你的地图组件是放到popup组件里,是用弹框打开的,如何ios端不能缩放, 那你一定要看下这个弹框的层级是否比地图层级要高 z-index. 如果高于地图层级,那地图肯定是不能移动和缩放的