第十七章:掌握网格(七)

简介:

响应方向变化
应用程序页面的布局通常与特定的外形和宽高比紧密相关。有时,应用程序将要求仅在纵向或横向模式下使用它。但是,当手机改变方向时,应用程序通常会尝试在屏幕上移动。
网格可以帮助应用程序适应方向更改。可以在XAML中定义网格,对纵向和横向模式都有一定的限制,然后一些代码可以在页面的SizeChanged处理程序中进行适当的调整。
如果您可以将应用程序的整个布局划分为两个大区域,当手机以纵向模式定向或水平定向为横向模式时,此作业最简单。将这些区域中的每一个放在网格的单独单元格中。当手机处于纵向模式时,网格有两行,当它处于横向模式时,它有两列。在下图中,第一个区域始终位于顶部或左侧。第二个区域可以是纵向模式的第二行,也可以是横向模式的第二列:
2018_10_07_151504
为了使事情变得相当简单,您需要在XAML中定义具有两行和两列的网格,但在纵向模式下,第二列的宽度为零,而在横向模式下,第二行的高度为零。
GridRgbSliders程序演示了这种技术。它类似于第15章“交互式界面”中的RgbSliders程序,除了布局使用Grid和StackLayout的组合,而Label元素通过使用带有值的数据绑定来显示Slider元素的当前值转换器和值转换器参数。 (稍后会详细介绍。)基于三个Slider元素设置BoxView的Color属性仍然需要代码,因为Color结构的R,G和B属性不受可绑定属性的支持,并且这些属性不能单独更改无论如何,因为他们没有公共集访问器。 (但是,在下一章中,在MVVM上,您将看到一种在代码隐藏文件中消除此逻辑的方法。)
正如您在下面的清单中所看到的,名为mainGrid的Grid确实有两行和两列。但是,它已初始化为纵向模式,因此第二列的宽度为零。 Grid的顶行包含BoxView,使用“*”(星号)设置尽可能大,而底行包含StackLayout和所有交互式控件。这是自动高度:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit=
                 "clr-namespace:Xamarin.FormsBook.Toolkit;assembly=Xamarin.FormsBook.Toolkit"
             x:Class="GridRgbSliders.GridRgbSlidersPage"
             SizeChanged="OnPageSizeChanged">
 
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness"
                    iOS="0, 20, 0, 0" />
    </ContentPage.Padding>
    <ContentPage.Resources>
        <ResourceDictionary>
            <toolkit:DoubleToIntConverter x:Key="doubleToInt" />
            <Style TargetType="Label">
                <Setter Property="HorizontalTextAlignment" Value="Center" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>
    <Grid x:Name="mainGrid">
        <!-- Initialized for portrait mode. -->
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="0" />
        </Grid.ColumnDefinitions>
        <BoxView x:Name="boxView"
                 Grid.Row="0" Grid.Column="0" />
        <StackLayout x:Name="controlPanelStack"
                     Grid.Row="1" Grid.Column="0"
                     Padding="10, 5">
 
            <StackLayout VerticalOptions="CenterAndExpand">
                <Slider x:Name="redSlider"
                        ValueChanged="OnSliderValueChanged" />
                <Label Text="{Binding Source={x:Reference redSlider},
                                      Path=Value,
                                      Converter={StaticResource doubleToInt},
                                      ConverterParameter=255,
                                      StringFormat='Red = {0:X2}'}" />
            </StackLayout>
            <StackLayout VerticalOptions="CenterAndExpand">
                <Slider x:Name="greenSlider"
                        ValueChanged="OnSliderValueChanged" />
                <Label Text="{Binding Source={x:Reference greenSlider},
                                      Path=Value,
                                      Converter={StaticResource doubleToInt},
                                      ConverterParameter=255,
                                      StringFormat='Green = {0:X2}'}" />
            </StackLayout>
 
            <StackLayout VerticalOptions="CenterAndExpand">
                <Slider x:Name="blueSlider"
                        ValueChanged="OnSliderValueChanged" />
                <Label Text="{Binding Source={x:Reference blueSlider},
                                      Path=Value,
                                      Converter={StaticResource doubleToInt},
                                      ConverterParameter=255,
                                      StringFormat='Blue = {0:X2}'}" />
            </StackLayout>
        </StackLayout>
    </Grid>
</ContentPage>
AI 代码解读

这是纵向视图:
2018_10_07_152401
XAML文件中的布局以两种方式为横向模式准备。首先,Grid已经有了第二列。这意味着要切换到横向模式,代码隐藏文件需要将第二行的高度更改为零,将第二列的宽度更改为非零值。
其次,包含所有Slider和Label元素的StackLayout可以从代码访问,因为它有一个名称,特别是controlPanelStack。然后,代码隐藏文件可以对此StackLayout进行Grid.SetRow和Grid.SetColumn调用,以将其从第1行和第0列移动到第0行和第1列。
在纵向模式下,BoxView的高度为“”(星号),StackLayout的高度为“自动”。这是否意味着StackLayout的宽度在横向模式下应该是Auto?这不是明智之举,因为它会缩小Slider元素的宽度。横向模式的一个更好的解决方案是给BoxView和StackLayout宽度为“”(星号),将屏幕分成两半。
这是代码隐藏文件,显示负责在纵向和横向模式之间切换的页面上的SizeChanged处理程序,以及设置BoxView颜色的Slider元素的ValueChanged处理程序:

