第五章:尺寸处理(1)

您已经看到了与各种视觉元素相关的尺寸参考:

iOS状态栏的高度为20,您可以使用页面上的填充设置进行调整。
BoxView将其默认宽度和高度设置为40。
框架中的默认填充为20。
StackLayout上的默认Spacing属性为6。

然后是Device.GetNamedSize,它为NamedSize枚举的各种成员返回一个适用于Label或Button的FontSize值的平台相关编号。
这些数字是什么?他们的单位是什么?我们如何智能地将需要大小的属性设置为其他值?
好问题。如您所见,各种平台具有不同的屏幕尺寸和不同的文本大小,并且都在屏幕上显示不同数量的文本。这是Xamarin.Forms应用程序可以预见或控制的文本数量吗?即使有可能,这是一个合适的编程习惯吗?应用程序是否应调整字体大小以在屏幕上获得所需的文本密度?
通常,在编写Xamarin.Forms应用程序时,最好不要太靠近可视对象的实际数字维度。最好相信Xamarin.Forms和各个平台来做出最好的默认选择。
但是,有时候程序员需要知道特定视觉对象的大小以及它们出现的屏幕大小。
像素,点,dps, DIPs和DIUs
视频显示由矩形的像素阵列组成。 屏幕上显示的任何对象也具有像素大小。 在个人电脑的早期,程序员以像素为单位调整和定位视觉对象。 但随着屏幕尺寸和像素密度越来越多,使用像素对于尝试编写在许多设备上大致相同的应用程序的程序员而言变得不可取。 需要另一个解决方案。
这些解决方案始于桌面计算机的操作系统,然后适用于移动设备。 出于这个原因,用桌面开始这种探索是很有启发性的。
桌面视频显示器具有广泛的像素尺寸,从近乎过时的640×480到成千上万。 4:3的宽高比曾经是电脑显示器的标准配置,也是电影和电视的标准配置,但16:9(或类似16:10)的高清宽高比现在更为普遍。
桌面视频显示器的物理尺寸通常以英寸或厘米为单位,沿屏幕对角线测量。像素尺寸与物理尺寸的组合允许您以每英寸点数(DPI)计算视频显示器的分辨率或像素密度,有时也称为每英寸像素数(PPI)。显示分辨率也可以测量为点距,这是相邻像素中心之间的距离,通常以毫米为单位进行测量。
例如,您可以使用毕达哥拉斯定理来计算古老的800×600显示器的对角线长度为1,000,800平方的平方根加600平方。如果此显示器的对角线为13英寸,则像素密度为77 DPI,或点距为0.33毫米。但是,现代笔记本电脑上的13英寸屏幕可能具有2560×1600的像素尺寸,其像素密度约为230 DPI,或者点间距约为0.11毫米。此屏幕上的100像素正方形对象的大小与旧屏幕上同一对象的大小相同。
程序员在尝试正确确定视觉元素的大小时应该有战斗机会。出于这个原因,苹果和微软都设计了桌面计算系统,允许程序员以某种形式的独立于设备的单元而不是像素来处理视频显示。程序员遇到和指定的大部分维度都在这些与设备无关的单元中。操作系统有责任在这些单元和像素之间来回转换。
在Apple世界中,桌面视频显示器传统上被认为具有72英寸的分辨率。这个数字来自印刷术,许多测量都是以点为单位。在古典印刷术中,英寸约有72点,但在数字印刷术中,该点已标准化为一英寸的七十二分之一。通过使用点而不是像素,程序员可以直观地了解数字大小与可视对象在屏幕上占据的区域之间的关系。
在Windows世界中,开发了一种类似的技术,称为设备无关像素(DIP)或设备无关单元(DIU)。对于Windows程序员来说,桌面视频显示器的分辨率假定为96个DIU,虽然可以由用户进行调整,但其分辨率仍然高于72 DPI的三分之一。
然而,移动设备的规则有所不同:现代手机所达到的像素密度通常比桌面显示器高得多。这种更高的像素密度允许文本和其他视觉对象在变得难以辨认之前缩小得多。
与台式机或笔记本电脑屏幕相比,电话通常也更贴近用户的脸部。这种差异还意味着手机上的可视对象可能比桌面或笔记本电脑屏幕上的可比对象更小。由于手机的外形尺寸比桌面显示器小得多,因此缩小视觉对象是非常理想的,因为它允许更多地适合屏幕。
Apple继续将iPhone上的设备无关单元称为点。直到最近,苹果所有的高密度显示器(Apple称之为Retina)都有两个像素点的转换。对于MacBook Pro,iPad和iPhone来说也是如此。最近的例外是iPhone 6 Plus,它有三个像素点。
例如,iPhone 4的3.5英寸屏幕的640×960像素尺寸具有约320DPI的实际像素密度。有两个像素点,所以对于在iPhone 4上运行的应用程序,屏幕显示尺寸为320×480点。 iPhone 3实际上的像素尺寸为320×480,点数等于像素,因此对于在这两个设备上运行的程序,iPhone 3和iPhone 4的显示器看起来大小相同。尽管尺寸相同,但图形对象和文本在iPhone 4上的显示分辨率要高于
iPhone 3。
对于iPhone 3和iPhone 4,屏幕尺寸和点尺寸之间的关系意味着转换因子为英寸160点,而不是桌面标准72。
iPhone 5拥有4英寸屏幕,但像素尺寸为640×1136.像素密度与iPhone 4大致相同。对于程序,此屏幕的尺寸为320×768点。
iPhone 6拥有4.7英寸的屏幕和750×1334的像素尺寸。像素密度也约为320 DPI。有两个像素的点,所以对于一个程序,屏幕似乎有一个375×667的点大小。
但是,iPhone 6 Plus具有5.5英寸的屏幕,像素尺寸为1080×1920,其像素密度为400 DPI。这个更高的像素密度意味着更多的像素点,对于iPhone 6 Plus,Apple已经设定了等于三个像素的点。这通常意味着屏幕尺寸为360×640点,但对于程序而言,iPhone 6 Plus屏幕的点大小为414×736,因此感知分辨率约为150英寸。
下表总结了这些信息:
第五章:尺寸处理(1)

Android做了一些非常类似的事情:Android设备具有各种尺寸和像素尺寸,但Android程序员通常以密度无关像素(dps)为单位工作。像素和Dps之间的关系假定为160英寸英寸,这意味着Apple和Android设备无关单位非常相似。
微软采取了与Windows Phone 7不同的方法。原始的Windows Phone 7设备具有480×800像素的屏幕尺寸,其通常被称为WVGA(宽视频图形阵列)。应用程序以像素为单位处理此显示。如果您假设480×800 Windows Phone 7设备的平均屏幕尺寸为4英寸,这意味着Windows Phone 7隐含地假定像素密度约为240 DPI。这是iPhone和Android设备的假设像素密度的1.5倍。最终,允许使用几种较大的屏幕尺寸:768×1280(WXGA或宽幅扩展图形阵列),720×1280(以高清电视术语表示为720p)和1080×1920(称为1080p)。对于这些额外的显示尺寸,程序员在独立于设备的单元中工作。在像素和设备无关单元之间转换的内部比例因子,因此纵向模式下屏幕的宽度始终显示为480像素。
使用Windows Phone 8.1中的Windows Runtime API,基于屏幕的像素大小和屏幕的物理大小引入了不同的缩放因子。下面的表格基于Windows Phone 8.1仿真器使用一个名为WhatSize的程序放在一起,您将很快看到:
第五章:尺寸处理(1)

缩放因子是根据宽度计算的,因为WhatSize程序显示的DIU中的高度不包括Windows Phone状态栏。 最终的DPI数字是根据全像素大小,屏幕对角线大小(英寸)和比例因子计算得出的。
除WVGA异常值外,计算出的DPI已经足够接近与iOS和Android设备相关的160 DPI标准。
Windows 10 Mobile使用稍高的缩放因子,并且以0.25的倍数而不是0.2。 下表根据Windows 10 Mobile仿真器放在一起:
第五章:尺寸处理(1)

