[MAUI程序设计]界面多态与实现

这篇具有很好参考价值的文章主要介绍了[MAUI程序设计]界面多态与实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录
  • 需求一:在不同设备上使用不同 UI 外观
    • 定义控件 UI 外观
    • 基于平台自定义配置
  • 需求二:在不同数据类别中使用不同的 UI 外观
    • 定义视图 UI 外观
    • 创建数据模板
    • 创建选择器
    • 定义数据
  • 需求三:在不同数据状态中使用不同的 UI 外观
    • 使用绑定模型更改控件的外观
    • 使用视觉状态更改控件的外观
  • 项目地址

.NET MAUI 实现界面多态有很多种方式,今天主要来说说在日常开发中常见的需求该如何应对。

需求一:在不同设备上使用不同 UI 外观

.NET MAUI是一个跨平台的UI框架,可在一个项目中开发Android、iOS、Windows、MacOS等多个平台的应用。在不同设备上我们希望应用的界面或交互方式能够有所不同。

比如在本示例中,我们希望博客条目的菜单使用平台特性的交互方式以方便触屏或鼠标的操作:比如手机设备中博客条目的菜单使用侧滑方式呈现,而在桌面设备中使用右键菜单呈现。

要实现不同平台下的控件外观,我们可以定义一个ContentView控件,然后在不同平台上使用不同的控件模板(ControlTemplate)

控件模板(ControlTemplate)是我们的老朋友了,早在WPF时代就已经出现了,它可以完全改变一个控件的可视结构和外观,与使用Style改变控件外观样式和行为样式不同,使用Style只能改变控件已有的属性。

定义控件 UI 外观

首先用控件模板定义博客条目的外观,“博客条目”是包含博客标题,内容,以及发布时间等信息的卡片,视觉上呈现圆角矩形的白色不透明卡片效果。

博客条目控件是一个基于ContentView控件

<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:service="clr-namespace:Lession1.Models;assembly=Lession1"
             x:Class="Lession1.Views.TextBlogView">
    <Grid>
       <VerticalStackLayout>
            <Label Text="{Binding Title}" FontAttributes="Bold">
            </Label>
            <Label Text="{Binding Content}"
                   LineBreakMode="WordWrap"></Label>
        </VerticalStackLayout>
    </Grid>
</ContentView>

在页面的资源中,添加如下两个ControlTemplate模板,分别用于手机设备和桌面设备。

  1. BlogCardViewPhone用于博客条目在手机设备中的呈现,条目菜单侧滑栏方式展开,我们配置SwipeView控件,作为卡片,用一个Frame框架包裹其内容。设置卡片的阴影,圆角,以及内边距。

[MAUI程序设计]界面多态与实现

[MAUI程序设计]界面多态与实现

代码如下

<ControlTemplate x:Key="BlogCardViewPhone">
    <Grid>
        <SwipeView>
            <SwipeView.LeftItems>
                <SwipeItems>
                    <SwipeItem Text="编辑"
                                IconImageSource="delete.png"
                                BackgroundColor="LightGray" />
                    <SwipeItem Text="分享"
                                IconImageSource="delete.png"
                                BackgroundColor="LightGray" />
                    <SwipeItem Text="删除"
                                IconImageSource="delete.png"
                                BackgroundColor="Red" />

                </SwipeItems>
            </SwipeView.LeftItems>
            <Frame  HasShadow="True"
                    Margin="0,10,0,10"
                    CornerRadius="5"
                    Padding="8">
                <VerticalStackLayout>
                    <ContentPresenter />
                    <Label Text="{TemplateBinding BindingContext.PostTime}"
                            FontFamily="FontAwesome"></Label>
                    <Button Text="编辑/发布"
                            Command="{TemplateBinding BindingContext.SwitchState}" />
                </VerticalStackLayout>
            </Frame>
        </SwipeView>
    </Grid>
</ControlTemplate>
  1. BlogCardViewDesktop用于博客条目在桌面设备中的呈现,条目菜单右键菜单方式展开,我们配置FlyoutBase.ContextFlyout属性,作为卡片,用一个Frame框架包裹其内容。设置卡片的阴影,圆角,以及内边距。

