文章目录

  • 创建页面布局
  • 创建手势控件
  • 创建TalkBox
  • 创建动画
    • 拖拽物动画
    • 按钮激活动画
    • TalkBox动画
    • Layout动画
  • 项目地址

.NET MAUI 跨平台框架包含了识别平移手势的功能,在之前的博文 [MAUI 项目实战] 手势控制音乐播放器(二): 手势交互中利用此功能实现了pan-pit拖拽系统。

简单来说就是拖拽物(pan)体到坑(pit)中,手势容器控件PanContainer描述了pan运动和pit位置的关系,并在手势运动中产生一系列消息事件。

今天使用这个控件,做一个模仿微信“按住-说话”的小功能,最终效果如下:

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

创建页面布局

新建.NET MAUI项目,命名HoldAndSpeak
MainPage.xaml中创建一个PitContentLayoutGrid容器,并对Grid容器进行如下布局:

在手机屏幕的底部设置两行两列的布局:

第一行第一列,对应取消发送手势区域,
第一行第二列,对应语音转文字手势区域,
第二行独占两列,对应发送手势区域。

布局如下图所示

<Grid x:Name="PitContentLayout"Opacity="1"><Grid.RowDefinitions><RowDefinition Height="1*" /><RowDefinition Height="1*" /></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="1*" /><ColumnDefinition Width="1*" /></Grid.ColumnDefinitions>
</Grid>

创建三个PitGrid控件,并对这三个功能区域的PitGrid控件命名,CancelPitTransliterationPit,分别对应了取消发送、语音转文字、发送。

为每个PitGrid控件添加内容:

发送区域是一个底部弧形区域,我们用一个巨大的圆形+Y轴方向的偏移,通过只保留屏幕底部往上的一部分圆形区域来实现底部弧形区域的效果,代码如下:

<BoxView TranslationY="450"x:Name="SendBox"HeightRequest="1000"WidthRequest="1000"CornerRadius="500">
</BoxView>

取消发送和语音转文字区域是一个圆形区域,我们用一个正常大小的圆形来实现。

PitContentLayout区域整体代码如下

<Grid x:Name="PitContentLayout"Opacity="1"><Grid.RowDefinitions><RowDefinition Height="1*" /><RowDefinition Height="1*" /></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="1*" /><ColumnDefinition Width="1*" /></Grid.ColumnDefinitions><controls1:PitGrid x:Name="CancelPit"TranslationX="-40"PitName="CancelPit"><BoxView x:Name="CancelBox"HeightRequest="80"WidthRequest="80"CornerRadius="50"Margin="7.5"Color="{StaticResource PhoneContrastBackgroundBrush}"VerticalOptions="CenterAndExpand"HorizontalOptions="CenterAndExpand"></BoxView><Label   x:Name="CancelLabel"TextColor="{StaticResource PhoneContrastForegroundBrush}"FontFamily="FontAwesome"FontSize="28"Rotation="-10"HorizontalOptions="CenterAndExpand"Margin="0"></Label></controls1:PitGrid><controls1:PitGrid x:Name="TransliterationPit"PitName="TransliterationPit"TranslationX="40"Grid.Column="1"><BoxView x:Name="TransliterationBox"HeightRequest="80"WidthRequest="80"CornerRadius="50"Margin="7.5"Color="{StaticResource PhoneContrastBackgroundBrush}"VerticalOptions="CenterAndExpand"HorizontalOptions="CenterAndExpand"></BoxView><Label  x:Name="TransliterationLabel"TextColor="{StaticResource PhoneContrastForegroundBrush}"FontSize="28"Text="文"Rotation="10"HorizontalOptions="CenterAndExpand"Margin="0"></Label></controls1:PitGrid><controls1:PitGrid x:Name="SendPit"PitName="SendPit"Grid.ColumnSpan="2"Grid.Row="1"><BoxView TranslationY="450"x:Name="SendBox"HeightRequest="1000"WidthRequest="1000"CornerRadius="500"Margin="7.5"Color="{StaticResource PhoneContrastBackgroundBrush}"VerticalOptions="CenterAndExpand"HorizontalOptions="CenterAndExpand"></BoxView><Label x:Name="SendLabel"TranslationY="30"FontSize="28"Rotation="45"TextColor="{StaticResource PhoneContrastForegroundBrush}"FontFamily="FontAwesome"HorizontalOptions="CenterAndExpand"Margin="0"></Label></controls1:PitGrid></Grid>

