第十三章:位图(四)
更多关于尺寸
到目前为止,您已经看到了两种方法来调整Image元素的大小:
如果Image元素没有受到任何限制,它将在保持bit?map的宽高比的同时填充其容器,或者如果将Aspect属性设置为Fill或AspectFill,则完全填充该区域。
如果位图小于其容器的大小,并且通过将HorizontalOptions或VerticalOptions设置为Fill以外的其他内容来水平或垂直限制Image,或者如果将Image放入StackLayout,则位图将以其自然大小显示。这是iOS和Android设备上的像素大小,但是Windows设备上与设备无关的单元的大小。
您还可以通过将WidthRequest或HeightRequest设置为与设备无关的单位中的显式维度来控制大小。但是,有一些限制。
以下讨论基于StackedBitmap示例的实验。它属于垂直约束的Image元素,它们是垂直StackLayout的子级,或者VerticalOptions属性设置为Fill以外的其他属性。相同的原则适用于水平约束的Image元素。
如果Image元素是垂直约束的,则可以使用WidthRequest从其自然大小减小位图的大小,但不能使用它来增加大小。例如,尝试将WidthRequest设置为100:
<Image Source="{local:ImageResource StackedBitmap.Images.Sculpture_320x240.jpg}"
WidthRequest="100"
HorizontalOptions="Center"
BackgroundColor="Aqua"
SizeChanged="OnImageSizeChanged" />
位图的合成高度由指定的宽度和位图的宽高比决定,因此现在在所有三个平台上显示的图像大小为100×75个与设备无关的单位:
Center的HorizontalOptions设置不会影响渲染位图的大小。 如果删除该行,Image元素将与屏幕一样宽(水色背景颜色将演示),但位图将保持相同的大小。
您不能使用WidthRequest来增加渲染位图的大小超出其自然大小。 例如,尝试将WidthRequest设置为1000:
<Image Source="{local:ImageResource StackedBitmap.Images.Sculpture_320x240.jpg}"
WidthRequest="1000"
HorizontalOptions="Center"
BackgroundColor="Aqua"
SizeChanged="OnImageSizeChanged" />
即使将HorizontalOptions设置为Center,结果Image元素现在也比渲染位图宽,如背景颜色所示:
但位图本身以其自然大小显示。 垂直StackLayout有效地防止渲染位图的高度超过其自然高度。
要克服垂直StackLayout的约束,您需要设置HeightRequest。 怎么样?你还希望将HorizontalOptions保留为其默认值Fill。 否则,Hori?zontalOptions设置将阻止渲染的位图的宽度超过其自然大小。
与WidthRequest一样,您可以设置HeightRequest以减小渲染位?map的大小。 以下代码将HeightRequest设置为100个与设备无关的单元:
<Image Source="{local:ImageResource StackedBitmap.Images.Sculpture_320x240.jpg}"
HeightRequest="100"
BackgroundColor="Aqua"
SizeChanged="OnImageSizeChanged" />
另请注意,已删除HorizontalOptions设置。
渲染的位图现在是100个与设备无关的单位高,其宽度由as?pect比率控制。 Image元素本身延伸到StackLayout的两侧:
在这种特殊情况下,您可以将HorizontalOptions设置为Center而不更改渲染位图的大小。 然后Image元素将是位图的大小(133×100),并且aqua背景将消失。
将HeightRequest设置为大于位图自然高度的值时,将HorizontalOptions保留为其默认设置Fill非常重要,例如250:
<Image Source="{local:ImageResource StackedBitmap.Images.Sculpture_320x240.jpg}"
HeightRequest="250"
BackgroundColor="Aqua"
SizeChanged="OnImageSizeChanged" />
现在渲染的位图大于其自然大小:
但是,此技术具有内置危险,当您将HeightRequest设置为400时会显示该危险:
<Image Source="{local:ImageResource StackedBitmap.Images.Sculpture_320x240.jpg}"
HeightRequest="400"
BackgroundColor="Aqua"
SizeChanged="OnImageSizeChanged" />
这是发生的事情:Image元素确实获得了400个与设备无关的单元的高度。 但是,该Image元素中渲染位图的宽度受到屏幕宽度的限制,这意味着渲染位图的高度小于Image元素的高度:
在实际程序中,您可能没有设置BackgroundColor属性,而是空白屏幕的荒地将占据渲染位图顶部和底部的区域。
这意味着你不应该使用HeightRequest来控制真正的StackLayout中位图的大小,除非你编写的代码确保HeightRequest被限制为StackLayout的宽度乘以位图的高度与宽度的比率。
如果您知道要显示的位图的像素大小,一种简单的方法是将WidthRequest和HeightRequest设置为该大小:
<Image Source="{local:ImageResource StackedBitmap.Images.Sculpture_320x240.jpg}"
WidthRequest="320"
HeightRequest="240"
HorizontalOptions="Center"
BackgroundColor="Aqua"
SizeChanged="OnImageSizeChanged" />
现在,位图在所有平台上以与设备无关的单位显示为该大小:
这里的问题是位图没有以其最佳分辨率显示。取决于设备,位图的每个像素占据屏幕的至少两个像素。
如果要在垂直StackLayout中调整位图大小以使它们在各种设备上看起来大致相同,请使用WidthRequest而不是HeightRequest。您已经看到垂直StackLayout中的WidthRe?quest只能减小位图的大小。这意味着您应该使用大于它们渲染大小的位图。当图像在与设备无关的单元中调整大小时,这将为您提供更优化的分辨率。您可以使用所需的英制尺寸(以英寸为单位)以及特定设备的英寸设备无关单位数来确定位图的大小,我们发现这三个设备为160。
这是一个与StackedBitmap非常相似的项目,名为DeviceIndBitmapSize。它是相同的位图,但现在是1200×900像素,这比甚至高分辨率1920×1080显示器的纵向宽度宽。特定于平台的请求的位图宽度对应于1.5英寸:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DeviceIndBitmapSize"
x:Class="DeviceIndBitmapSize.DeviceIndBitmapSizePage">
<StackLayout>
<Label Text="1200 x 900 Pixel Bitmap"
FontSize="Medium"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />
<!-- 1.5 inch image width -->
<Image Source="{local:ImageResource DeviceIndBitmapSize.Images.Sculpture_1200x900.jpg}"
WidthRequest="240"
HorizontalOptions="Center"
SizeChanged="OnImageSizeChanged" />
</Image>
<Label x:Name="label"
FontSize="Medium"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Center" />
</StackLayout>
</ContentPage>
如果前面关于大小调整的分析是正确的并且一切顺利,那么这个位图应该在所有三个平台上看起来相对于屏幕宽度大致相同,并且提供比前一个程序更高的保真度分辨率:
有了关于调整位图大小的知识,现在可以制作一个带有图片的小型电子书阅读器,因为没有图片的书的使用是什么?
这本电子书阅读器显示了一个可滚动的StackLayout,其中包含Lewis Carroll的“爱丽丝梦游仙境”第7章的全文,其中包括John Tenniel的三张原始插图。 文本和插图是从阿德莱德大学的网站下载的。 插图作为MadTeaParty项目中的嵌入资源包含在内。 它们的名称和大小与网站上的名称和大小相同。 名称是指原书中的页码:
- image113.jpg — 709 × 553
- image122.jpg — 485 × 545
- image129.jpg — 670 × 596
回想一下,在StackLayout中使用WidthRequest for Image元素只能缩小渲染位图的大小。 这些位图的宽度不足以确保它们在所有三个平台上都缩小到合适的大小,但无论如何都值得检查结果,因为这更接近现实生活中的例子。
MadTeaParty程序使用Image的隐式样式将WidthRequest属性设置为对应于1.5英寸的值。 与前面的示例一样,此值为240。
对于用于这些屏幕截图的三个设备,此宽度对应于:
- iPhone 6上有480像素
- AndroidNexus 5上的720像素
- 运行Windows 10 Mobile的诺基亚Lumia 925上540像素
这意味着iPhone 6上的所有三个图像尺寸都会缩小,并且它们的渲染宽度均为240个与设备无关的单位。
但是,三个图像中没有一个会在Nexus 5上缩小尺寸,因为它们的像素宽度都比1.5英寸的像素数要窄。这三个图像在Nexus 5上将具有(分别)236,162和223个与设备无关的单元的渲染宽度。(这是像素宽度除以3)。
在Windows 10移动设备上,两个将缩小,一个不会缩小。
让我们看看预测是否正确。 XAML文件在根元素上包含BackgroundColor设置,该设置将整个页面着色为白色,这适用于书籍。样式定义仅限于StackLayout中的Resources字典。书名的样式基于定义的TitleStyle,但带有黑色文本和居中,Label和Image的两个隐式样式用于设置大多数Label元素和所有三个Image元素的样式。只有章节文本的第一段和最后一段显示在XAML文件的此列表中:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:MadTeaParty"
x:Class="MadTeaParty.MadTeaPartyPage"
BackgroundColor="White">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="5, 20, 5, 0"
Android="5, 0"
WinPhone="5, 0" />
</ContentPage.Padding>
<ScrollView>
<StackLayout Spacing="10">
<StackLayout.Resources>
<ResourceDictionary>
<Style x:Key="titleLabel"
TargetType="Label"
BaseResourceKey="TitleStyle">
<Setter Property="TextColor" Value="Black" />
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
<!-- Implicit styles -->
<Style TargetType="Label"
BaseResourceKey="BodyStyle">
<Setter Property="TextColor" Value="Black" />
</Style>
<Style TargetType="Image">
<Setter Property="WidthRequest" Value="240" />
</Style>
<!-- 1/4 inch indent for poetry -->
<Thickness x:Key="poemIndent">40, 0, 0, 0</Thickness>
</ResourceDictionary>
</StackLayout.Resources>
<!-- Text and images from http://ebooks.adelaide.edu.au/c/carroll/lewis/alice/ -->
<StackLayout Spacing="0">
<Label Text="Alice’s Adventures in Wonderland"
Style="{DynamicResource titleLabel}"
FontAttributes="Italic" />
<Label Text="by Lewis Carroll"
Style="{DynamicResource titleLabel}" />
</StackLayout>
<Label Style="{DynamicResource SubtitleStyle}"
TextColor="Black"
HorizontalTextAlignment="Center">
<Label.FormattedText>
<FormattedString>
<Span Text="Chapter VII" />
<Span Text="{x:Static sys:Environment.NewLine}" />
<Span Text="A Mad Tea-Party" />
</FormattedString>
</Label.FormattedText>
</Label>
<Label Text=
"There was a table set out under a tree in front of the
house, and the March Hare and the Hatter were having tea at
it: a Dormouse was sitting between them, fast asleep, and
the other two were using it as a cushion, resting their
elbows on it, and talking over its head. ‘Very uncomfortable
for the Dormouse,’ thought Alice; ‘only, as it’s asleep, I
suppose it doesn’t mind.’" />
__
__
<Label>
<Label.FormattedText>
<FormattedString>
<Span Text=
"Once more she found herself in the long hall, and close to
the little glass table. ‘Now, I’ll manage better this time,’
she said to herself, and began by taking the little golden
key, and unlocking the door that led into the garden. Then
she went to work nibbling at the mushroom (she had kept a
piece of it in her pocket) till she was about a foot high:
then she walked down the little passage: and " />
<Span Text="then" FontAttributes="Italic" />
<Span Text=
" — she found herself at last in the beautiful garden,
among the bright flower-beds and the cool fountains." />
</FormattedString>
</Label.FormattedText>
</Label>
</StackLayout>
</ScrollView>
</ContentPage>
三个Image元素只是引用三个嵌入的资源,并通过隐式样式给出WidthRequest属性的设置:
<Image Source="{local:ImageResource MadTeaParty.Images.image113.jpg}" />
__
<Image Source="{local:ImageResource MadTeaParty.Images.image122.jpg}" />
__
<Image Source="{local:ImageResource MadTeaParty.Images.image129.jpg}" />
这是第一张图片:
它在三个平台中相当一致,即使它在Nexus 5上以709像素的自然宽度显示,但这非常接近720像素,宽度为240个独立于设备的单位意味着。
第二张图片的差异要大得多:
它在Nexus 5上以像素大小显示,对应于162个与设备无关的单元,但在iPhone 6和诺基亚Lumia 925上显示宽度为240个单位。
虽然图片在任何平台上看起来都不差,但要让它们全部大小相同,则需要从较大的位图开始。