[MAUI程序设计]界面多态与实现

代码如下:

<ControlTemplate x:Key="BlogCardViewDesktop">
    <Frame HasShadow="True"
            Margin="0,10,0,10"
            CornerRadius="5"
            Padding="8">
        <FlyoutBase.ContextFlyout>
            <MenuFlyout>
                <MenuFlyoutItem Text="编辑" />
                <MenuFlyoutItem Text="分享" />
                <MenuFlyoutItem Text="删除" />
            </MenuFlyout>
        </FlyoutBase.ContextFlyout>

        <VerticalStackLayout>
            <ContentPresenter  />
            <Label Text="{TemplateBinding BindingContext.PostTime}"
                    FontFamily="FontAwesome"></Label>
            <Button Text="编辑/发布"
                    Command="{TemplateBinding BindingContext.SwitchState}" />
        </VerticalStackLayout>
    </Frame>

</ControlTemplate>

.NET MAUI 提供了ContentPresenter作为模板控件中的内容占位符,用于标记模板化自定义控件或模板化页面要显示的内容将在何处显示。

各平台模板中的<ContentPresenter /> 将显示控件的Content属性,也就是将TextBlogView中定义的内容,放到ContentPresenter处。

<view:TextBlogView ControlTemplate="{StaticResource BlogCardViewPhone}">
</view:TextBlogView>

基于平台自定义配置

.NET MAUI 提供了 OnPlatform 标记扩展和 OnIdiom 标记扩展。以便在不同平台上使用不同的控件模板。

通过 OnPlatform 标记扩展可基于每个平台控件属性:

属性 描述
Default 平台的属性的默认值。
Android 属性在 Android 上应用的值。
iOS 属性在 iOS 上应用的值。
MacCatalyst 设置为要在 Mac Catalyst 的值。
Tizen 属性在 Tizen 平台的值。
WinUI 属性在 WinUI 的值。

通过 OnIdiom 标记扩展可基于设备语义上的控件属性

属性 描述
Default 设备语义的属性的默认值。
Phone 属性在手机上应用的值。
Tablet 属性在平板电脑的值。
Desktop 设置为要在桌面平台的值。
TV 属性在电视平台的值。
Watch 属性在可穿戴设备(手表)平台的值。

在本示例中,我们使用OnIdiom标记扩展,分别为手机和桌面设备配置不同的模板。

<view:TextBlogView>
    <view:TextBlogView.ControlTemplate>
        <OnIdiom Phone="{StaticResource BlogCardViewPhone}"
                    Desktop="{StaticResource BlogCardViewDesktop}">
        </OnIdiom>
    </view:TextBlogView.ControlTemplate>
</view:TextBlogView>

需求二:在不同数据类别中使用不同的 UI 外观

数据模板(DataTemplate) 可以在支持的控件上(如:CollectionView)定义数据表示形式
可以使用数据模板选择器(DataTemplateSelector) 来实现更加灵活的模板选择。

DataTemplateSelector 可用于在运行时根据数据绑定属性的值来选择 DataTemplate。 这样可将多个 DataTemplate 应用于同一类型的对象,以自定义特定对象的外观。

相对于ControlTemplate方式,DataTemplateSelector是从Xamarin.Forms 2.1引入的新特性。

定义视图 UI 外观

创建两种视图和模板选择器:

[MAUI程序设计]界面多态与实现

  • TextBlog: 文本博客
  • PhotoBlog: 图片博客

编写文本博客条目展示标题和内容,创建TextBlogView.xaml,定义如下:

<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:service="clr-namespace:Lession1.Models;assembly=Lession1"
             x:Class="Lession1.Views.TextBlogView">
    <Grid>
       <VerticalStackLayout>
            <Label Text="{Binding Title}" FontAttributes="Bold">
            </Label>
            <Label Text="{Binding Content}"
                   LineBreakMode="WordWrap"></Label>
        </VerticalStackLayout>
    </Grid>