效果如下

创建手势控件

创建一个手势控件。他包裹的内容。是一个带有按住说话的按钮。

<controls1:PanContainer BackgroundColor="Transparent"x:Name="DefaultPanContainer"OnTapped="DefaultPanContainer_OnOnTapped"AutoAdsorption="False"OnfinishedChoise="DefaultPanContainer_OnOnfinishedChoise"><Grid PropertyChanged="BindableObject_OnPropertyChanged"VerticalOptions="Start"HorizontalOptions="Start"><BoxView HeightRequest="80"WidthRequest="250"Margin="7.5"Color="{StaticResource PhoneContrastBackgroundBrush}"></BoxView><Label  x:Name="PauseLabel"HorizontalOptions="CenterAndExpand"FontSize="28"TextColor="{StaticResource PhoneForegroundBrush}"Text="按住 说话"Margin="0"></Label></Grid></controls1:PanContainer>

此时应该是可以拖动,并且在拖拽开始,进入pit,离开pit,释放时,分别触发Start,In,Out,Over四个状态。

但我们希望在拖拽时隐藏这个按钮,这将在创建动画章节将介绍。

创建TalkBox

创建一个圆角矩形,用来显示正在说话的动画。

<Grid Grid.Row="1"Opacity="1"x:Name="TalkBoxLayout"><BoxView x:Name="TalkBox"HeightRequest="80"WidthRequest="200"CornerRadius="20"Margin="7.5"Color="{StaticResource PhoneAccentBrush}"VerticalOptions="CenterAndExpand"HorizontalOptions="CenterAndExpand"></BoxView><controls:PlayingMotionView   HorizontalOptions="CenterAndExpand"x:Name="MotionView"Margin="0"></controls:PlayingMotionView></Grid>
</Grid>

效果如下

创建动画

拖拽物动画

在拖拽时我们希望可以隐藏拖拽物,设置 PanScalePanScaleAnimationLength属性为0,代码如下:

<controls1:PanContainer BackgroundColor="Transparent"x:Name="DefaultPanContainer"OnTapped="DefaultPanContainer_OnOnTapped"AutoAdsorption="False"PanScale="0.0"PanScaleAnimationLength="0">

按钮激活动画

Codebeind代码中,配置Active和DeActive方法,用于激活和取消激活功能区域按钮的样式。

激活时,对应功能区域按钮背景颜色变为白色,字体颜色变为黑色,并且放大到1.2倍。
取消激活时,恢复到原来的样式。

代码如下

private void Active(BoxView currentContent, Label text, Color toColor, Color txtToColor, double scaleTo = 1.2)
{currentContent.AbortAnimation("ActivateFunctionAnimations");var parentAnimation = new Animation();var txtFromColor = text.TextColor;var animation2 = new Animation(t => text.TextColor = GetColor(t, txtFromColor, txtToColor), 0, 1, Easing.SpringOut);var fromColor = currentContent.Color;var animation4 = new Animation(t => currentContent.Color = GetColor(t, fromColor, toColor), 0, 1, Easing.SpringOut);var animation5 = new Animation(v => currentContent.Scale = v, currentContent.Scale, scaleTo);parentAnimation.Add(0, 1, animation2);parentAnimation.Add(0, 1, animation4);parentAnimation.Add(0, 1, animation5);parentAnimation.Commit(this, "ActivateFunctionAnimations", 16, 300);
}private void DeActive(BoxView currentContent, Label text)
{currentContent.AbortAnimation("DeactivateFunctionAnimations");var parentAnimation = new Animation();var txtFromColor = text.TextColor;var txtToColor = (Color)Application.Current.Resources["PhoneContrastForegroundBrush"];var animation2 = new Animation(t => text.TextColor = GetColor(t, txtFromColor, txtToColor), 0, 1, Easing.SpringOut);var fromColor = currentContent.Color;var toColor = (Color)Application.Current.Resources["PhoneContrastBackgroundBrush"];var animation4 = new Animation(t => currentContent.Color = GetColor(t, fromColor, toColor), 0, 1, Easing.SpringOut);var animation5 = new Animation(v => currentContent.Scale = v, currentContent.Scale, 1.0);parentAnimation.Add(0, 1, animation2);parentAnimation.Add(0, 1, animation4);parentAnimation.Add(0, 1, animation5);parentAnimation.Commit(this, "DeactivateFunctionAnimations", 16, 300);
}

