帮酷LOGO
0 0 评论
  • 显示原文与译文双语对照的内容
文章标签:asset  Assets  form  图像  Xamarin  SHA  for  xamarin-forms  


本系列文章中的文章

鈣和示例應用的源代碼

本文的源代碼位於位於 https://calcium.codeplex.com/SourceControl/latest的鈣源代碼庫中。

請參閱解決方案 TrunkSourceCalciumXamarinInstallation CalciumTemplates.Xamarin.sln

介紹

在使用Xamarin構建跨平台應用時,圖像資源管理是一個挑戰。 每個平台都需要以不同方式處理圖像。 Android和iOS項目都使用自己的系統;將映像放在不同的目錄中。 然而,Windows Phone 可以讓你在任何地方放置圖片。 如果你希望能夠在整個項目中使用相同的圖像,那麼你需要將它們鏈接到不同的位置。 Windows Phone 是最大的失敗者,因為圖像必須放在項目的root 目錄中,這遠遠不是理想的。 另一種方法是將圖像資源嵌入到程序集中,當存在程序集大小增加程序集時不是很好。

Visual Studio Android和iOS項目要求所有圖像都放置在單個目錄中。 我不希望將圖像放入單個目錄中。 我更喜歡用功能相關來分組事物。 看到大型的web項目已經被孤立的圖像所填充后,它們之後的頁面已經很長時間了。

我設計了一種更好的方法來在項目之間共享圖像資源;一個可以保持 Windows Phone 系統的靈活性。 我的方法使用一個T4模板,將共享項目中的文件複製到各種iOS和Android資源目錄,將它們添加到你的iOS和Android項目中,並正確設置映像的生成操作。 在本文後面,你將看到自定義標記擴展如何轉換圖像資源 url,以便正確解決圖像。 這種方法提供了 Windows Phone 資源系統的所有靈活性,同時仍然保持與iOS和Android的兼容性。

圖像元素通常用於Xamarin窗體中,在頁面上顯示PNG或者JPG圖像。 請參見下面的示例:

<ImageSource="CalciumLogo.png"/>

要在每個平台上正確顯示圖像,必須位於iOS項目的資源目錄。Android項目的資源/或者 Windows 電話的root 目錄。

在Xamarin網站上對圖片元素進行了全面的介紹,在 http://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/images/網站上。
儘管有很好的理解Xamarin形式的圖像資源,但在使用本文描述的方法時,大部分摩擦都會消失。

有一個名為 CalciumLogo.png的PNG映像位於共享項目的/Views/MainView/Images 目錄中。 Windows Phone 不同,在使用Xamarin窗體時不解析以下路徑:

<ImageSource="/Views/MainView/Images/CalciumLogo.png"/>

讓它工作吧。

圖像元素的Source 屬性是一個 ImageSource。 類型轉換器用於將XAML中提供的字元串值轉換為實際的ImageSource 實例。 我們可以通過創建自定義標記擴展來接管從指定URL創建 ImageSource 對象的責任。

Xamarin表單的一個出色特性是包含了標記擴展。 我驚喜地看到他們出現在Xamarin表單的第一個版本中。 擁有創建自定義標記擴展的能力為我們提供了擴展在XAML中可以做的事情的強大方法。 我們並沒有等待'官方'支持一切;我們可以去 MacGyver,讓它自己。

位於鈣源代碼庫中 Outcoder.Calcium.Android 項目中的ImageUrlTransformer 類將字元串值轉換為特定於平台的URL。 它有一個名為 TransformForCurrentPlatform的方法。 如清單 1所示,該方法接受一個 URL,如果應用程序在iOS或者Android上運行,它將用下劃線替換路徑分隔符斜杠。 例如如果我們在iOS或者Android上傳遞 "/Views/MainView/Images/CalciumLogo.png" 這個方法,該方法應該返回" views_mainview_images_calciumlogo.png"

相反,如果應用程序在 Windows Phone 上運行,任務就會變得更加直接;標記擴展使用提供的未更改路徑解析圖像。

當然,為了在iOS和Android上正常工作,必須有一個名為 Views_MainView_Images_CalciumLogo.png的映像,位於每個平台的各自資源目錄中。 我們將在本節後面的GREATER 細節中進行。

如果你的平台是iOS或者 Android,指定的URL以 file:///,請注意,它表示一個Uri對象,而不是字元串,用於指定圖像位置。 可以,但必須從圖像的URL中刪除,才能正確解析。

