MAUI新生6.2-布局类控件难点:FlexLayout、BindableLayout、StateContainer
一、FlexLayout弹性布局
1、FlexLayout弹性布局,和前端的Flex弹性布局,几乎一样。FlexLayout是容器,可以定义Direction/主轴方向、Wrap/子元素在主轴方向上是否换行/列、JustityContent/AlignItems/AlignContent子元素整体对齐方式。同时,在子元素上可以通过附加属性,定义子元素的个体行为,如Order,定义子元素排列顺序;Basis/Grow/Shrink,定义子元素主轴方向的尺寸形为;AlighSeft,定义子元素在交叉轴方向的对齐行为。
2、使用FlexLayout布局时的经验
- 确定子元素排列的主轴方向Direction,Row-由左至右水平排列(默认值),Column-由上至下垂直排列,或者RowReverse-由右至左水平排列、ColumnReverse-由下至上垂直排列
- 确定子元素在主轴方向上是否换行Wrap,NoWrap-不换行(默认值)、Wrap-换行、Reverse-反方向换行
- 确定子元素整体在主轴和交叉轴上的对齐方式,JustifyContent-主轴方向上的对齐方式、AlignItems-NoWap时交叉轴方向上的对齐方式、AlignContent-Wap时交叉轴方向上的对齐方式
- 确定子元素个体在主轴和交叉轴上的排列顺序、缩放和对齐行为,Order-排列顺序、Basis/Grow/Shrink-NoWap时主轴方向上的尺寸和缩放、AlignSeft-NoWap时交叉轴方向上的对齐
- 如下图所示:
3、使用FlexLayout完成圣杯布局
<ContentPage x:Class="MauiApp12.MainPage" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" BackgroundColor="{DynamicResource PageBackgroundColor}"> <!-- 外层FlexLayout,主轴为Column,自上而下垂直排列,分为三行,不换行 --> <!-- JustifyContent主轴-垂直方向的对齐方式为Start,AlignItems交叉轴-水平方向对齐方式为Stretch/自动扩展 --> <FlexLayout AlignItems="Stretch" Direction="Column" JustifyContent="Start" Wrap="NoWrap"> <Label BackgroundColor="Red" HorizontalTextAlignment="Center" Text="Header" /> <!--内层FlexLayout,作为外层FlexLayout的子元素,附加属性FlexLayout.Grow为1,在交叉轴-水平方向上填满剩余空间--> <!--内层FlexLayout,主轴方向为Row,自左向右水平排列,不换行--> <FlexLayout Direction="Row" FlexLayout.Grow="1" Wrap="NoWrap"> <!--内层FlexLayout的子元素,BoxView设置附加属性FlexLayout.Basis,主轴方向的基础尺寸为50--> <BoxView FlexLayout.Basis="50" Color="Yellow" /> <!--内层FlexLayout的子元素,Lable设置附加属性FlexLayout.Grow,主轴方向上扩展填满剩余空间--> <Label BackgroundColor="Green" FlexLayout.Grow="1" Text="Content" /> <BoxView FlexLayout.Basis="50" Color="Yellow" /> </FlexLayout> <Label BackgroundColor="Gray" HorizontalTextAlignment="Center" Text="Footer" /> </FlexLayout> </ContentPage>
二、绑定布局BindableLayout,以附加属性的形式,在宿主布局容器内,实现一个集合展示。实现的功能,与ListView或CollectionView类似,在条目数较少、无滚动、无选择按钮情况时,可以使用BindableLayout。
1、定义一个ViewModel,作为数据源
//直接New一个Employee集合 //ImageSource为Resources/Images目录下的图像 public partial class MainPageViewModel: ObservableObject { [ObservableProperty] private List<Employee> employees = new List<Employee> { new Employee{Name = "HeLiu",ImageSource="he_liu.png"}, new Employee{Name = "HaiShang",ImageSource="hai_shang.png"}, new Employee{Name = "LuoRi",ImageSource="luo_ri.png"}, new Employee{Name = "GongYuan",ImageSource="gong_yuan.png"}, }; }
2、使用BindableLayout
<ContentPage x:Class="MauiApp12.MainPage" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:vm="clr-namespace:MauiApp12.ViewModels"> <!--直接创建ViewModel对象,并设置为页面的BindingContext--> <ContentPage.BindingContext> <vm:MainPageViewModel /> </ContentPage.BindingContext> <!--BindableLayout.ItemsSource,数据源--> <!--BindableLayout.ItemTemplate,数据模板--> <!--BindableLayout.EmptyView,无数据时显示的文字提示--> <!--BindableLayout.EmptyView,还支持定义复杂的外观--> <!--BindableLayout.ItemTemplateSelector,相当于迭代中的if,详见数据模板的DataTemplateSelector--> <StackLayout BindableLayout.EmptyView="无数据" BindableLayout.ItemsSource="{Binding Employees}" Orientation="Horizontal"> <BindableLayout.ItemTemplate> <DataTemplate> <Image Aspect="AspectFill" HeightRequest="44" Source="{Binding ImageSource}" WidthRequest="44" /> </DataTemplate> </BindableLayout.ItemTemplate> <!--<BindableLayout.EmptyView> <Label Text="数据为空时显示的外观"/> </BindableLayout.EmptyView>--> </StackLayout> </ContentPage>
三、状态容器StateContainer,以附加属性的形式,在宿主布局容器内,根据不同的状态条件,显示不同的外观。
1、安装Nuget包,Community.Toolkit.Maui,并在入口文件MauiProgram.cs文件中设置【builder.UseMauiApp<App>().UseMauiCommunityToolkit()】
2、定义一个ViewModel,作为数据源
public partial class MainPageViewModel: ObservableObject { [ObservableProperty] private string myCurrentState; [RelayCommand] private void ChangeMyCurrentStateLoading() { MyCurrentState = "Loading"; } [RelayCommand] private void ChangeMyCurrentStateSuccess() { MyCurrentState = "Success"; } [RelayCommand] private void ChangeMyCurrentStateEmpty() { MyCurrentState = ""; } }
3、使用StateContainer
<ContentPage ...... xmlns:tk="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" xmlns:vm="clr-namespace:MauiApp12.ViewModels"> <!-- 直接创建ViewModel对象,并设置为页面的BindingContext --> <ContentPage.BindingContext> <vm:MainPageViewModel /> </ContentPage.BindingContext> <VerticalStackLayout> <!--tk:StateContainer.CurrentState的值和tk:StateView.StateKey匹配--> <VerticalStackLayout tk:StateContainer.CurrentState="{Binding MyCurrentState}"> <tk:StateContainer.StateViews> <!--tk:StateContainer.CurrentState的值为Loading时,显示如下内容--> <VerticalStackLayout tk:StateView.StateKey="Loading"> <ActivityIndicator IsRunning="True" /> <Label Text="加载中..." /> </VerticalStackLayout> <!--tk:StateContainer.CurrentState的值为Success时,显示如下内容--> <Label tk:StateView.StateKey="Success" Text="Success!" /> </tk:StateContainer.StateViews> <!--tk:StateContainer.CurrentState的值为Null或空字符串时默认显示的内容--> <Label Text="默认内容" /> </VerticalStackLayout>
<!--按钮更改MyCurrentState值--> <Button Command="{Binding ChangeMyCurrentStateLoadingCommand}" Text="Loading" /> <Button Command="{Binding ChangeMyCurrentStateSuccessCommand}" Text="Success" /> <Button Command="{Binding ChangeMyCurrentStateEmptyCommand}" Text="Empty" /> </VerticalStackLayout> </ContentPage>