共用方式為


自訂 ContentPage

ContentPage 是可見的項目,會顯示單一檢視,並佔用螢幕的大部分空間。 本文示範如何建立 ContentPage 頁面的自訂轉譯器,讓開發人員以自己的平台特定自訂來覆寫預設原生轉譯。

每個 Xamarin.Forms 控件都有每個平臺的隨附轉譯器,可建立原生控件的實例。 ContentPage當應用程式轉Xamarin.Forms譯 時,會在iOS PageRenderer 中具現化 類別,進而具現化原生UIViewController控件。 在 Android 平台上,PageRenderer 類別會具現化原生的 ViewGroup 控制項。 在通用 Windows 平台 (UWP) 上,PageRenderer 類別會具現化 FrameworkElement 控制項。 如需控件對應之轉譯器和原生控件類別 Xamarin.Forms 的詳細資訊,請參閱 轉譯器基類和原生控件

下圖說明 ContentPage 和實作它之對應原生控制項間的關聯性:

ContentPage 類別與實作原生控制項之間的關聯性

您可在每個平台上建立 ContentPage 的自訂轉譯器,利用轉譯程序實作平台特定的自訂。 執行這項作業的程序如下:

  1. 建立Xamarin.Forms頁面。
  2. 從Xamarin.Forms取用頁面。
  3. 在每個平台上建立頁面的自訂轉譯器。

現在將依序討論每個項目,以實作 CameraPage 提供即時相機播放和拍照功能。

Xamarin.Forms建立頁面

將未修改 ContentPage 的專案新增至共享 Xamarin.Forms 專案,如下列 XAML 程式代碼範例所示:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomRenderer.CameraPage">
    <ContentPage.Content>
    </ContentPage.Content>
</ContentPage>

同樣地,ContentPage 的程式碼後置檔案也應該保持不變,如下列程式碼範例所示:

public partial class CameraPage : ContentPage
{
    public CameraPage ()
    {
        // A custom renderer is used to display the camera UI
        InitializeComponent ();
    }
}

下列程式碼範例示範如何在 C# 中建立頁面:

public class CameraPageCS : ContentPage
{
    public CameraPageCS ()
    {
    }
}

每個平台上都會使用 CameraPage 執行個體來顯示即時相機播放。 控制項的自訂作業會在自訂轉譯器中完成,因此不需要在 CameraPage 類別中進行其他實作。

取用 Xamarin.Forms 頁面

應用程式必須顯示Xamarin.Forms空白CameraPage。 此動作發生於點選 MainPage 執行個體上的按鈕時,並會接著執行 OnTakePhotoButtonClicked 方法,如下列程式碼範例所示:

async void OnTakePhotoButtonClicked (object sender, EventArgs e)
{
    await Navigation.PushAsync (new CameraPage ());
}

此程式碼只會巡覽至 CameraPage,自訂轉譯器會在上方自訂每個平台上的頁面外觀。

在每個平台上建立頁面轉譯器

建立自訂轉譯器類別的流程如下:

  1. 建立 PageRenderer 類別的子類別。
  2. 覆寫轉譯原生頁面的 OnElementChanged 方法,並撰寫自訂頁面的邏輯。 建立 OnElementChanged 對應的 Xamarin.Forms 控件時會呼叫 方法。
  3. ExportRenderer將屬性新增至頁面轉譯器類別,以指定其將用來轉Xamarin.Forms譯頁面。 這個屬性是用來向 Xamarin.Forms註冊自定義轉譯器。

注意

您可以選擇每個平台專案是否提供頁面轉譯器。 如果頁面轉譯器未註冊,則會使用頁面的預設轉譯器。

下圖說明範例應用程式中每個專案的責任,以及它們之間的關聯性:

CameraPage 自訂轉譯器專案責任

CameraPage 執行個體是由平台特定 CameraPageRenderer 類別轉譯,其全部衍生自平台的 PageRenderer 類別。 這會導致每個 CameraPage 執行個體都會透過即時相機播放轉譯,如下列螢幕擷取畫面所示:

每個平台上的 CameraPage

類別 PageRendererOnElementChanged 公開 方法,這個方法會在建立頁面以轉譯對應的原生控件時 Xamarin.Forms 呼叫。 這個方法採用 ElementChangedEventArgs 參數,其中包含 OldElementNewElement 屬性。 這些屬性代表Xamarin.Forms轉譯器附加的專案,以及Xamarin.Forms轉譯器分別附加至的專案。 在範例應用程式中,OldElement 屬性會是 null,而 NewElement 屬性會包含 CameraPage 執行個體的參考。

CameraPageRenderer 類別中,OnElementChanged 方法的覆寫版本是執行原生頁面自訂的位置。 可以透過屬性取得正在轉譯之頁面實例的Element參考Xamarin.Forms。

每個自定義轉譯器類別都會以 ExportRenderer 向 註冊轉譯器 Xamarin.Forms的屬性裝飾。 屬性會採用兩個參數 : 正在轉譯之頁面的類型 Xamarin.Forms 名稱,以及自定義轉譯器的型別名稱。 屬性的 assembly 前置詞會指定套用至整個組件的屬性。

下列各節會討論適用於每個平台的 CameraPageRenderer 自訂轉譯器實作。

在 iOS 上建立頁面轉譯器

下列程式碼範例示範適用於 iOS 平台的頁面轉譯器:

[assembly:ExportRenderer (typeof(CameraPage), typeof(CameraPageRenderer))]
namespace CustomRenderer.iOS
{
    public class CameraPageRenderer : PageRenderer
    {
        ...

        protected override void OnElementChanged (VisualElementChangedEventArgs e)
        {
            base.OnElementChanged (e);

            if (e.OldElement != null || Element == null) {
                return;
            }

            try {
                SetupUserInterface ();
                SetupEventHandlers ();
                SetupLiveCameraStream ();
                AuthorizeCameraUse ();
            } catch (Exception ex) {
                System.Diagnostics.Debug.WriteLine (@"            ERROR: ", ex.Message);
            }
        }
        ...
    }
}

基底類別的 OnElementChanged 方法呼叫會具現化 iOS UIViewController 控制項。 只有在轉譯器尚未附加至現有 Xamarin.Forms 元素的情況下,才會轉譯即時相機串流,而且前提是自定義轉譯器正在轉譯的頁面實例存在。

該頁面會接著透過一連串使用 AVCapture API 的方法來自訂,以從相機提供即時資料流並提供拍照功能。

在 Android 上建立頁面轉譯器

下列程式碼範例示範適用於 Android 平台的頁面轉譯器:

[assembly: ExportRenderer(typeof(CameraPage), typeof(CameraPageRenderer))]
namespace CustomRenderer.Droid
{
    public class CameraPageRenderer : PageRenderer, TextureView.ISurfaceTextureListener
    {
        ...
        public CameraPageRenderer(Context context) : base(context)
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null || Element == null)
            {
                return;
            }

            try
            {
                SetupUserInterface();
                SetupEventHandlers();
                AddView(view);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(@"            ERROR: ", ex.Message);
            }
        }
        ...
    }
}

基底類別的 OnElementChanged 方法呼叫會具現化 Android ViewGroup 控制項,這會是一組檢視。 只有在轉譯器尚未附加至現有 Xamarin.Forms 元素的情況下,才會轉譯即時相機串流,而且前提是自定義轉譯器正在轉譯的頁面實例存在。

該頁面會接著透過叫用一連串使用 Camera API 的方法自訂,以從相機提供即時資料流並提供拍照功能,再叫用 AddView 方法,將即時相機資料流 UI 新增至 ViewGroup。 請注意,在 Android 上,若要對檢視執行測量和配置作業,還必須覆寫 OnLayout 方法。

在 UWP 上建立頁面轉譯器

下列程式碼範例示範適用於 UWP 的頁面轉譯器:

[assembly: ExportRenderer(typeof(CameraPage), typeof(CameraPageRenderer))]
namespace CustomRenderer.UWP
{
    public class CameraPageRenderer : PageRenderer
    {
        ...
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Page> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null || Element == null)
            {
                return;
            }

            try
            {
                ...
                SetupUserInterface();
                SetupBasedOnStateAsync();

                this.Children.Add(page);
            }
            ...
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            page.Arrange(new Windows.Foundation.Rect(0, 0, finalSize.Width, finalSize.Height));
            return finalSize;
        }
        ...
    }
}

基底類別的 OnElementChanged 方法呼叫會具現化 iOS FrameworkElement 控制項,再於上方轉譯頁面。 只有在轉譯器尚未附加至現有 Xamarin.Forms 元素的情況下,才會轉譯即時相機串流,而且前提是自定義轉譯器正在轉譯的頁面實例存在。 該頁面會接著透過叫用一連串使用 MediaCapture API 的方法自訂,以從相機提供即時資料流並提供拍照功能,再將自訂頁面新增至 Children 集合以便顯示。

在 UWP 上實作衍生自 PageRenderer的自訂轉譯器時,還應該實作 ArrangeOverride 方法來排列頁面控制項,因為基底轉譯器並不知道要如何處理。 否則會產生空白頁。 因此,在此範例中,ArrangeOverride 方法會在 Page 執行個體上呼叫 Arrange 方法。

注意

請務必停止並處置提供 UWP 應用程式中相機存取權的物件。 若未這樣做,則可能會干擾嘗試存取裝置相機的其他應用程式。 如需詳細資訊,請參閱顯示相機預覽

摘要

本文示範了如何建立 ContentPage 頁面的自訂轉譯器,讓開發人員以自己的平台特定自訂來覆寫預設原生轉譯。 ContentPage 是可見的項目,會顯示單一檢視,並佔用螢幕的大部分空間。