</ContentView>

编写图片博客条目展示标题和博客中图片的缩略图,创建PhotoBlogView.xaml,定义如下:

<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:service="clr-namespace:Lession1.Models;assembly=Lession1"
             x:Class="Lession1.Views.PhotoBlogView">
    <Grid>
        <Label Text="{Binding Title}"
                FontAttributes="Bold">
        </Label>
        <StackLayout BindableLayout.ItemsSource="{Binding Images}"
                        Orientation="Horizontal">
            <BindableLayout.ItemTemplate>
                <DataTemplate>
                    <Image Source="{Binding}"
                            Aspect="AspectFill"
                            WidthRequest="44"
                            HeightRequest="44" />
                </DataTemplate>
            </BindableLayout.ItemTemplate>
        </StackLayout>
    </Grid>
</ContentView>

[MAUI程序设计]界面多态与实现

创建数据模板

在页面的资源中,添加各个视图创建数据模板(DataTemplate)类型的资源。

<ContentPage.Resources>
    <DataTemplate x:Key="PhotoBlog">
        <view:PhotoBlogView>
            <view:PhotoBlogView.ControlTemplate>
                <OnIdiom Phone="{StaticResource BlogCardViewPhone}"
                            Tablet="{StaticResource BlogCardViewDesktop}"
                            Desktop="{StaticResource BlogCardViewDesktop}">
                </OnIdiom>
            </view:PhotoBlogView.ControlTemplate>
        </view:PhotoBlogView>
    </DataTemplate>
    <DataTemplate x:Key="TextBlog">
        <view:TextBlogView>
            <view:TextBlogView.ControlTemplate>

                <OnIdiom Phone="{StaticResource BlogCardViewPhone}"
                            Tablet="{StaticResource BlogCardViewDesktop}"
                            Desktop="{StaticResource BlogCardViewDesktop}">
                </OnIdiom>

            </view:TextBlogView.ControlTemplate>
        </view:TextBlogView>
    </DataTemplate>
  
</ContentPage.Resources>

创建选择器

创建BlogDataTemplateSelector,根据博客的类型,返回不同的数据模板(DataTemplate)对象。

public class BlogDataTemplateSelector : DataTemplateSelector
{
    public object ResourcesContainer { get; set; }

    protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
    {
        if (item == null)
        {
            return default;
        }
        if (item is Blog)
        {
            var dataTemplateName = (item as Blog).Type;
            if (dataTemplateName == null) { return default; }
            if (ResourcesContainer == null)
            {
                return Application.Current.Resources[dataTemplateName] as DataTemplate;
            }
            return (ResourcesContainer as VisualElement).Resources[dataTemplateName] as DataTemplate;

        }
        return default;

    }
}

DataTemplate将在页面资源字典中被创建。若没有绑定ResourcesContainer,则在App.xaml中寻找。

同样, 将BlogDataTemplateSelector添加到页面的资源中

  <view:BlogDataTemplateSelector x:Key="BlogDataTemplateSelector"
ResourcesContainer="{x:Reference MainContentPage}" />

注意,此时BlogDataTemplateSelector.ResourcesContainer指向MainContentPage,显式设置MainPage对象的名称:x:Name="MainContentPage"

定义数据

我们定义一个Blog类, 用于表示博客条目,包含标题,内容,发布时间,图片等属性。

public class Blog 
{
    public Blog()
    {
        PostTime = DateTime.Now;
        State = BlogState.Edit;
    }

    
    public Guid NoteId { get; set; }
    public string Title { get; set; }
    public string Type { get; set; }
    public BlogState State { get; set; }
    public string Content { get; set; }
    public List<string> Images { get; set; }
    public DateTime PostTime { get; set; }
    public bool IsHidden { get; set; }
}

定义博客列表的绑定数据源 ObservableCollection<Blog> Blogs,给数据源初始化一些数据,用于测试。