清單 1。ImageUrlTransformer.TransformForCurrentPlatform 方法

publicstring TransformForCurrentPlatform(string url)
{
 string result = ArgumentValidator.AssertNotNull(url, "url");
 if (Device.OS == TargetPlatform.Android || Device.OS == TargetPlatform.iOS)
 {
 conststring filePrefix = "file:///";
 if (url.StartsWith(filePrefix))
 {
 result = url.Substring(filePrefix.Length);
 }
 result = result.Replace("/", "_").Replace("", "_");
 if (result.StartsWith("_") && result.Length >1)
 {
 result = result.Substring(1);
 }
 }
 elseif (Device.OS == TargetPlatform.WinPhone)
 {
 if (url.StartsWith("/") && url.Length >1)
 {
 result = result.Substring(1);
 }
 }
 return result;
}

自定義標記擴展為你提供了在運行時使用自定義邏輯解析值的擴展點。 iPhone 7 還沒出來,我們已經在iPhone上獲取細節 8,或者不管是想到下一步。 Xamarin.Forms.Xaml.IMarkupExtension 介面包含名為 ProvideValue的單個方法,它用於處理值並將對象返回到XAML元素中的屬性集。

ImageResourceExtension 類中的類是一個自定義標記擴展,它利用 ImageUrlTransformer 類。 見清單 2.

清單 2。ImageResourceExtension類( 摘錄)

[ContentProperty("Source")]publicclass ImageResourceExtension : IMarkupExtension
{
 publicstring Source { get; set; }
 publicobject ProvideValue(IServiceProvider serviceProvider)
 {
. . .
 }
}

從方法的ImageResourceExtensionProvideValue 返回一個 ImageSource 對象。 參見清單 3。該方法使用 IImageUrlTransformer的實現將 Source 屬性的值轉換為特定於平台的URL。

注意 NOTE。如果要更改url的處理方式和修改類的行為,可以通過註冊你自己的IImageUrlTransformer的實現來完成。

類使用Xamarin窗體 Device.OS 屬性確定應用程序運行的平台。 如果應用程序在iOS或者Android上運行,那麼URL將被平整,圖像將駐留在資源目錄中。 static ImageSource.FromFile 方法用於創建一個 ImageSource 對象。

如果應用程序在 Windows Phone 上運行,則創建一個流來讀取圖像文件,該流在lambda表達式中傳遞到 static ImageSource.FromStream 方法。

清單 3。ImageResourceExtension.ProvideValue 方法