public partial class GridRgbSlidersPage : ContentPage
{
    public GridRgbSlidersPage()
    {
        // Ensure link to Toolkit library.
        new Xamarin.FormsBook.Toolkit.DoubleToIntConverter();
        InitializeComponent();
    }
    void OnPageSizeChanged(object sender, EventArgs args)
    {
        // Portrait mode.
        if (Width < Height)
        {
            mainGrid.RowDefinitions[1].Height = GridLength.Auto;
            mainGrid.ColumnDefinitions[1].Width = new GridLength(0, GridUnitType.Absolute);
            Grid.SetRow(controlPanelStack, 1);
            Grid.SetColumn(controlPanelStack, 0);
        }
        // Landscape mode.
        else
        {
            mainGrid.RowDefinitions[1].Height = new GridLength(0, GridUnitType.Absolute);
            mainGrid.ColumnDefinitions[1].Width = new GridLength(1, GridUnitType.Star);
            Grid.SetRow(controlPanelStack, 0);
            Grid.SetColumn(controlPanelStack, 1);
        }
    }
    void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
    {
        boxView.Color = new Color(redSlider.Value, greenSlider.Value, blueSlider.Value);
    }
}
AI 代码解读

这是横向展示的横向布局:
2018_10_07_153450
请注意,特别是在iOS和Android显示器上,每对Slider和Label元素如何组合在一起。这是第三种方式,即XAML文件准备好适应横向模式。每对Slider和Label元素都嵌套在一个嵌套的StackLayout中。这将给出CenterAndExpand的VerticalOptions设置以执行此间距。
稍微考虑安排BoxView和控制面板:在纵向模式下,操纵Slider元素的手指不会遮挡BoxView中的结果,而在横向模式下,惯用右手的用户的手指不会模糊BoxView也是。 (当然,左撇子用户可能会坚持使用程序选项来交换位置!)
屏幕截图显示了以十六进制显示的Slider值。这是通过数据绑定完成的,这通常是个问题。 Slider的Value属性是double类型,如果您尝试使用“X2”格式化十六进制的double,则会引发异常。类型转换器(例如,名为DoubleToIntConverter)必须将源double转换为int以进行字符串格式化。但是,Slider元素的设置范围为0到1,而格式为十六进制的整数值的范围必须介于0到255之间。
解决方案是使用Binding的ConverterParameter属性。设置为此属性的任何内容都作为第三个参数传递给值转换器中的Convert和ConvertBack方法。这是Xamarin.FormsBook.Toolkit库中的DoubleToIntConverter类:

namespace Xamarin.FormsBook.Toolkit
{
    public class DoubleToIntConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, 
 object parameter, CultureInfo culture)
        {
            string strParam = parameter as string;
            double multiplier = 1;
            if (!String.IsNullOrEmpty(strParam))
            {
                Double.TryParse(strParam, out multiplier);
            }
            return (int)Math.Round((double)value * multiplier);
        }
        public object ConvertBack(object value, Type targetType, 
 object parameter, CultureInfo culture)
        {
            string strParam = parameter as string;
            double divider = 1;
            if (!String.IsNullOrEmpty(strParam))
            {
                Double.TryParse(strParam, out divider);
            }
            return (int)value / divider;
        }
    }
} 
AI 代码解读

Convert和ConvertBack方法假定参数参数是一个字符串,如果是,则尝试将其转换为double。 然后将该值乘以转换的double值,然后将产品转换为int。
值转换器,转换器参数和字符串格式的组合将从Slider到0到1的值转换为0到255范围内的整数,然后将这些值格式化为两个十六进制数字:

<Label Text="{Binding Source={x:Reference redSlider},
                      Path=Value,
                      Converter={StaticResource doubleToInt},
                      ConverterParameter=255,
                      StringFormat='Red = {0:X2}'}" />
AI 代码解读

当然,如果您在代码中定义Binding,则可能将ConverterParameter属性设置为255的数值而不是字符串“255”,并且DoubleToIntConverter中的逻辑将失败。 简单的数值转换器通常比完全防弹更简单。
如果没有代码隐藏文件中的Slider事件处理程序,可以完全实现像GridRgbSliders这样的程序吗? 代码肯定仍然是必需的,但其中一些将被移离用户界面逻辑。 这是下一章探讨的Model-View-ViewModel架构的主要目标。

目录
打赏
0
0
0
0
1221
分享
相关文章
C# | 凸包算法之Andrew‘s,获取围绕一组点的凸多边形的轮廓点
这篇关于凸包算法的文章,本文使用C#和Andrew’s算法来实现凸包算法。 首先消除两个最基本的问题: 什么是凸包呢? 凸包是一个包围一组点的凸多边形。凸多边形是指多边形中的每个内角都小于180度的多边形。 凸包算法有什么用呢? 凸包算法的作用是找到这个凸多边形,并且使用最少的点来绘制出它的轮廓。凸包算法在计算机图形学、计算几何和机器学习等领域中有着广泛的应用。
240 0
|
11月前
|
Python实现教程:平面最短路径算法
Python实现教程:平面最短路径算法
140 1
C# | 凸包算法之Jarvis,寻找一组点的边界/轮廓
这篇关于凸包算法的文章,本文使用C#和Jarvis算法来实现凸包算法。 首先消除两个最基本的问题: 什么是凸包呢? 凸包是一个包围一组点的凸多边形。凸多边形是指多边形中的每个内角都小于180度的多边形。 凸包算法有什么用呢? 凸包算法的作用是找到这个凸多边形,并且使用最少的点来绘制出它的轮廓。凸包算法在计算机图形学、计算几何和机器学习等领域中有着广泛的应用。
111 0
技术分享 | ANSYS高级几何处理与网格应用技巧
Space Claim、排油烟机几何处理、流体域抽取;ANSYS Meshing、实际案例网格划分
技术分享 | ANSYS高级几何处理与网格应用技巧