Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5026439
  • 博文数量: 891
  • 博客积分: 17977
  • 博客等级: 上将
  • 技术积分: 8636
  • 用 户 组: 普通用户
  • 注册时间: 2005-08-26 09:59
个人简介

一个好老好老的老程序员了。

文章分类

全部博文(891)

文章存档

2020年(8)

2019年(40)

2018年(88)

2017年(130)

2015年(5)

2014年(12)

2013年(41)

2012年(36)

2011年(272)

2010年(1)

2009年(53)

2008年(65)

2007年(47)

2006年(81)

2005年(12)

分类: Android平台

2019-11-06 10:58:05

响应方向变化
应用程序页面的布局通常与特定的外形和宽高比紧密相关。有时,应用程序将要求仅在纵向或横向模式下使用它。但是,当手机改变方向时,应用程序通常会尝试在屏幕上移动。
网格可以帮助应用程序适应方向更改。可以在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和所有交互式控件。这是自动高度:
这是纵向视图:
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处理程序:

点击(此处)折叠或打开

  1. public partial class GridRgbSlidersPage : ContentPage
  2. {
  3.     public GridRgbSlidersPage()
  4.     {
  5.         // Ensure link to Toolkit library.
  6.         new Xamarin.FormsBook.Toolkit.DoubleToIntConverter();
  7.         InitializeComponent();
  8.     }
  9.     void OnPageSizeChanged(object sender, EventArgs args)
  10.     {
  11.         // Portrait mode.
  12.         if (Width < Height)
  13.         {
  14.             mainGrid.RowDefinitions[1].Height = GridLength.Auto;
  15.             mainGrid.ColumnDefinitions[1].Width = new GridLength(0, GridUnitType.Absolute);
  16.             Grid.SetRow(controlPanelStack, 1);
  17.             Grid.SetColumn(controlPanelStack, 0);
  18.         }
  19.         // Landscape mode.
  20.         else
  21.         {
  22.             mainGrid.RowDefinitions[1].Height = new GridLength(0, GridUnitType.Absolute);
  23.             mainGrid.ColumnDefinitions[1].Width = new GridLength(1, GridUnitType.Star);
  24.             Grid.SetRow(controlPanelStack, 0);
  25.             Grid.SetColumn(controlPanelStack, 1);
  26.         }
  27.     }
  28.     void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
  29.     {
  30.         boxView.Color = new Color(redSlider.Value, greenSlider.Value, blueSlider.Value);
  31.     }
  32. }


这是横向展示的横向布局:
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类:

点击(此处)折叠或打开

  1. namespace Xamarin.FormsBook.Toolkit
  2. {
  3.     public class DoubleToIntConverter : IValueConverter
  4.     {
  5.         public object Convert(object value, Type targetType,
  6.  object parameter, CultureInfo culture)
  7.         {
  8.             string strParam = parameter as string;
  9.             double multiplier = 1;
  10.             if (!String.IsNullOrEmpty(strParam))
  11.             {
  12.                 Double.TryParse(strParam, out multiplier);
  13.             }
  14.             return (int)Math.Round((double)value * multiplier);
  15.         }
  16.         public object ConvertBack(object value, Type targetType,
  17.  object parameter, CultureInfo culture)
  18.         {
  19.             string strParam = parameter as string;
  20.             double divider = 1;
  21.             if (!String.IsNullOrEmpty(strParam))
  22.             {
  23.                 Double.TryParse(strParam, out divider);
  24.             }
  25.             return (int)value / divider;
  26.         }
  27.     }
  28. }
Convert和ConvertBack方法假定参数参数是一个字符串,如果是,则尝试将其转换为double。 然后将该值乘以转换的double值,然后将产品转换为int。
值转换器,转换器参数和字符串格式的组合将从Slider到0到1的值转换为0到255范围内的整数,然后将这些值格式化为两个十六进制数字:


点击(此处)折叠或打开

  1. <Label Text="{Binding Source={x:Reference redSlider},
  2.                       Path=Value,
  3.                       Converter={StaticResource doubleToInt},
  4.                       ConverterParameter=255,
  5.                       StringFormat='Red = {0:X2}'}" />
当然,如果您在代码中定义Binding,则可能将ConverterParameter属性设置为255的数值而不是字符串“255”,并且DoubleToIntConverter中的逻辑将失败。 简单的数值转换器通常比完全防弹更简单。
如果没有代码隐藏文件中的Slider事件处理程序,可以完全实现像GridRgbSliders这样的程序吗? 代码肯定仍然是必需的,但其中一些将被移离用户界面逻辑。 这是下一章探讨的Model-View-ViewModel架构的主要目标。


阅读(124) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~