这是一篇系列博文。请关注我,学习更多.NET 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;

下一章将逐步展开手势控制的实现细节。

项目地址

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. 第11章 配置ASP.NET Core应用程序(ASP.NET Core in Action, 2nd Edition)

    本章包括 从多个配置提供程序加载设置 安全存储敏感设置 使用强类型设置对象 在不同的宿主环境中使用不同的设置 在本书的第1部分中,您学习了ASP.NET Core应用程序启动和运行的基础知识,以及如何 ...

  2. .netCore Nuget包引用记录

    1.画图  System.Drawing.Common 2.

  3. 关于cmake找不到库的问题

    1. Error:Could not find a configuration file for package 解决办法1:将/usr/lib/x86_64-linux-gnu/cmake/.... ...

  4. Expression #1 of SELECT list is not in GROUP BY clause and contains nonag

    报错信息: Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'a.rs ...

  5. InnoDB和MyISAM的区别(超详细)

    1.事务 InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务: ...

  6. 更改yum源

    1)cd /etc/yum.repos.d/ 2)wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/C ...

  7. 10、jmeter的 Http的请求默认值

    在我们测试过程当中,有很多HTTP协议的请求 这些请求 有很多比如说网址(url)都是相同的 端口也是相同的,路径可能也是相同的 这个时候就需要用到请求默认值,后续直接用就可以  不需要再去配置 后续 ...

  8. python 猜数字

    方法一 import randomif __name__ == '__main__':    yourname = input("你好! 你的名字是什么?\n");    prin ...

  9. 【Linux】虚拟机CentOS 7 磁盘扩容

    [Linux]虚拟机CentOS 7 磁盘扩容 在有些时候,自己或者公司开的虚拟机的磁盘在一开始的时候没规划好,或者有磁盘扩容的需求(其实在系统日常运维的时候这个需求时常出现),那么这个时候又该怎么处 ...

  10. SQLyog中创建的数据库在idea找不到

    在里面把需要的数据库