Xamarin.Forms 中的图像

Download Sample下载示例

可以通过 Xamarin.Forms 跨平台共享图像,可以针对每个平台专门加载图像,也可以下载它们以供显示。

图像是应用程序导航、可用性和品牌打造的关键组成部分。 Xamarin.Forms 应用程序需要能够跨所有平台共享图像,但也可能会在每个平台上显示不同的图像。

图标和初始屏幕也需要特定于平台的图像;需要按平台对它们进行配置。

显示图像

Xamarin.Forms 使用 Image 视图在页面上显示图像。 它具有几个重要的属性:

  • Source - ImageSource 实例,可以是文件、URI 或资源,用于设置要显示的图像。
  • Aspect - 如何在显示图像的边界内调整图像的大小(无论是拉伸、裁剪还是上下黑边)。

可以使用每种图像源的静态方法获取 ImageSource 实例:

  • FromFile - 需要可在每个平台上解析的文件名或文件路径。
  • FromUri - 需要 Uri 对象,例如 new Uri("http://server.com/image.jpg")
  • FromResource - 需要使用生成操作:EmbeddedResource 嵌入到应用程序或 .NET Standard 库项目中的图像文件的资源标识符。
  • FromStream - 需要提供图像数据的流。

Aspect 属性会确定图像的缩放方式以适应显示区域:

  • Fill - 拉伸图像,以完全、准确地填充显示区域。 这可能会导致图像失真。
  • AspectFill - 剪裁图像,使其填充显示区域,同时保持纵横比(即不失真)。
  • AspectFit - 根据需要对图像上下加框,以使整个图像适合显示区域,并根据图像的宽度或高度,将空白添加到顶部/底部或侧边。

可以从本地文件嵌入式资源下载,或从流加载图像。 此外,通过在 FontImageSource 对象中指定字体图标数据,Image 视图可以显示字体图标。 有关详细信息,请参阅“字体”指南中的“显示字体图标”。

本地图像

图像文件可以添加到每个应用程序项目中,并从 Xamarin.Forms 共享代码中进行引用。 当图像特定于平台时,例如在不同平台上使用不同分辨率或稍微不同的设计时,需要这种分发图像的方法。

要跨所有应用使用单个图像,必须在每个平台上使用相同的文件名,并且该名称应为有效的 Android 资源名称(即只允许使用小写字母、数字、下划线和句点)

  • iOS - 自 iOS 9 以来,管理和支持图像的首选方法是使用“资产目录图像集”,该图像应包含支持各种设备和应用程序缩放因子所需的所有图像版本。 有关详细信息,请参阅“将图像添加到资产目录图像集”。
  • Android - 使用生成操作:AndroidResource 将图像放置到 Resources/drawable 目录中。 还可以(在适当命名的 “Resources”子目录中,如 drawable-ldpidrawable-hdpidrawable-xhdpi)提供图像的高 DPI 和低 DPI 版本。
  • 通用 Windows 平台 (UWP) - 默认情况下,应使用生成操作:Content 将图像放置在应用程序的根目录中。 或者,可以将图像放置在另一个目录中,然后使用特定于平台的方式进行指定。 有关详细信息,请参阅 Windows 上的默认图像目录

重要

在 iOS 9 之前,通常会使用生成操作:BundleResource 将图像放置在 Resources 文件夹中。 但是,Apple 已弃用在 iOS 应用中处理图像的方法。 有关详细信息,请参阅“图像大小和文件名”。

遵循用于文件命名和放置的这些规则可让以下 XAML 在所有平台上加载和显示图像:

<Image Source="waterfront.jpg" />

等效的 C# 代码如下所示:

var image = new Image { Source = "waterfront.jpg" };

以下屏幕截图显示了在每个平台上显示本地图像的结果:

Sample application displaying a local image

为了提高灵活性,可以使用 Device.RuntimePlatform 属性为部分或所有平台选择不同的图像文件或路径,如以下代码示例所示:

image.Source = Device.RuntimePlatform == Device.Android
                ? ImageSource.FromFile("waterfront.jpg")
                : ImageSource.FromFile("Images/waterfront.jpg");

重要

若要在所有平台上使用相同的图像文件名,则名称必须在所有平台上有效。 Android 可绘制资源具有命名限制,仅允许使用小写字母、数字、下划线和句点,并且对于跨平台兼容性,必须在所有其他平台上也遵循此限制。 示例文件名 waterfront.png 遵循该规则,但无效文件名的示例包括“water front.png”、“WaterFront.png”、“water-front.png”和“wåterfront.png”。

本机分辨率(retina 和 high-DPI)

iOS、Android 和 UWP 包括对不同映像分辨率的支持,其中操作系统会根据设备的功能在运行时选择适当的图像。 Xamarin.Forms 使用本机平台的 API 加载本地图像,因此,如果文件已正确命名并位于项目中,它会自动支持备用分辨率。

自 iOS 9 以来,管理图像的首选方法是将每种分辨率所需的图像拖动到相应的资产目录图像集。 有关详细信息,请参阅“将图像添加到资产目录图像集”。

在 iOS 9 之前,图像的 retina 版本可以放置在 Resources 文件夹中,分辨率为 2 倍和 3 倍,文件扩展名前的后缀为 @2x@3x(例如)。(例如 myimage@2x.png)。 但是,Apple 已弃用在 iOS 应用中处理图像的方法。 有关详细信息,请参阅“图像大小和文件名”。

Android 备用分辨率图像应放置在 Android 项目中专门命名的目录中,如以下屏幕截图所示:

Android multiple-resolution image location

UWP 映像文件名可以在文件扩展名之前用 .scale-xxx 后缀,其中 xxx 是应用于资产的缩放百分比,例如 myimage.scale-200.png。 然后,可以在代码或 XAML 中引用图像,而无需缩放修饰符,例如只需 myimage.png。 平台将根据显示器的当前 DPI 选择最接近的相应资产比例。

显示图像的其他控件

某些控件具有显示图像的属性,例如:

  • Button 具有一个 ImageSource 属性,该属性可以设置为要显示在 Button 上的位图图像。 有关详细信息,请参阅“将位图与按钮一起使用”。

  • ImageButton 具有一个 Source 属性,该属性可以设置为要在 ImageButton 中显示的图像。 有关详细信息,请参阅“设置图像源”。

  • ToolbarItem 具有一个 IconImageSource 属性,该属性可以设置为从文件、嵌入式资源、URI 或流加载的图像。

  • ImageCell 具有一个 ImageSource 属性,该属性可以设置为从文件、嵌入式资源、URI 或流检索到的图像。

  • Page。 派生自 Page 的任何页面类型都有 IconImageSourceBackgroundImageSource 属性,这些属性可以分配文件、嵌入的资源、URI 或流。 在某些情况下(例如,当 NavigationPage 显示 ContentPage 时),如果平台支持,则会显示该图标。

    重要

    在 iOS 上,无法从资产目录图像集中的图像填充 Page.IconImageSource 属性。 而是会从文件、嵌入式资源、URI 或流加载 Page.IconImageSource 属性的图标图像。

嵌入图像

嵌入图像也随应用程序(如本地图像)一起提供,但不是在每个应用程序的文件结构中拥有图像副本,而是将图像文件作为资源嵌入到程序集中。 当在每个平台上使用相同的图像时,建议使用这种分发图像的方法,这种方法特别适合创建组件,因为图像与代码捆绑在一起。

若要在项目中嵌入图像,请右键单击以添加新项,然后选择要添加的图像。 默认情况下,图像将具有生成操作:None;需要将其设置为生成操作:EmbeddedResource

Set build action to embedded resource

可以在文件的“属性”窗口中查看和更改“生成操作”。

在此示例中,资源 ID 为 WorkingWithImages.beach.jpg。 IDE 使用每个值之间的句点 (.) 将此项目的“默认命名空间”与文件名连接,从而生成此默认值。

如果将嵌入图像放入项目中的文件夹,则文件夹名称也用资源 ID 中的句点 (.) 分隔。 将 beach.jpg 图像移动到名为 “myImages ”的文件夹将导致资源 ID 变为 WorkingWithImages.MyImages.beach.jpg

加载嵌入图像的代码只是将“资源 ID”传递给 ImageSource.FromResource 方法,如下所示:

Image embeddedImage = new Image
{
    Source = ImageSource.FromResource("WorkingWithImages.beach.jpg", typeof(MyClass).GetTypeInfo().Assembly)
};

注意

若要支持在通用 Windows 平台上以发布模式显示嵌入图像,必须使用指定要在其中搜索图像的源程序集的 ImageSource.FromResource 重载。

目前,资源标识符没有隐式转换。 相反,必须使用 ImageSource.FromResourcenew ResourceImageSource() 加载嵌入图像。

以下屏幕截图显示了在每个平台上显示嵌入图像的结果:

Sample application displaying an embedded image

XAML

由于没有从 stringResourceImageSource 的内置类型转换器,因此 XAML 无法从本机加载这些类型的图像。 相反,可以使用 XAML 中指定的“资源 ID”编写简单的自定义 XAML 标记扩展来加载图像:

[ContentProperty (nameof(Source))]
public class ImageResourceExtension : IMarkupExtension
{
 public string Source { get; set; }

 public object ProvideValue (IServiceProvider serviceProvider)
 {
   if (Source == null)
   {
     return null;
   }

   // Do your translation lookup here, using whatever method you require
   var imageSource = ImageSource.FromResource(Source, typeof(ImageResourceExtension).GetTypeInfo().Assembly);

   return imageSource;
 }
}

注意

若要支持在通用 Windows 平台上以发布模式显示嵌入图像,必须使用指定要在其中搜索图像的源程序集的 ImageSource.FromResource 重载。

若要使用此扩展,请使用项目的正确命名空间和程序集值将自定义 xmlns 添加到 XAML。 然后,可以使用以下语法设置图像源:{local:ImageResource WorkingWithImages.beach.jpg}。 下面显示了完整的 XAML 示例:

<?xml version="1.0" encoding="UTF-8" ?>
<ContentPage
   xmlns="http://xamarin.com/schemas/2014/forms"
   xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
   xmlns:local="clr-namespace:WorkingWithImages;assembly=WorkingWithImages"
   x:Class="WorkingWithImages.EmbeddedImagesXaml">
 <StackLayout VerticalOptions="Center" HorizontalOptions="Center">
   <!-- use a custom Markup Extension -->
   <Image Source="{local:ImageResource WorkingWithImages.beach.jpg}" />
 </StackLayout>
</ContentPage>

对嵌入图像进行故障排除

调试代码

由于有时很难理解为什么没有加载特定图像资源,因此可以将以下调试代码临时添加到应用程序中,以帮助确认资源配置正确。 它将把给定程序集中嵌入的所有已知资源输出到“控制台”,以帮助调试资源加载问题

using System.Reflection;
// ...
// NOTE: use for debugging, not in released app code!
var assembly = typeof(MyClass).GetTypeInfo().Assembly;
foreach (var res in assembly.GetManifestResourceNames())
{
    System.Diagnostics.Debug.WriteLine("found resource: " + res);
}

嵌入在其他项目中的图像

默认情况下,ImageSource.FromResource 方法仅查找与调用 ImageSource.FromResource 方法的代码相同的程序集中的图像。 使用上方调试代码,可以通过将 typeof() 语句更改为在每个程序集中已知的 Type 来确定哪些程序集包含特定资源。

但是,要搜索嵌入图像的源程序集可以作为参数指定给 ImageSource.FromResource 方法:

var imageSource = ImageSource.FromResource("filename.png",
            typeof(MyClass).GetTypeInfo().Assembly);

下载图像

如以下 XAML 所示,可自动下载图像以进行显示:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       x:Class="WorkingWithImages.DownloadImagesXaml">
  <StackLayout VerticalOptions="Center" HorizontalOptions="Center">
    <Label Text="Image UriSource Xaml" />
    <Image Source="https://aka.ms/campus.jpg" />
    <Label Text="campus.jpg gets downloaded from microsoft.com" />
  </StackLayout>
</ContentPage>

等效的 C# 代码如下所示:

var webImage = new Image {
     Source = ImageSource.FromUri(
        new Uri("https://aka.ms/campus.jpg")
     ) };

ImageSource.FromUri 方法需要一个 Uri 对象,并会返回从 Uri 读取的新 UriImageSource

URI 字符串也有隐式转换,因此以下示例也起作用:

webImage.Source = "https://aka.ms/campus.jpg";

以下屏幕截图显示了在每个平台上显示远程内容的结果:

Sample application displaying a downloaded image

下载的图像缓存

UriImageSource 还支持已下载图像的缓存,可通过以下属性进行配置:

  • CachingEnabled - 是否启用缓存(默认情况下为 true)。
  • CacheValidity - 定义将在本地存储图像的时长的 TimeSpan

默认情况下会启用缓存,并将图像存储在本地 24 小时。 若要禁用特定图像的缓存,请实例化图像源,如下所示:

image.Source = new UriImageSource { CachingEnabled = false, Uri = new Uri("https://server.com/image") };

若要设置特定的缓存周期(例如 5 天),请实例化图像源,如下所示:

webImage.Source = new UriImageSource
{
    Uri = new Uri("https://aka.ms/campus.jpg"),
    CachingEnabled = true,
    CacheValidity = new TimeSpan(5,0,0,0)
};

借助内置缓存,可以轻松支持滚动图片列表等场景,在这些场景中,你可以在每个单元格中设置(或绑定)图片,当单元格滚动到视图中时,让内置缓存重新加载图片。

动态 GIF

Xamarin.Forms 包括对显示小型动态 GIF 的支持。 这是通过将 Image.Source 属性设置为动画 GIF 文件来实现的:

<Image Source="demo.gif" />

重要

虽然 Xamarin.Forms 中的动态 GIF 支持包括下载文件的功能,但它不支持缓存或流式处理动态 GIF。

默认情况下,加载动画 GIF 时不会播放该 GIF。 这是因为,控制是播放还是停止动画 GIF 的 IsAnimationPlaying 属性的默认值为 falsebool 类型的此属性由 BindableProperty 对象提供支持,这意味着它可以是数据绑定的目标,并可以设置样式。

因此,在加载动画 GIF 时,只有将 IsAnimationPlaying 属性设置为 true 才能播放它。 然后,可以通过将 IsAnimationPlaying 属性设置为 false 来停止播放。 请注意,此属性在显示非 GIF 图像源时不起作用。

注意

在 Android 上,动态 GIF 支持要求应用程序使用快速呈现器,如果已选择使用旧呈现器,则不会起作用。 在 UWP 上,动态 GIF 支持需要最低版本的 Windows 10 周年更新(版本 1607)。

图标和初始屏幕

虽然与 Image 视图无关,但应用程序图标和初始屏幕也是 Xamarin.Forms 项目中图像的重要用途。

Xamarin.Forms 应用设置图标和初始屏幕是在每个应用程序项目中完成的。 这意味着为 iOS、Android 和 UWP 生成大小正确的图像。 应根据每个平台的要求命名和定位这些映像。

图标

有关创建这些应用程序资源的详细信息,请参阅 iOS 图像处理指南Google 图标设计指南,以及 UWP 磁贴和图标资产指南

此外,通过在 FontImageSource 对象中指定字体图标数据,Image 视图可以显示字体图标。 有关详细信息,请参阅“字体”指南中的“显示字体图标”。

初始屏幕

只有 iOS 和 UWP 应用程序需要初始屏幕(也称为启动屏幕或默认图像)。

请参阅 Windows 开发人员中心上有关 iOS 图像处理指南初始屏幕的文档。