private async void CreateBlogAction(object obj)
{
    var type = obj as string;
    if (type == "TextBlog")
    {
        var blog = new Blog()
        {
            NoteId = Guid.NewGuid(),
            Title = type + " Blog",
            Type = type,
            Content = type + " Blog Test, There are so many little details that a software developer must take care of before publishing an application. One of the most time-consuming is the task of adding icons to your toolbars, buttons, menus, headers, footers and so on.",
            State = BlogState.PreView,
            IsHidden = false,

        };
        this.Blogs.Add(blog);

    }
    else if (type == "PhotoBlog")
    {
        var blog = new Blog()
        {
            NoteId = Guid.NewGuid(),
            Title = type + " Blog",
            Type = type,
            Content = type + " Blog Test",
            Images = new List<string>() { "p1.png", "p2.png", "p3.png", "p4.png" },
            State = BlogState.PreView,
            IsHidden = false,
        };
        this.Blogs.Add(blog);
    }
}

设置博客列表控件CollectionView绑定的数据源为Blogs,并设置数据模板选择器为BlogDataTemplateSelector

<ContentPage.Content>
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="1*" />
        </Grid.RowDefinitions>
        <!--标题区域-->
        <Label Text="My Blog"
                TextColor="SlateGray"
                FontSize="Header"
                FontAttributes="Bold"></Label>
        <CollectionView x:Name="MainCollectionView"
                        Grid.Row="1"
                        ItemsSource="{Binding Blogs}"
                        ItemTemplate="{StaticResource BlogDataTemplateSelector}" />


    </Grid>
</ContentPage.Content>

则列表中的每个博客条目将根据博客类型,使用不同的数据模板进行渲染。

效果如下:

[MAUI程序设计]界面多态与实现

需求三:在不同数据状态中使用不同的 UI 外观

此功能没有一个固定的解决方案,可以根据实际情况,选择合适的方式实现。

比如在本项目中,博客存在编辑和发布两个状态

public enum BlogState
{
    Edit,
    PreView
}

使用绑定模型更改控件的外观

最简单的方式是用IsVisible来控制控件中元素的显示和隐藏。

在本示例中,TextBlogView需要对编辑中的状态和预览中的状态进行区分。
EnumToBoolConverter是枚举到bool值的转换器,它返回当前绑定对象的State属性与指定的BlogState枚举项是否一致,详情请查看 .NET MAUI 社区工具包

<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:service="clr-namespace:Lession1.Models;assembly=Lession1"
             x:Class="Lession1.Views.TextBlogView">
    <Grid>
        <VerticalStackLayout IsVisible="{Binding State, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static service:BlogState.PreView}}">
            <Label Text="{Binding Title}" FontAttributes="Bold">
            </Label>
            <Label Text="{Binding Content}"
                   LineBreakMode="WordWrap"></Label>
        </VerticalStackLayout>

        <VerticalStackLayout IsVisible="{Binding State, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static service:BlogState.Edit}}">
            <Label Text="编辑"
                   FontAttributes="Bold">
            </Label>
            <Entry Text="{Binding Title}"
                   Placeholder="标题"></Entry>
            <Editor Text="{Binding Content}"
                    AutoSize="TextChanges"
                    Placeholder="内容"></Editor>
        </VerticalStackLayout>
    </Grid>

</ContentView>

编辑状态:

[MAUI程序设计]界面多态与实现

发布状态:

[MAUI程序设计]界面多态与实现

使用视觉状态更改控件的外观

还可以使用定义自定义视觉状态对界面进行控制。

在本示例中,使用VisualStateManager定义了两个视觉状态,分别对应Label的编辑状态和发布状态,当State属性的值发生变化时,会触发对应的视觉状态。

<Label Grid.Row="1">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState Name="BlogPreView">
                <VisualState.StateTriggers>
                    <StateTrigger
                                    IsActive="{Binding State, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static service:BlogState.PreView}}" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Property="Text"
                            Value="当前为发布模式" />

                </VisualState.Setters>
            </VisualState>
            <VisualState Name="BlogEdit">
                <VisualState.StateTriggers>
                    <StateTrigger IsActive="{Binding State, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static service:BlogState.Edit}}" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Property="Text"
                            Value="当前为编辑模式" />

                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

</Label>

编辑状态:

[MAUI程序设计]界面多态与实现

发布状态:

[MAUI程序设计]界面多态与实现

项目地址

Github:maui-learning

关注我,学习更多.NET MAUI开发知识!文章来源地址https://www.toymoban.com/news/detail-444073.html

到了这里,关于[MAUI程序设计]界面多态与实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 《抽象代数极简教程》全书目录 / By 禅与计算机程序设计艺术&ChatGPT

    —— By 禅与计算机程序设计艺术ChatGPT 1.1 集合的基本概念 1.2 二元运算 1.3 代数系统的定义 1.4 例子:整数集合的代数系统 2.1 群的定义 2.2 群的基本性质 2.3 群的例子 2.4 子群 2.5 商群 2.6 同态与同构 3.1 环的定义 3.2 环的基本性质 3.3 环的例子 3.4 理想 3.5 商环 3.6 同态与同构 4

    2024年02月03日
    浏览(56)
  • FireMonkey3D之中国象棋程序(一)界面设计

    声明:本程序设计参考象棋巫师源码(开发工具dephi 11,建议用delphi 10.3以上版本)。 本章目标: 制作一个可操作的图形界面 第一步我们设计图形界面,显示初始化棋局。效果如下图:  我们先做个3D象棋子控件(请看我的博客关于FireMonkey3D的文章:万能控件Mesh详解),源码

    2024年01月20日
    浏览(43)
  • 基于微信在线教育视频学习小程序毕业设计作品成品(11)视频详情和目录

    博主介绍: 《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程,免费 项目配有对应开发文档、开题报告、任务书、PPT、论文模版

    2024年02月08日
    浏览(64)
  • 【老生谈算法】基于matlab时域频域处理的语音信号变声处理系统设计与算法原理(论文+程序源码+GUI图形用户界面)——变声算法

    大家好,今天给大家介绍基于matlab的语音信号变声处理系统设计与算法原理(论文+程序源码)。 运用matlab软件实现对声音的变声处理,利用离散付里叶变换进行频谱分析;设计数字滤波器组;通过时域和频域方法做出各种音效效果,实现变速(慢放、快放),变调(频谱左

    2024年02月04日
    浏览(62)
  • (微信小程序毕业设计)校园圈子小程序的设计与实现(附源码+论文)

    大家好!我是岛上程序猿,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:微信小程序毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 安卓app毕业设计 🌎Java毕业设计 目前各个高校基本都有各自的社区,但仍以传统的BBS、论坛等形式为主,移动互联网形式下,多以班级、社

    2024年02月08日
    浏览(48)
  • 澡堂洗澡预约小程序小程序系统设计与实现

    目的 :本课题主要目标是设计并能够实现一个基于微信小程序预约订座小程序,前台用户使用小程序,后台管理使用基PHP+MySql的B/S架构;通过后台添加浴室类型、浴室房间,用户通过小程序登录,查看浴室、提交浴室预约信息。 意义 :微信小程序预约订座小程序系统是计算

    2024年02月10日
    浏览(43)
  • 微信小程序毕业设计作品成品(03)在线投票小程序投票评选小程序系统设计与实现

    博主介绍 :《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程,免费 项目配有对应开发文档、开题报告、任务书、PPT、论文模版

    2024年02月08日
    浏览(46)
  • 微信小程序校园洗衣小程序系统设计与实现

     博主介绍 :黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程,免费 项目配有对应开发文档、开题报告、任务书、

    2024年02月04日
    浏览(48)
  • 微信小程序毕业设计作品成品(02)高校校园教室预约小程序系统设计与实现

    博主介绍 :《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程,免费 项目配有对应开发文档、开题报告、任务书、PPT、论文模版

    2024年02月08日
    浏览(39)
  • 微信小程序毕业设计作品成品(51)微信小程序手机商城系统设计与实现

    博主介绍: 《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程,免费 项目配有对应开发文档、开题报告、任务书、PPT、论文模版

    2024年02月08日
    浏览(69)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包