Xamarin.Forms 使用目標平台的本機控件呈現用戶界面,從而讓 Xamarin.Forms 應用程序為每個平台保留了相應的界面外觀。憑借效果,無需進行自定義呈現器實現,即可自定義每個平台上的本機控件,通常用於細微的樣式更改。
Xamarin.Forms 頁、布局和控件提供常見的 API,用於描述跨平台的移動用戶界面。 通過 Renderer
類可以在每個平台上以不同方式呈現每個頁面、布局和控件,反過來又可以創建本機控件(對應於 Xamarin.Forms 表示),在屏幕上排列該控件,並添加共享代碼中指定的行為。
開發人員可以實現自定義 Renderer
類,以自定義控件的外觀和/或行為。 可以將給定類型的自定義呈現器添加到一個應用程序項目中,以便在同一個位置自定義控件,同時允許其他平台上的默認行為,或者將不同的自定義呈現器添加到每個應用程序項目中,以便在 iOS、Android 和通用 Windows 平台 (UWP) 上創建不同的外觀和感覺。 但是,實現自定義渲染器類以執行簡單的控件自定義通常是一項重量級的響應。 效果簡化了此過程,通常用於較小的樣式更改。有關詳細信息,請參閱效果。
效果
通過將PlatformEffect控件子類化,可以在特定於平台的項目中創建效果,然后通過將效果附加到Xamarin.Forms .NET Standard庫或共享庫項目中的適當控件來使用效果。
為什么要在自定義呈現器上使用效果?
效果簡化了控件的自定義、可重用並且可以通過參數化進一步增加重用。
任何可以使用效果達成的事情也可以使用自定義呈現器達成。 但是,自定義呈現器提供比效果更多的靈活性和自定義。 以下指南列出了在自定義呈現器上選擇效果的情況:
- 當更改特定於平台的控件的屬性能達成所需結果時,建議使用效果。
- 當需要替代特定於平台的控件的方法時,需要使用自定義呈現器。
- 當需要替換實現 Xamarin.Forms 控件的特定於平台的控件時,需要使用自定義呈現器。
子類化 PlatformEffect 類
每個特定於平台的 PlatformEffect
類都公開以下屬性:
Container
– 引用用於實現布局的特定於平台的控件。Control
– 引用用於實現 Xamarin.Forms 控件的特定於平台的控件。Element
– 引用正在呈現的 Xamarin.Forms 控件。
效果沒有它們附加到的容器、控件或元素的類型信息,因為它們可以附加到任何元素。 因此,當效果附加到它不支持的元素時,它應該適當地降級或引發異常。 但是,Container
、Control
和 Element
屬性可以強制轉換為其實現的類型。 若要詳細了解這些類型,請參閱呈現器基類和本機控件。
每個特定於平台的 PlatformEffect
類都公開以下方法,必須替代這些方法以實現效果:
OnAttached
– 當效果附加到 Xamarin.Forms 控件時調用。 在每個特定於平台的效果類中,此方法的overridden是執行控件自定義邏輯的位置,以及在效果無法應用於指定的 Xamarin.Forms 控件的情況下的異常處理。OnDetached
– 當效果自 Xamarin.Forms 控件分離時調用。 在每個特定於平台的效果類中,此方法的overridden是執行任何效果清除的位置,例如取消注冊事件處理程序。
此外,PlatformEffect
公開了 OnElementPropertyChanged
方法,該方法也可以被替代。 當該元素的屬性發生更改時,調用此方法。 在每個特定於平台的效果類中,此方法的替代版本是響應 Xamarin.Forms 控件上的可綁定屬性更改的位置。 應始終檢查已更改的屬性,因為可多次調用此替代。
效果創建
例如,創建效果以實現 在指向 Entry 控件時更改其背景顏色。
在每個特定於平台的項目中創建效果的過程如下:
- 創建
PlatformEffect
類的子類。 - 替代
OnAttached
方法並寫入自定義控件的邏輯。 - 根據需要替代
OnDetached
方法並寫入清理控件自定義的邏輯。 - 向效果類添加
ResolutionGroupName
屬性。 此屬性為效果設置一個公司范圍的命名空間,以避免與同名的其他效果發生沖突。 請注意,每個項目只能應用一次該屬性。 - 向效果類添加
ExportEffect
屬性。 該屬性使用 Xamarin.Forms 所用的唯一 ID 以及組名注冊效果,以便在將應用於控件之前定位該效果。 該屬性接受兩個參數 - 效果的類型名稱和一個唯一的字符串,該字符串用於在將效果應用於控件之前定位該效果。
然后,可以通過將效果附加到相應控件來使用該效果。
1、在各平台上創建效果
[assembly: ResolutionGroupName("MyCompany")]
[assembly: ExportEffect(typeof(EffectsDemo.Droid.FocusEffect), nameof(EffectsDemo.Droid.FocusEffect))]
namespace EffectsDemo.Droid
{
public class FocusEffect : PlatformEffect
{
protected override void OnAttached() {
在OnAttached()中設置控件【需要設置效果的控件】的一些外觀。
屬性ResolutionGroupName和ExportEffect的第二個參數,用於定位效果,"MyCompany.FocusEffect"【在使用效果時 需要】
2、使用效果(在XAML中)
RoutingEffect
類它表示一個獨立於平台的效果,該效果包裝通常特定於平台的內部效果。
在運行時初始化 Entry
時,向控件的 Effects
集合添加了 MyCompany.FocusEffect
的新實例。
傳遞參數
效果參數可以通過屬性定義,從而可以重用效果。 然后,可以在實例化效果時通過為每個屬性指定值來將參數傳遞給效果。
1、將效果參數作為公共語言運行時(CLR)屬性傳遞
公共語言運行時(CLR)屬性可用於定義不響應運行時屬性更改的效果參數。 本文演示了如何使用CLR屬性將參數傳遞給效果。
2、將效果參數作為附加屬性傳遞
附加屬性可用於定義響應運行時屬性更改的效果參數。 本文演示了如何使用附加屬性將參數傳遞給效果,以及在運行時更改參數。
作為CLR屬性的參數
創建效果參數

public class ShadowEffect : RoutingEffect { public float Radius { get; set; } public Color Color { get; set; } public float DistanceX { get; set; } public float DistanceY { get; set; } public ShadowEffect () : base ("MyCompany.LabelShadowEffect") { } }
使用效果

<Label Text="Label Shadow Effect" ...> <Label.Effects> <local:ShadowEffect Radius="5" DistanceX="5" DistanceY="5"> <local:ShadowEffect.Color> <OnPlatform x:TypeArguments="Color"> <On Platform="iOS" Value="Black" /> <On Platform="Android" Value="White" /> <On Platform="UWP" Value="Red" /> </OnPlatform> </local:ShadowEffect.Color> </local:ShadowEffect> </Label.Effects> </Label>
在各個平台上創建效果:略
作為附加屬性的參數
創建效果參數

public static class ShadowEffect { public static readonly BindableProperty HasShadowProperty = BindableProperty.CreateAttached ("HasShadow", typeof(bool), typeof(ShadowEffect), false, propertyChanged: OnHasShadowChanged); public static readonly BindableProperty ColorProperty = BindableProperty.CreateAttached ("Color", typeof(Color), typeof(ShadowEffect), Color.Default); public static readonly BindableProperty RadiusProperty = BindableProperty.CreateAttached ("Radius", typeof(double), typeof(ShadowEffect), 1.0); public static readonly BindableProperty DistanceXProperty = BindableProperty.CreateAttached ("DistanceX", typeof(double), typeof(ShadowEffect), 0.0); public static readonly BindableProperty DistanceYProperty = BindableProperty.CreateAttached ("DistanceY", typeof(double), typeof(ShadowEffect), 0.0); public static bool GetHasShadow (BindableObject view) { return (bool)view.GetValue (HasShadowProperty); } public static void SetHasShadow (BindableObject view, bool value) { view.SetValue (HasShadowProperty, value); } ... static void OnHasShadowChanged (BindableObject bindable, object oldValue, object newValue) { var view = bindable as View; if (view == null) { return; } bool hasShadow = (bool)newValue; if (hasShadow) { view.Effects.Add (new LabelShadowEffect ()); } else { var toRemove = view.Effects.FirstOrDefault (e => e is LabelShadowEffect); if (toRemove != null) { view.Effects.Remove (toRemove); } } } class LabelShadowEffect : RoutingEffect { public LabelShadowEffect () : base ("MyCompany.LabelShadowEffect") { } } }
ShadowEffect
包含五個附加屬性,以及每個附加屬性的 static
getter 和 setter。 其中四個屬性表示要傳遞給每個特定於平台的 LabelShadowEffect
的參數。 ShadowEffect
類還定義了 HasShadow
附加屬性,用於控制 ShadowEffect
類附加到的控件的效果的添加或刪除。 該附加屬性注冊屬性值更改時執行的 OnHasShadowChanged
方法。 此方法根據 HasShadow
附加屬性的值添加或刪除效果。
嵌套 LabelShadowEffect
類是 RoutingEffect
類的子類,支持添加和刪除效果。
其他詳細的看示例。
自定義呈現器Renderer
Xamarin.Forms 使用目標平台的本機控件呈現用戶界面,從而讓 Xamarin.Forms 應用程序為每個平台保留了相應的界面外觀。自定義呈現器允許開發人員重寫此過程,自定義每個平台上 Xamarin.Forms 控件的外觀和行為。
Renderer Base Classes and Native Controls
每個Xamarin.Forms控件都有一個用於每個平台的隨附渲染器,這些渲染器創建本機控件的實例。 本文列出了實現每個Xamarin.Forms頁面,布局,視圖和單元格的渲染器和本機控件類。
除MapRenderer類外,特定於平台的渲染器可在以下命名空間中找到:
- iOS – Xamarin.Forms.Platform.iOS
- Android – Xamarin.Forms.Platform.Android
- Android(AppCompat)– Xamarin.Forms.Platform.Android.AppCompat
- 通用Windows平台(UWP)– Xamarin.Forms.Platform.UWP
可以在以下命名空間中找到MapRenderer類:
- iOS – Xamarin.Forms.Maps.iOS
- Android – Xamarin.Forms.Maps.Android
- 通用Windows平台(UWP)– Xamarin.Forms.Maps.UWP
有關 Xamarin.Forms 控件映射到的呈現器和本機控件類的詳細信息,請參閱呈現器基類和本機控件。
自定義Entry
Xamarin.Forms Entry 控件允許對單行文本進行編輯。本文演示了如何為 Entry 控件創建自定義呈現器,使開發人員能夠使用自己特定於平台的自定義呈現替代默認本機呈現。
每個 Xamarin.Forms 控件都有一個附帶的呈現器,適用於創建本機控件實例的各個平台。
Xamarin.Forms 應用程序呈現 Entry
控件時,在 iOS 中實例化 EntryRenderer
類,進而實例化本機 UITextField
控件。 在 Android 平台上,EntryRenderer
類實例化 EditText
控件。 在通用 Windows 平台 (UWP) 上,EntryRenderer
類實例化 TextBox
控件。
下圖說明了 Entry
控件和實現它的相應本機控件之間的關系:
通過在每個平台上為 Entry
控件創建自定義呈現器,可以利用呈現過程來實現特定於平台的自定義。 執行此操作的過程如下:
- 創建 Xamarin.Forms 自定義控件。
- 使用 Xamarin.Forms 中的自定義控件。
- 在每個平台上為控件創建自定義呈現器。
注:本文介紹如何創建簡單的自定義呈現器。 但是,要在每個平台上實現具有不同背景色的 Entry
,無需創建自定義呈現器。 這可以通過使用 Device
類或 OnPlatform
標記擴展來輕松實現,以提供特定於平台的值。 有關詳細信息,請參閱提供特定於平台的值和 OnPlatform 標記擴展。
創建和使用自定義Entry控件
定義類(不必是控件,不需要xaml)MyEntry,
public class MyEntry : Entry { }
<ContentPage ... xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer" ...> ... <local:MyEntry Text="In Shared Code" /> ... </ContentPage>
在每個平台上創建自定義呈現器
創建自定義呈現器類的過程如下所示:
- 創建呈現本機控件的
EntryRenderer
類的子類。 - 替代呈現本機控件的
OnElementChanged
方法並寫入邏輯以自定義控件,創建相應的 Xamarin.Forms 控件時將調用此方法【相當於構造函數】。 - 向自定義呈現器類添加
ExportRenderer
屬性,以指定其將用於呈現 Xamarin.Forms 控件,此屬性用於向 Xamarin.Forms 注冊自定義呈現器。
Android為例,

using Xamarin.Forms.Platform.Android; [assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))] namespace CustomRenderer.Android { class MyEntryRenderer : EntryRenderer { public MyEntryRenderer(Context context) : base(context) { } protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); if (Control != null) { Control.SetBackgroundColor(global::Android.Graphics.Color.LightGreen); } } } }
對基類的OnElementChanged方法的調用將實例化一個Android EditText控件,並將對該控件的引用分配給渲染器的Control屬性。 然后使用Control.SetBackgroundColor方法將背景色設置為淺綠色。
自定義ContentPage
實現自定義的View
Xamarin.Forms自定義用戶界面控件應從View類派生,該類用於在屏幕上放置布局和控件。
每個Xamarin.Forms視圖都有一個用於每個平台的隨附渲染器,這些渲染器創建本機控件的實例。
- 當iOS中的Xamarin.Forms應用程序呈現View時,將實例化ViewRenderer類,從而實例化本機UIView控件。
- 在Android平台上,ViewRenderer類實例化本機View控件。
- 在通用Windows平台(UWP)上,ViewRenderer類實例化本機FrameworkElement控件。
自定義ListView
通過在每個平台上為 ListView
創建自定義呈現器,可以利用呈現過程來實現特定於平台的自定義。 執行此操作的過程如下:
- 創建 Xamarin.Forms 自定義控件。
- 使用 Xamarin.Forms 中的自定義控件。
- 在每個平台上為控件創建自定義呈現器。
現在將依次討論每個項目,以實現 NativeListView
呈現器,該呈現器利用特定於平台的列表控件和本機單元布局。 移植包含可以重復使用的列表和單元代碼的現有本機應用時,此方案很有用。 此外,它還允許對可能影響性能的列表控件功能進行詳細自定義,例如數據虛擬化。
自定義WebView
Xamarin.Forms WebView
是在應用中顯示 Web 和 HTML 內容的視圖。 可以創建擴展 WebView
以允許從 JavaScript 調用 C# 代碼的自定義呈現器。
WebView
可從 C# 調用 JavaScript 函數,並將任何結果返回給調用的 C# 代碼。 有關詳細信息,請參閱調用 JavaScript。
通過在每個平台上為 WebView
創建自定義呈現器,可使用呈現過程來實現平台自定義。 執行此操作的過程如下:
- 創建
HybridWebView
自定義控件。 - 使用 Xamarin.Forms 中的
HybridWebView
。 - 在每個平台上為
HybridWebView
創建自定義呈現器。
現在,依次討論每個項目以實現 HybridWebView
呈現器,該呈現器可增強 Xamarin.Forms WebView
以允許從 JavaScript 調用 C# 代碼。 HybridWebView
實例將用於顯示要求用戶輸入其名稱的 HTML 頁。 然后,當用戶單擊 HTML 按鈕,JavaScript 函數將調用 C# Action
顯示一個包含用戶名稱的彈出項。