Xamarin.Forms 自定義控件(呈現器和效果)


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 控件。

效果沒有它們附加到的容器、控件或元素的類型信息,因為它們可以附加到任何元素。 因此,當效果附加到它不支持的元素時,它應該適當地降級或引發異常。 但是,ContainerControl 和 Element 屬性可以強制轉換為其實現的類型。 若要詳細了解這些類型,請參閱呈現器基類和本機控件

每個特定於平台的 PlatformEffect 類都公開以下方法,必須替代這些方法以實現效果:

  • OnAttached – 當效果附加到 Xamarin.Forms 控件時調用。 在每個特定於平台的效果類中,此方法的overridden是執行控件自定義邏輯的位置,以及在效果無法應用於指定的 Xamarin.Forms 控件的情況下的異常處理。
  • OnDetached – 當效果自 Xamarin.Forms 控件分離時調用。 在每個特定於平台的效果類中,此方法的overridden是執行任何效果清除的位置,例如取消注冊事件處理程序。

此外,PlatformEffect 公開了 OnElementPropertyChanged 方法,該方法也可以被替代。 當該元素的屬性發生更改時,調用此方法。 在每個特定於平台的效果類中,此方法的替代版本是響應 Xamarin.Forms 控件上的可綁定屬性更改的位置。 應始終檢查已更改的屬性,因為可多次調用此替代。

效果創建

例如,創建效果以實現 在指向 Entry 控件時更改其背景顏色。

在每個特定於平台的項目中創建效果的過程如下:

  1. 創建 PlatformEffect 類的子類。
  2. 替代 OnAttached 方法並寫入自定義控件的邏輯。
  3. 根據需要替代 OnDetached 方法並寫入清理控件自定義的邏輯。
  4. 向效果類添加 ResolutionGroupName 屬性。 此屬性為效果設置一個公司范圍的命名空間,以避免與同名的其他效果發生沖突。 請注意,每個項目只能應用一次該屬性。
  5. 向效果類添加 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")
  {            
  }
}
View Code

使用效果

<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>
View Code

在各個平台上創建效果:略

作為附加屬性的參數

創建效果參數

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")
    {
    }
  }
}
View Code

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 控件創建自定義呈現器,可以利用呈現過程來實現特定於平台的自定義。 執行此操作的過程如下:

  1. 創建 Xamarin.Forms 自定義控件。
  2. 使用 Xamarin.Forms 中的自定義控件。
  3. 在每個平台上為控件創建自定義呈現器。

注:本文介紹如何創建簡單的自定義呈現器。 但是,要在每個平台上實現具有不同背景色的 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>

在每個平台上創建自定義呈現器

創建自定義呈現器類的過程如下所示:

  1. 創建呈現本機控件的 EntryRenderer 類的子類。
  2. 替代呈現本機控件的 OnElementChanged 方法並寫入邏輯以自定義控件,創建相應的 Xamarin.Forms 控件時將調用此方法【相當於構造函數】
  3. 向自定義呈現器類添加 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);
            }
        }
    }
}
View Code

對基類的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 創建自定義呈現器,可以利用呈現過程來實現特定於平台的自定義。 執行此操作的過程如下:

  1. 創建 Xamarin.Forms 自定義控件。
  2. 使用 Xamarin.Forms 中的自定義控件。
  3. 在每個平台上為控件創建自定義呈現器。

現在將依次討論每個項目,以實現 NativeListView 呈現器,該呈現器利用特定於平台的列表控件和本機單元布局。 移植包含可以重復使用的列表和單元代碼的現有本機應用時,此方案很有用。 此外,它還允許對可能影響性能的列表控件功能進行詳細自定義,例如數據虛擬化。

自定義WebView

Xamarin.Forms WebView 是在應用中顯示 Web 和 HTML 內容的視圖。 可以創建擴展 WebView 以允許從 JavaScript 調用 C# 代碼的自定義呈現器。

 

 WebView 可從 C# 調用 JavaScript 函數,並將任何結果返回給調用的 C# 代碼。 有關詳細信息,請參閱調用 JavaScript

通過在每個平台上為 WebView 創建自定義呈現器,可使用呈現過程來實現平台自定義。 執行此操作的過程如下:

  1. 創建HybridWebView自定義控件。
  2. 使用 Xamarin.Forms 中的 HybridWebView
  3. 在每個平台上為 HybridWebView創建自定義呈現器。

現在,依次討論每個項目以實現 HybridWebView 呈現器,該呈現器可增強 Xamarin.Forms WebView 以允許從 JavaScript 調用 C# 代碼。 HybridWebView 實例將用於顯示要求用戶輸入其名稱的 HTML 頁。 然后,當用戶單擊 HTML 按鈕,JavaScript 函數將調用 C# Action 顯示一個包含用戶名稱的彈出項。

示例地址

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM