第十三章:位图(三)

嵌入资源
通过Internet访问位图很方便,但有时候并不是最佳选择。该过程需要互联网连接,确保位图未被移动,并有一段时间下载。为了快速且有保证地访问位图,它们可以直接绑定到应用程序中。
如果需要访问非特定于平台的映像,则可以将位图作为嵌入资源包含在共享的可移植类库项目中,并使用ImageSource.From?Resource方法访问它们。 ResourceBitmapCode解决方案演示了如何执行此操作。
此解决方案中的ResourceBitmapCode PCL项目有一个名为Images的文件夹,它包含两个位图,名为ModernUserInterface.jpg(一个非常大的位图)和ModernUserInterface256.jpg(相同的图片,但宽度为256像素)。
将任何类型的嵌入资源添加到PCL项目时,请确保将资源的构建操作设置为EmbeddedResource。这很关键。
在代码中,将Image元素的Source属性设置为从静态ImageSource.FromResource方法返回的ImageSource对象。此方法需要资源ID。 resource ID包括程序集名称后跟句点,然后是文件夹名称后跟一个otherperiod,然后是文件名,其中包含文件扩展名的另一个句点。对于此示例,用于访问ResourceBitmapCode程序中两个位图中较小位图的资源ID为:
ResourceBitmapCode.Images.ModernUserInterface256.jpg
此程序中的代码引用较小的位图,并将Image元素上的HorizontalOptions和VerticalOptions设置为Center:

public class ResourceBitmapCodePage : ContentPage
{
    public ResourceBitmapCodePage()
    {
        Content = new Image
        {
            Source = ImageSource.FromResource(
                        "ResourceBitmapCode.Images.ModernUserInterface256.jpg"),
            VerticalOptions = LayoutOptions.Center,
            HorizontalOptions = LayoutOptions.Center
        };
    }
}

如您所见,此实例中的位图未展开以填充页面:
201808152121250377
如果符合以下情况,则不会拉伸位图以填充其容器:

  • 它小于容器,并且
  • 未设置Image元素的VerticalOptions和HorizontalOptions属性
    填充,或者如果Image是StackLayout的子级。

如果注释掉VerticalOptions和HorizontalOptions设置,或者引用大位图(文件名末尾没有“256”),图像将再次拉伸以填充容器。
如果未展开位图以适合其容器,则必须以特定大小显示该位图。那个大小是多少?
在iOS和Android上,位图以像素大小显示。换句话说,通过位图的像素和视频显示的像素之间的一对一映射来渲染位图。用于这些屏幕截图的iPhone 6模拟器的屏幕宽度为750像素,您可以看到位图的256像素宽度约为宽度的三分之一。这里的Android手机是Nexus 5,其像素宽度为1080,位图大约是宽度的四分之一。
但是,在Windows运行时平台上,位图显示在与设备无关的单元中 - 在此示例中,为256个与设备无关的单元。用于这些屏幕截图的诺基亚Lumia 925的像素宽度为768,与iPhone 6大致相同。但是,这款Windows 10 Mobile手机在独立于设备的设备中的屏幕宽度为341,您可以看到ren?dered位图比其他平台宽得多。
有关调整位图大小的讨论将在下一节继续讨论。
您如何引用从XAML存储为嵌入资源的位图?不幸的是,没有ResourceImageSource类。如果有,您可能会尝试在Image.Source标记之间在XAML中实例化该类。但那不是一个选择。
您可以考虑使用x:FactoryMethod来调用ImageSource.FromResource,但这不起作用。正如当前实现的那样,ImageSource.FromResource方法要求位图资源与调用该方法的代码位于同一程序集中。当您使用x:FactoryMethod调用ImageSource.FromResource时,将从Xamarin.Forms.Xaml程序集进行调用。
什么是有效的是一个非常简单的XAML标记扩展。这是一个名为StackedBitmap的项目中的一个:

namespace StackedBitmap
{
    [ContentProperty ("Source")]
    public class ImageResourceExtension : IMarkupExtension
    {
        public string Source { get; set; }
        public object ProvideValue (IServiceProvider serviceProvider)
        {
            if (Source == null)
                return null;
            return ImageSource.FromResource(Source); 
        }
    }
}

ImageResourceExtension有一个名为Source的属性,您可以将其设置为资源ID。 ProvideValue方法只使用Source属性调用ImageSource.FromResource。 对于单属性标记扩展常见,Source也是该类的content属性。 这意味着当您使用大括号语法进行XAML标记扩展时,您不需要显式包含“Source =”。
但请注意:您无法将此ImageResourceExtension类移动到诸如Xama?rin.FormsBook.Toolkit之类的库中。 该类必须是包含要加载的嵌入式源的同一程序集的一部分,通常是应用程序的可移植类库。
这是StackedBitmap项目中的XAML文件。 Image元素与StackLayout共享两个Label元素:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:StackedBitmap "
             x:Class="StackedBitmap.StackedBitmapPage">
 
    <StackLayout>
        <Label Text="320 x 240 Pixel Bitmap"
               FontSize="Medium"
               VerticalOptions="CenterAndExpand"
               HorizontalOptions="Center" />
 
        <Image Source="{local:ImageResource StackedBitmap.Images.Sculpture_320x240.jpg}"
               BackgroundColor="Aqua"
               SizeChanged="OnImageSizeChanged" />
        <Label x:Name="label"
               FontSize="Medium"
               VerticalOptions="CenterAndExpand"
               HorizontalOptions="Center" />
    </StackLayout>
</ContentPage>

本地前缀是指StackedBitmap程序集中的StackedBitmap命名空间。 Image元素的Source属性设置为ImageResource标记扩展,它引用存储在PCL项目的Images文件夹中的位图并标记为EmbeddedResource。 位图宽320像素,高240像素。 Image还设置了BackgroundColor属性; 这将允许我们在StackLayout中查看Image的整个大小。
Image元素的SizeChanged事件设置为代码隐藏文件中的处理程序:

public partial class StackedBitmapPage : ContentPage
{
    public StackedBitmapPage()
    {
        InitializeComponent();
    }
    void OnImageSizeChanged(object sender, EventArgs args)
    {
        Image image = (Image)sender;
        label.Text = String.Format("Render size = {0:F0} x {1:F0}", 
                                   image.Width, image.Height);
   }
}

Image元素的大小由StackLayout垂直约束,因此位图以其像素大小(在iOS和Android上)和在Windows Phone上与设备无关的单位显示。 Label以与设备无关的单位显示Image元素的大小,这些单元在每个平台上都有所不同:
201808152138020378
底部Label显示的Image元素的宽度包括aqua背景,并且等于设备无关单元中页面的宽度。 您可以使用Fill或As?pectFill的Aspect设置来使位图填充整个aqua区域。
如果您希望Image元素的大小与设备独立单元中的渲染位图大小相同,则可以将Image的HorizontalOptions属性设置为Fill的默认值以外的值:

<Image Source="{local:ImageResource StackedBitmap.Images.Sculpture_320x240.jpg}"
       HorizontalOptions="Center"
       BackgroundColor="Aqua"
       SizeChanged="OnImageSizeChanged" />

现在,底部Label仅显示渲染位图的宽度。 Aspect支架的设置无效:
201808152140330380
让我们将这个渲染的图像大小称为其自然大小,因为它基于正在显示的位图的大小。
iPhone 6的像素宽度为750像素,但正如您在第5章中运行WhatSize程序时发现的那样,应用程序感知屏幕宽度为375.设备有两个像素?独立单元,因此位图的宽度为显示320像素,宽度为160个单位。
Nexus 5的像素宽度为1080,但应用程序感知宽度为360,因此与设备无关的单元有三个像素,因为107个单元的图像宽度确认。
在iOS和Android设备上,当以自然大小显示位图时,位图的像素与显示器的像素之间存在一对一的映射。但是,在Windows运行时设备上,情况并非如此。用于这些屏幕截图的诺基亚Lumia 925的像素宽度为768.运行Windows 10 Mobile操作系统时,设备独立单元有2.25像素,因此应用程序感知屏幕宽度为341。但320× 240像素位图以320×240个与设备无关的单元的大小显示。
当您从各个平台项目访问位图时,Windows运行时和其他两个平台之间的这种不一致实际上是有益的。正如您将看到的,iOS和Android包含一项功能,可让您为不同的设备分辨率提供不同大小的位图。在效果上,这允许您在与设备无关的单元中指定位图大小,这意味着Windows设备与这些方案一致。
但是当使用与平台无关的位图时,您可能希望在所有三个平台上确定位图的大小,这需要更深入地了解主题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值