在拖拽进入pit的事件中设置激活状态,在拖拽离开pit的事件中设置取消激活状态。


case PanType.Out:switch (args.CurrentPit?.PitName){case "CancelPit":DeActive(this.CancelBox, this.CancelLabel);break;case "SendPit":DeActive(this.SendBox, this.SendLabel);break;case "TransliterationPit":DeActive(this.TransliterationBox, this.TransliterationLabel);break;default:break;}break;
case PanType.In:var parentAnimation = new Animation();Color toColor = default;double translationX = default;double width = default;switch (args.CurrentPit?.PitName){case "CancelPit":Active(this.CancelBox, this.CancelLabel, Colors.White, Colors.Black);this.TalkBox.AbortAnimation("TalkBoxAnimations");break;case "SendPit":Active(this.SendBox, this.SendLabel, Colors.Gray, Colors.Black, 1.0);break;case "TransliterationPit":Active(this.TransliterationBox, this.TransliterationLabel, Colors.White, Colors.Black);break;default:break;}

TalkBox动画

创建GetColor方法,使用插值法用于获取渐变过程中获取当前进度的颜色

    private Color GetColor(double t, Color fromColor, Color toColor){return Color.FromRgba(fromColor.Red + t * (toColor.Red - fromColor.Red),fromColor.Green + t * (toColor.Green - fromColor.Green),fromColor.Blue + t * (toColor.Blue - fromColor.Blue),fromColor.Alpha + t * (toColor.Alpha - fromColor.Alpha));}

在进入功能区域时,TalkBox的颜色,偏移量和宽度都会发生变化,创建一个复合动画TalkBoxAnimations,用于触发TalkBox的动画效果。

this.TalkBox.AbortAnimation("TalkBoxAnimations");var fromColor = this.TalkBox.Color;var animation2 = new Animation(t => this.TalkBox.Color = GetColor(t, fromColor, toColor), 0, 1, Easing.SpringOut);
var animation4 = new Animation(v => this.TalkBoxLayout.TranslationX = v, this.TalkBoxLayout.TranslationX, translationX);
var animation5 = new Animation(v => this.TalkBox.WidthRequest = v, this.TalkBox.Width, width);parentAnimation.Add(0, 1, animation2);
parentAnimation.Add(0, 1, animation4);
parentAnimation.Add(0, 1, animation5);parentAnimation.Commit(this, "TalkBoxAnimations", 16, 300);

最终效果如下:

Layout动画

创建一个用于显示功能区域和TalkBox的渐变动画,用于在拖拽开始和结束时,显示和隐藏这两个控件。

private void ShowLayout(double opacity = 1)
{this.PitContentLayout.FadeTo(opacity);this.TalkBoxLayout.FadeTo(opacity);
}
case PanType.Over:ShowLayout(0);break;
case PanType.Start:ShowLayout();break;

项目地址

Github:maui-samples

