首页 > 其他分享 >[MAUI]模仿微信“按住-说话”的交互实现

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

时间:2023-04-15 20:46:41浏览次数:53  
标签:动画 fromColor Color 微信 var parentAnimation MAUI 交互 TalkBox

@

目录
.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

标签:动画,fromColor,Color,微信,var,parentAnimation,MAUI,交互,TalkBox
From: https://www.cnblogs.com/jevonsflash/p/17321805.html

相关文章

  • 微信小程序后端开发
    微信开发javaSDKhttps://gitee.com/binary/weixin-java-tools<dependency><groupId>com.github.binarywang</groupId><artifactId>(不同模块参考下文)</artifactId><version>4.4.0</version></dependency>微信小程序:weixin-jav......
  • 【小程序】微信小程序基础语法讲解(一)
    目录一、概述二、小程序代码组成1)JSON配置2)WXML模板1、WXML模板常用标签2、view标签与block标签的区别3、条件控制1、wx:if条件控制2、wx:if/else条件控制3、wx:for循环3)WXSS样式4)JS(JavaScript)逻辑交互1、生命周期函数2、事件函数3、双向绑定三、目录结构四、Page构造......
  • vue3微信公众号商城项目实战系列(5)页面适配手机屏幕
    上一篇完成了2个页面之间的跳转,在浏览器中也可以正常浏览和跳转,但这2个页面并没有为适配手机屏幕设计,如果我们用chrome浏览器模拟手机屏幕的大小后再看,结果如下图:(注:用chrome模拟手机屏幕只需要在正常情况下按下F12键,然后点击红框2处的小图标就可以了,改变模拟屏幕的大小......
  • 网页版微信抓包和IPAD微信抓包 Wireshark
    #在51CTO的第一篇博文#本来想抓普通网页版微信,但是换了好几个微信号说安全问题无法登陆,,,只能去QQ浏览器的微信(应该是插件)。只是熟悉了一下过程,并没有深入分析微信传输协议(其实是不会)。网页版微信一:实验目标1.认识web端微信通过TCP建立连接和使用SSL/TLS协议进行数据加密的过程。2.......
  • Maui安卓调试时部署报错:ADB1000
    突发情况,于是重新建了个项目,什么都没动的直接选择安卓仿真器。点击部署。于是等了半天,打开仿真器变慢了。部署也变慢了,CPU直接嗷嗷响,温度瞬间直飙80多度。接着仿真器是打开了,但一直都是黑屏。然后就是一个报错。报错内容: 错误ADB1000:System.IO.FileNotFoundException:......
  • vue3微信公众号商城项目实战系列(4)第一个页面
    在开始写第一个页面之前,先简单看下index.html、App.vue、main.js、HelloWorld.vue、TheWelcome.vue、WelcomeItem.vue这几个页面及文件是怎么运作的,然后再新建2个页面,完成从一个页面跳转到另一个页面这个最简单的操作。 index.html和main.js代码如下:index.html文件的......
  • MAUI之Android记录设备号+动态授权
    一、获取Android唯一标识的方法android10以前的版本可以通过获取imei得到设备的唯一标识,但是android10以后的系统已无法获取到imei。那么我们该如何确定设备呢?查阅了一些资料,个人看来下面的方法最为稳妥:通过在app外部保存一个guid,每次打开app时读取该guid确定为设备号。保存......
  • 使用vscode开发微信小程序
    1.安装插件  2.文件-打开文件夹-将新建的微信小程序导入,代码会有高亮的效果 3.编辑内容,查看效果,如果有就说明插件引入成功。 ......
  • 使用VS Code开发微信小程序
    使用VSCode开发微信小程序微信开发工具结构缺点VSCodeVSCode下载插件Chinese小程序开发助手Easylessminappvscodewxmlwechat-snippet中文乱码处理配置Easyless说明 微信开发工具说归说,但是开发微信小程序的时候,这个微信开发工具......
  • 人机交互-11-往年试卷
    1.选择题【2016】(Nielsen)提出了十条启发式设计原则【2014】文件复制到另一地方,会出现显示动画,这个属于(反馈)现象2.简答题2.1.写出下列核心词汇的英文全称(6’)【2015】人机交互:HumanComputerInteraction【2015】以用户为中心的设计:UserCenteredDesing【2015】启发式评估:heu......