publicobject ProvideValue(IServiceProvider serviceProvider)
{
 if (Source == null)
 {
 returnnull;
 }
 ImageSource imageSource = null;
 var transformer = Dependency.Resolve<IImageUrlTransformer, ImageUrlTransformer>(true);
 string url = transformer.TransformForCurrentPlatform(Source);
 if (Device.OS == TargetPlatform.Android)
 {
 imageSource = ImageSource.FromFile(url);
 }
 elseif (Device.OS == TargetPlatform.iOS)
 {
 imageSource = ImageSource.FromFile(url);
 }
 elseif (Device.OS == TargetPlatform.WinPhone)
 {#if WINDOWS_PHONEif (url.StartsWith("/") && url.Length >1)
 {
 url = url.Substring(1);
 }
 var stream = System.Windows.Application.GetResourceStream(new Uri(url, UriKind.Relative));
 if (stream!= null)
 {
 imageSource = ImageSource.FromStream(() => stream.Stream);
 }
 else {
 ILog log;
 if (Dependency.TryResolve<ILog>(out log))
 {
 log.Debug("Unable to located create ImageSource using URL:" + url);
 }
 }#endif }
 if (imageSource == null)
 {
 imageSource = ImageSource.FromFile(url);
 }
 return imageSource;
}

有了 ImageResourceExtension 類之後,現在就可以指定像這樣的映像文件的路徑了:

<ImageSource="{calcium:ImageResource/Views/MainView/Images/CalciumLogo.png}"/>

我們可以在這裡停止,但這將使我們不得不重複。重命名和重新排列每個平台的圖像。 我們甚至可以嘗試鏈接和重命名文件。 但是我們很快就遇到了同樣的可維護性問題,我們開始嘗試解決這些問題。 讓我們做一些更好的事情。

使用T4共享圖像資源

在本節中,你將看到如何創建可以複製的T4模板,該模板將共享項目中的所有圖像複製到你的iOS或者Android項目的資源目錄。 然後自動將文件導入項目,根據平台為文件設置正確的生成操作。

這不是我們在本系列第 3部分中看到的本地化解決方案之後提出的擴展: 構建可以本地化的跨平台平台應用Xamarin形式和鈣。 T4對於這樣的任務很方便。 你可能使用定製的MS生成任務實現相同的結果。 因為我覺得 LESS 很難配置和工作,所以我選擇了T4方法。 代碼易於修改且不被隱藏在外部程序集中。 然而,我猜,在長期以來,Xamarin可能會選擇 MS,。 但現在T4完成了任務。

使用T4將圖像導入到Android項目中

讓我們先看一下將T4模板集成到Android項目中。 可以下載示例中的ProjectTemplate.Xamarin.CSharp.Android 項目包含與這裡示例相關的兩個目錄: 基於xml的/Resources/Drawable 插件目錄,它是默認解析的必需位置;以及 /ResourcesModel/T4Templates 目錄,其中包含一些必需的T4文件。

以下步驟概述了設置T4映像共享模板的過程:

  • 創建一個名為ResourcesModel的目錄,並在你的Android項目中創建一個T4Templates目錄。
  • 將 Images.ttinclude 文件和 MultiFileOutput.ttinclude 文件添加到/ResourcesModel/T4Templates 目錄中,這些文件位於可以下載的示例中。
  • 將 Images.ttinclude 文件的生成操作和 MultiFileOutput.ttinclude 文件設置為無。
  • 在/Resources/Drawable 項目的目錄中,使用studio對話框Visual添加一個文本文件。 單擊確定之前,請重命名文件 Images.tt.
  • 將以下文本粘貼到 Images.tt file: 中
    <#@ 包括 file="。resourcesmodelt4templatesimages。ttinclude"#>
    <#@ 輸出 extension=". txt"#>
    <#@ 模板 language="C#"hostspecific="true"#> <#

    處理("calciumsampleapp","androidresource") ;

    #>
  • 將文本"calciumsampleapp"更改為共享項目的NAME。

注意 Process 方法的第二個參數定義了圖像的生成動作。 對於 Android,必須將它的指定為 AndroidResource。

如果路徑已經正確指定,當保存 Images.tt 文件時,圖像應當顯示為 Images.tt 文件的子項。 參見圖 1.共享項目中的圖像被成功複製。重命名並包含到Android項目中。

向資源目錄中導入圖 1.

使用T4將圖像導入到iOS項目中

為導入共享映像而設置一個iOS項目的過程與Android項目的過程幾乎相同。 但是,有兩種差異: iOS的映像目錄為 /resources,並且必須將生成操作參數指定為 BundleResource。 Images.tt的內容應類似於以下內容:

<#@includefile="..ResourcesModelT4TemplatesImages.ttinclude"#><#@outputextension=".txt"#><#@templatelanguage="C#"hostSpecific="true"#><#Process("CalciumSampleApp","BundleResource");#>

在場景後面使用T4導入圖像

生成圖像的邏輯包含在 Images.ttinclude 文件的Process 方法中。 方法使用 Visual Studio DTE對象來遍歷項目和文件的解決方案。

在流程方法中,可以像這樣檢索 DTE:

IServiceProvider hostServiceProvider = (IServiceProvider)Host;
EnvDTE.DTE dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));

方法使用名為 GetProjects的方法檢索解決方案的所有項目。 由於項目可能位於解決方案文件夾中,因此檢索項目的List 是一個遞歸的Activity。

隨著項目的List,Process 方法嘗試通過在解決方案中迭代項目來找到圖像所在的項目。

var solution = dte.Solution;var items = GetProjects();foreach (EnvDTE.Project item in items)
{ 
 if (item.Name.EndsWith(projectName))
 {
 project = item;
 break;
 }
}

GetFiles 函數使用尾部遞歸來檢索具有指定文件擴展名的所有文件。 見清單 4.

清單 4 GetFiles function功能

void GetFiles(ProjectItem projectItem, string fileExtension, IList<string> fileList)
{
 string fullPath = projectItem.Properties.Item("FullPath").Value.ToString();
 if (fullPath.ToLower().EndsWith(fileExtension))
 {
 fileList.Add(fullPath);
 }
 var childItems = projectItem.ProjectItems;
 if (childItems!= null)
 {
 foreach (ProjectItem childItem in childItems)
 {
 GetFiles(childItem, fileExtension, fileList); 
 }
 }
}

Process 函數使用 GetFiles 函數填充包含所有PNG和JPG文件路徑的List,如下所示:

var fileExtensions = new string[] { ".png", ".jpg" };var fileList = new List<string>();var projectItems = project.ProjectItems;if (projectItems!= null)
{
 foreach (ProjectItem projectItem in project.ProjectItems)
 {
 foreach (string extension in fileExtensions)
 {
 GetFiles(projectItem, extension, fileList);
 }
 }
}

過程函數然後通過將路徑分隔符替換為下劃線來創建每個圖像路徑中的展平 NAME。 參見清單 5.如果圖像已經作為資源存在,則對兩個文件的LastWriteTime 值進行比較。 如果原始圖像具有較舊的LastWriteTime 值,則不需要執行任何操作。 這裡步驟避免從源代碼管理中不必要地簽出文件。

清單 5 過程函數中的copy。Images.ttinclude 複製文件

string templateDirectory = Path.GetDirectoryName(Host.TemplateFile); foreach (string item in fileList)
{
 if (!item.StartsWith(projectDirectory))
 {
 continue;
 }
 string fileNameInProject = Path.GetFileName(item);
 string fileDirectory = Path.GetDirectoryName(item);
 string pathSubstring = fileDirectory.Substring(projectDirectoryLength);
 if (pathSubstring.StartsWith(""))
 {
 pathSubstring = pathSubstring.Substring(1);
 }
 string flattenedPathSubstring = pathSubstring.Replace("","_");
 if (flattenedPathSubstring.Length >0)
 {
 flattenedPathSubstring = flattenedPathSubstring + "_";
 }
 string flattenedFileName = flattenedPathSubstring + fileNameInProject;
 string newOutputPath = Path.Combine(templateDirectory, flattenedFileName);
 if (File.Exists(newOutputPath))
 {
 var projectFileInfo = new System.IO.FileInfo(item);
 var newFileInfo = new System.IO.FileInfo(newOutputPath);
 if (projectFileInfo.LastWriteTimeUtc < newFileInfo.LastWriteTimeUtc)
 {
 continue;
 }
 }
 File.Copy(item, newOutputPath, true);
. . .
}

最後,使用 MultiFileOutput.ttinclude 文件中的AddProjectItem 函數將該項添加到項目中,如下面的摘錄所示:

AddProjectItem(flattenedFileName, buildAction);

感謝go在 Oleg Sych上提供關於從單個T4模板生成多個輸出的有用的文章。

如果你閱讀上一篇文章,第 4部分: 使用Xamarin窗體和鈣創建一個跨平台應用程序條,你可能會想起,icon 圖像是使用IImageUrlTransformer來解析的。 在清單 6中,你再次看到TransformForCurrentPlatform如何返回與 Images.tt 模板平滑輸出兼容的圖像 URL。

清單 6。使用IImageUrlTransformer解析 icon 映像。

var uri = appBarItem.IconUri;if (uri!= null)
{
 string url = uri.ToString();
 string transformedUrl = imageUrlTransformer.TransformForCurrentPlatform(url);
 item.Icon = transformedUrl;
}

注意:在生成項目時,Visual Studio 可能會抱怨文件x 已經定義。 確定(. tt ) 模板的生成操作設置為無。 Visual Studio 有時喜歡對這些文件進行 switch 構建操作。

結束語

如何為各種平台解決圖像的差異將在Xamarin窗體中放置圖像的一些限制。 使用本文提供的技術可以避免這些限制;提供 Windows Phone 資源系統的靈活性,同時仍保持iOS和 Android。

在本文中,你了解了如何以統一的方式共享和使用項目之間的映像文件。 你已經看到了如何將圖像文件從共享項目複製到iOS和Android資源目錄;。 最後,你了解了如何使用自定義標記擴展來翻譯圖像資源 url,以便在XAML中引用圖像,而不管平台如何使用。

我希望你能找到這個項目。 如果是這樣,那麼我會感謝你的價格,並且/或者離開反饋 below。 這將幫助我更好地閱讀下一篇文章。

在下一篇文章中,你將探索鈣選項系統用戶,它允許你在一行代碼中定義一個選項。 然後在應用程序的選項視圖中自動顯示選項,當用戶修改選項時,選項系統會自動保存更改。

歷史記錄

2014

  • 初始出版物。


文章标签:图像  for  form  SHA  表单  分享  asset  Xamarin  

Copyright © 2011 HelpLib All rights reserved.    知识分享协议 京ICP备05059198号-3  |  如果智培  |  酷兔英语