您可能会得出这样的结论:Windows 10 Mobile的平均DPI平均值为144(四舍五入到最接近的16的倍数)而不是160.或者您可以说它足够接近160以便认为它与iOS和Windows Phone一致。
Xamarin.Forms具有尽可能多地使用底层平台约定的理念。 按照这个理念,Xamarin.Forms程序员可以处理每个特定平台定义的大小。 程序员通过Xamarin.Forms API遇到的所有尺寸都在这些平台特定的,独立于设备的单元中。
Xamarin.Forms程序员通常可以以独立于设备的方式处理手机显示屏,并具有以下分辨率:

每英寸160单位
每厘米64个单位

VisualElement类定义了两个名为Width和Height的属性,它们提供了这些设备无关单元中视图,布局和页面的渲染尺寸。但是,宽度和高度的初始设置是“模拟”值-1。这些属性的值只有在布局系统在页面上定位和调整所有内容时才有效。另外,请记住,HorizontalOptions或VerticalOptions的默认填充设置通常会导致视图占用更多的空间。宽度和高度值反映了这个额外的空间。 “宽度”和“高度”值还包括可以在元素上设置的任何填充,并且与视图的BackgroundColor属性着色的区域一致。
VisualElement定义了一个名为SizeChanged的事件,每当Width或
视觉元素的高度属性发生变化。此事件是页面布局时发生的几个通知的一部分,这是一个涉及页面各种元素大小和位置的过程。此布局过程发生在页面的第一个定义(通常在页面构造函数中)之后,并且响应于可能影响布局的任何更改而发生新的布局传递 - 例如,视图添加到ContentPage或StackLayout时,从这些对象中移除,或者在视觉元素上设置可能导致其尺寸变化的属性。
当屏幕尺寸改变时,新的布局也会触发。这主要发生在手机在纵向和横向模式之间旋转时。
对Xamarin.Forms布局系统的完全熟悉通常伴随着编写自己的Layout 派生物的工作。此任务在第26章“自定义布局”中等待我们。在此之前,只需知道“宽度”和“高度”属性的更改对于处理可视对象的大小有帮助。您可以将一个SizeChanged处理程序附加到页面上的任何可视对象,包括页面本身。 WhatSize程序演示如何获取页面大小并显示它:

点击(此处)折叠或打开

public class WhatSizePage : ContentPage
{
    Label label;
    public WhatSizePage()
    {
        label = new Label
        {
            FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center
        };
        Content = label;
        SizeChanged += OnPageSizeChanged;
    }
    void OnPageSizeChanged(object sender, EventArgs args)
    {
        label.Text = String.Format("{0} \u00D7 {1}", Width, Height);
    }
}

这是本书中事件处理的第一个例子,您可以看到事件是以正常的C#和.NET方式处理的。构造函数末尾的代码将OnPageSizeChanged事件处理程序附加到页面的SizeChanged事件。事件处理程序(通常命名为sender)的第一个参数是引发事件的对象,在这种情况下是WhatSizePage的实例,但事件处理程序不使用它。事件处理程序也不使用第二个参数 - 所谓的事件参数 - 有时会提供有关该事件的更多信息。
相反,事件处理程序访问Label元素(方便地保存为字段)以显示页面的Width和Height属性。 String.Format调用中的Unicode字符是一个times(×)符号。
SizeChanged事件不是获得元素大小的唯一机会。 VisualElement还定义了一个名为OnSizeAllocated的受保护虚拟方法,用于指示何时为可视元素分配了大小。您可以在ContentPage派生中重写此方法,而不是处理SizeChanged事件,但有时在大小实际未更改时调用OnSizeAllocated。
这是在三个标准平台上运行的程序:
第五章:尺寸处理(1)

为了记录,这些是这三个图像中屏幕的来源:

iPhone 6模拟器,像素尺寸为750×1334。
LG Nexus 5,屏幕尺寸为1080×1920像素。
诺基亚Lumia 925,屏幕尺寸为768×1280像素。

请注意,Android上程序感知的垂直尺寸不包括状态栏或底部按钮占用的区域; Windows 10 Mobile设备的垂直尺寸不包括状态栏占用的区域。
默认情况下,所有三个平台都会响应设备方向更改。 如果逆时针旋转手机(或仿真器)90度,手机将显示以下尺寸:
第五章:尺寸处理(1)

本书的屏幕截图仅为肖像模式而设计,因此您需要横向翻阅本书,以了解该程序在横向上的效果。 Android上的598像素宽度排除了按钮的区域; 335像素的高度不包括状态栏,该状态栏始终显示在页面上方。 在Windows 10 Mobile设备上,728像素宽度不包括状态栏的区域,该区域显示在相同的位置,但带有旋转的图标以反映新的方向。
这是iPad Air 2模拟器上运行的程序,像素尺寸为2048×1536。
第五章:尺寸处理(1)

显然,缩放因子是2.屏幕对角线为9.7英寸,分辨率为132 DPI。
Surface Pro 3的像素尺寸为2160×1440.缩放系数可由用户选择以使屏幕上的所有内容变大或变小,但推荐的缩放系数为1.5:
第五章:尺寸处理(1)

WhatSize显示的高度不包括屏幕底部的任务栏。 屏幕对角线为12“,分辨率为144 DPI。
有关WhatSize程序本身的一些注意事项:
WhatSize在其构造函数中创建一个Label并在事件处理函数中设置Text属性。这不是写这样一个程序的唯一方法。该程序可以使用SizeChanged处理程序来创建一个全新的Label,并将新的Label设置为页面的内容,在这种情况下,以前的Label将变为未引用并因此有资格进行垃圾回收。但是在这个程序中创造新的视觉元素是不必要和浪费的。这是最好的方案
只创建一个Label视图,只需设置Text属性以指示页面的新大小。
监控尺寸变化是Xamarin.Forms应用程序可以检测方向变化而不需要获取平台特定信息的唯一方式。宽度是否大于高度?那是风景。否则,它是肖像。
默认情况下,Xamarin.Forms解决方案的Visual Studio和Xamarin Studio模板支持所有三个平台的设备方向更改。如果您想禁用方向更改 - 例如,如果您的应用程序在纵向或横向模式下效果不佳,则可以这样做。
对于iOS,首先在Visual Studio或Xamarin Studio中显示Info.plist的内容。在“iPhone部署信息”部分中,使用“支持的设备方向”区域指定允许的方向。
对于Android,在MainActivity.cs文件的MainActivity类的Activity属性中,添加:

点击(此处)折叠或打开

ScreenOrientation = ScreenOrientation.Landscape

或者

点击(此处)折叠或打开

ScreenOrientation = ScreenOrientation.Portrait

由解决方案模板生成的Activity属性包含一个ConfigurationChanges参数,该参数也指向屏幕方向,但ConfigurationChanges的用途是禁止在手机方向或屏幕大小更改时重新启动活动。
对于两个Windows Phone项目,要使用的类和枚举位于Windows -.Graphics.Display命名空间中。 在MainPage.xaml.cs文件的MainPage构造函数中,将静态DisplayInformation.AutoRotationPreferences属性设置为DisplayOrientations枚举的一个或多个成员,并将其与C#按位或运算结合使用。 要将程序限制为横向或纵向,请使用:

点击(此处)折叠或打开

DisplayInformation.AutoRotationPreferences = DisplayOrientations.Landscape

或者

点击(此处)折叠或打开

DisplayInformation.AutoRotationPreferences = DisplayOrientations.Portrait;
上一篇:第五章:尺寸处理(4)


下一篇:MapXtreme 2005 学习心得 道路区域选择(十三)