[MAUI]模仿微信“按住-说话”的交互实现相关推荐

  1. 微信按住说话HTML实现

    直接看代码来得快: <meta name="viewport" content="width=device-width, initial-scale=1.0, ma ...

  2. pc端和移动端鼠标事件,实现与微信按住说话差不多的按键

    1.移动端: 事件类型: touchstart : 触摸开始(手指放在触摸屏上) touchmove : 拖动(手指在触摸屏上移动) touchend : 触摸结束(手指从触摸屏上移开) 直接上栗子, ...

  3. js 在页面实现微信按住说话,移开取消录音效果

    获取起点(touchstart)Y轴坐标与终点(touchend)Y轴坐标,如果起点大于终点那么就去执行取消操作 ********:坐标起点是浏览器左上角,所以往上滑动的话,起点坐标大于终点坐标. 点 ...

  4. android按住录音按钮_Android模仿微信录音、发送语音效果实现

    在项目开发中,有个需求:实现模仿微信录音,发送语音的功能.长按按钮录音,弹框显示语音时间,以及上滑取消发送.我重写了一个发送语音的控件,以实现该功能. 首先添加权限: AudioRecorderBut ...

  5. 小程序仿微信聊天按住说话功能

    小程序仿微信聊天按住说话功能 实现:按住说话有录音动画,上滑可取消发送,松开发送录音 录音授权判断 # .wxml <view class="btn {{touchBtn?'hover ...

  6. php按住说话然后播放,小程序仿微信聊天按住说话功能

    小程序仿微信聊天按住说话功能 实现:按住说话有录音动画,上滑可取消发送,松开发送录音 录音授权判断 # .wxml bind:longpress="onLongpress" cat ...

  7. uniapp微信小程序实现按住说话功能

    前端页面布局代码 描述:@longpress是uniapp的事件,长按时触发的事件,@touchend事件可以监听松开按钮时触发的. <!-- 上传语音 --><view class ...

  8. [MAUI]模仿网易云音乐黑胶唱片的交互实现

    文章目录 创建页面布局 创建手势控件 创建影子控件 唱盘拨动交互 唱盘和唱针动画 项目地址 用过网易云音乐App的同学应该都比较熟悉它播放界面. 这是一个良好的交互设计,留声机的界面隐喻准确地向人们传 ...

  9. 李长军android语音开发_Android模仿微信录音、发送语音效果实现

    在项目开发中,有个需求:实现模仿微信录音,发送语音的功能.长按按钮录音,弹框显示语音时间,以及上滑取消发送.我重写了一个发送语音的控件,以实现该功能. 首先添加权限: AudioRecorderBut ...

最新文章

  1. 分析与设计(AD)简介(2)
  2. 如何判断一个元素在亿级数据中是否存在?
  3. leetcode C++ 2. 两数相加 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 如果,我们将这两个数
  4. 《c语言从入门到精通》看书笔记——第1章 C语言的概述
  5. python在统计专业的应用_Python:使用Counter进行计数统计
  6. 技术圈的女性工程师都去哪呢?
  7. 三、系统分层和分割策略
  8. php中session总结,PHP中SESSION使用中的一点经验总结
  9. android web sevice,Web Service在Android开发中的应用研究
  10. android百度地图导航功能开发,Android百度地图应用开发基础知识
  11. zookeeper学习一-ZK简介
  12. 用c语言绘制小猫图案,【科研猫·R】R语言从入门到精通:Day8
  13. 这些“新职业”到底好不好干?听听过来人怎么说
  14. 免费开源的几款Web服务器软件简介
  15. 2022-2028年全球与中国全轮驱动(AWD)系统行业深度分析
  16. 工欲善其事!有这些工具你才能修出一张完美的照片
  17. Qt+ECharts开发笔记(五):ECharts的动态排序柱状图介绍、基础使用和Qt封装Demo
  18. [Python]小甲鱼Python视频第019课(函数:我的地盘听我的)课后题及参考解答
  19. Storage Access API 介绍
  20. 局域网如何连接打印机

热门文章

  1. iOS 图片解压缩的过程
  2. 最佳平方逼近的Matlab
  3. 集群中zeus平台的变更
  4. 给初学Java的老铁,知道这4点太重要了!
  5. Android评论工具类,实现QQ空间文字评论效果
  6. gStore:A Graph-based SPARQL Query Engine---part1
  7. 云服务器与虚拟主机有什么区别,我们应该如何选择?
  8. 为什么我要在BDTC2016上担任“大数据云服务”分论坛召集人
  9. 【IP代理】吐槽某大爷IP
  10. 鸿蒙开发之表格布局(TableLayout)