我正在使用PCL(而非共享项目)开发Xamarin.Forms项目。
我在Android和iOS项目的资源文件夹中都有一些图像。
这是有效的,图标显示在按钮中,因为它们应该:
<Button Image="speaker.png" Grid.Row="0" Grid.Column="0" />
我的PCL项目中还有一个包含一些图像的文件夹: images / icons / speaker.png 我试过这个:
<Button Image="{local:EmbeddedImage TestThree.images.icons.speaker.png}" />
......但那不起作用......
我希望这些按钮能够在我的PCL项目中显示图像文件夹中的图像。
所以我的问题是......
<Button WHAT GOES HERE? Grid.Row="0" Grid.Column="0" />
答案 0 :(得分:3)
当Button.Image想要FileImageStream时,我会把它交给他。但是作为项目中的图像,我仍然在PCL(或.NET标准2.0)库(项目)中使用嵌入式资源PNG文件。 例如,PCL项目名称是“MyProject”,我在其子文件夹“Images \ Icons \ ok.png”中放置了一个图像。然后资源名称(例如,对于ImageSource.FromResource)是“MyProject.Images.Icons.ok.png”。 此方法将嵌入的资源文件复制到应用程序本地存储中的文件中(仅第一次)。
public static async Task<string> CopyIcon(string fileName)
{
if (String.IsNullOrEmpty(fileName)) return "";
try
{
// Create (or open if already exists) subfolder "icons" in application local storage
var fld = await FileSystem.Current.LocalStorage.CreateFolderAsync("icons", CreationCollisionOption.OpenIfExists);
if (fld == null) return ""; // Failed to create folder
// Check if the file has not been copied earlier
if (await fld.CheckExistsAsync(fileName) == ExistenceCheckResult.FileExists)
return (await fld.GetFileAsync(fileName))?.Path; // Image copy already exists
// Source assembly and embedded resource path
string imageSrcPath = $"MyProject.Images.Icons.{fileName}"; // Full resource name
var assembly = typeof(FileUtils).GetTypeInfo().Assembly;
// Copy image from resources to the file in application local storage
var file = await fld.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);
using (var target = await file.OpenAsync(PCLStorage.FileAccess.ReadAndWrite))
using (Stream source = assembly.GetManifestResourceStream(imageSrcPath))
await source.CopyToAsync(target); // Copy file stream
return file.Path; // Result is the path to the new file
}
catch
{
return ""; // No image displayed when error
}
}
当我有一个常规文件时,我可以将它用于FileImageStream(Button.Image)。 第一个选项是从代码中使用它。
public partial class MainPage : ContentPage
{
protected async override void OnAppearing()
{
base.OnAppearing();
btnOk.Image = await FileUtils.CopyIcon("ok.png");
}
}
我也可以在XAML中使用它,但我必须创建一个IMarkupExtension接口的实现。
[ContentProperty("Source")]
public class ImageFileEx : IMarkupExtension
{
public string Source { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
return Task.Run(async () => await FileUtils.CopyIcon(Source)).Result;
}
}
现在我可以直接在XAML中分配图像。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyProject"
x:Class="MyProject.MainPage"
xmlns:lcl="clr-namespace:MyProject;assembly=MyProject">
<Grid VerticalOptions="Fill" HorizontalOptions="Fill">
<Button Image="{lcl:ImageFileEx Source='ok.png'}" Text="OK" />
</Grid>
</ContentPage>
对于此解决方案,需要NuGet PCLStorage。
答案 1 :(得分:0)
不起作用的原因是因为属性绑定到不同的类型。
Button的Image属性采用“FileImageSource” - Github
Image的Source属性采用“ImageSource” - Github
来自本地:EmbeddedImage即时猜测您使用的是Xamarin forms image docs
的扩展程序这不起作用,因为它加载了“StreamImageSource”而不是“FileImageSource”。
在实践中你不应该这样做,因为它不会从不同尺寸的图像(@ 2x,xhdpi等)加载,并且会产生质量差的图像而不支持多种分辨率。
您可以使用带有TapGestureRecognizer的视图容器(堆栈布局等)以及在其中居中的图像,或者创建一个自定义渲染器,它实际上比它的价值更省力。但是,这些仍然显然不能处理多个图像。
正确的解决方案是从基础生成正确大小的图像(我假设它将是MDPI Android或1X for iOS)并将它们放在正确的文件夹中并在您的工作按钮示例中引用它们。