Bagikan melalui


Menerapkan Tampilan

Xamarin.Forms kontrol antarmuka pengguna kustom harus berasal dari kelas Tampilan, yang digunakan untuk menempatkan tata letak dan kontrol di layar. Artikel ini menunjukkan cara membuat perender kustom untuk Xamarin.Forms kontrol kustom yang digunakan untuk menampilkan streaming video pratinjau dari kamera perangkat.

Setiap Xamarin.Forms tampilan memiliki perender yang menyertainya untuk setiap platform yang membuat instans kontrol asli. View Ketika dirender oleh Xamarin.Forms aplikasi di iOS, ViewRenderer kelas dibuat, yang pada gilirannya membuat instans kontrol asliUIView. Pada platform Android, ViewRenderer kelas membuat instans kontrol asli View . Pada Platform Windows Universal (UWP), ViewRenderer kelas membuat instans kontrol asliFrameworkElement. Untuk informasi selengkapnya tentang kelas perender dan kontrol asli yang Xamarin.Forms mengontrol peta ke, lihat Kelas Dasar Perender dan Kontrol Asli.

Catatan

Beberapa kontrol di Android menggunakan perender cepat, yang tidak menggunakan ViewRenderer kelas . Untuk informasi selengkapnya tentang perender cepat, lihat Xamarin.Forms Perender Cepat.

Diagram berikut mengilustrasikan hubungan antara View kontrol asli terkait dan yang mengimplementasikannya:

Hubungan Antara Kelas Tampilan dan Menerapkan Kelas Asli

Proses penyajian dapat digunakan untuk mengimplementasikan penyesuaian khusus platform dengan membuat perender kustom untuk View di setiap platform. Proses untuk melakukan ini adalah sebagai berikut:

  1. BuatXamarin.Forms kontrol kustom.
  2. Gunakan kontrol kustom dari Xamarin.Forms.
  3. Buat perender kustom untuk kontrol pada setiap platform.

Setiap item sekarang akan dibahas secara bergantian, untuk mengimplementasikan perender CameraPreview yang menampilkan streaming video pratinjau dari kamera perangkat. Mengetuk streaming video akan berhenti dan memulainya.

Membuat Kontrol Kustom

Kontrol kustom dapat dibuat dengan mensubkelas View kelas, seperti yang ditunjukkan dalam contoh kode berikut:

public class CameraPreview : View
{
  public static readonly BindableProperty CameraProperty = BindableProperty.Create (
    propertyName: "Camera",
    returnType: typeof(CameraOptions),
    declaringType: typeof(CameraPreview),
    defaultValue: CameraOptions.Rear);

  public CameraOptions Camera
  {
    get { return (CameraOptions)GetValue (CameraProperty); }
    set { SetValue (CameraProperty, value); }
  }
}

CameraPreview Kontrol kustom dibuat dalam proyek pustaka .NET Standard dan menentukan API untuk kontrol. Kontrol kustom mengekspos Camera properti yang digunakan untuk mengontrol apakah aliran video harus ditampilkan dari kamera depan atau belakang pada perangkat. Jika nilai tidak ditentukan untuk Camera properti saat kontrol dibuat, nilai defaultnya adalah menentukan kamera belakang.

Mengonsumsi Kontrol Kustom

CameraPreview Kontrol kustom dapat direferensikan dalam XAML dalam proyek pustaka Standar .NET dengan mendeklarasikan namespace untuk lokasinya dan menggunakan awalan namespace pada elemen kontrol kustom. Contoh kode berikut menunjukkan bagaimana CameraPreview kontrol kustom dapat digunakan oleh halaman XAML:

<ContentPage ...
             xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
             ...>
    <StackLayout>
        <Label Text="Camera Preview:" />
        <local:CameraPreview Camera="Rear"
                             HorizontalOptions="FillAndExpand"
                             VerticalOptions="FillAndExpand" />
    </StackLayout>
</ContentPage>

local Awalan namespace dapat diberi nama apa pun. Namun, clr-namespace nilai dan assembly harus cocok dengan detail kontrol kustom. Setelah namespace dinyatakan, awalan digunakan untuk mereferensikan kontrol kustom.

Contoh kode berikut menunjukkan bagaimana CameraPreview kontrol kustom dapat dikonsumsi oleh halaman C#:

public class MainPageCS : ContentPage
{
  public MainPageCS ()
  {
    ...
    Content = new StackLayout
    {
      Children =
      {
        new Label { Text = "Camera Preview:" },
        new CameraPreview
        {
          Camera = CameraOptions.Rear,
          HorizontalOptions = LayoutOptions.FillAndExpand,
          VerticalOptions = LayoutOptions.FillAndExpand
        }
      }
    };
  }
}

Instans CameraPreview kontrol kustom akan digunakan untuk menampilkan streaming video pratinjau dari kamera perangkat. Selain menentukan nilai untuk Camera properti secara opsional, penyesuaian kontrol akan dilakukan di perender kustom.

Perender kustom sekarang dapat ditambahkan ke setiap proyek aplikasi untuk membuat kontrol pratinjau kamera khusus platform.

Membuat Perender Kustom di setiap Platform

Proses untuk membuat kelas perender kustom di iOS dan UWP adalah sebagai berikut:

  1. Buat subkelas ViewRenderer<T1,T2> kelas yang merender kontrol kustom. Argumen jenis pertama harus menjadi kontrol kustom untuk perender, dalam hal CameraPreviewini . Argumen jenis kedua harus menjadi kontrol asli yang akan mengimplementasikan kontrol kustom.
  2. Ambil alih OnElementChanged metode yang merender kontrol kustom dan logika tulis untuk menyesuaikannya. Metode ini dipanggil ketika kontrol yang Xamarin.Forms sesuai dibuat.
  3. ExportRenderer Tambahkan atribut ke kelas perender kustom untuk menentukan bahwa atribut tersebut akan digunakan untuk merender Xamarin.Forms kontrol kustom. Atribut ini digunakan untuk mendaftarkan perender kustom dengan Xamarin.Forms.

Proses untuk membuat kelas perender kustom di Android, sebagai perender cepat, adalah sebagai berikut:

  1. Buat subkelas kontrol Android yang merender kontrol kustom. Selain itu, tentukan bahwa subkelas akan mengimplementasikan IVisualElementRenderer antarmuka dan IViewRenderer .
  2. Terapkan IVisualElementRenderer antarmuka dan IViewRenderer di kelas perender cepat.
  3. ExportRenderer Tambahkan atribut ke kelas perender kustom untuk menentukan bahwa atribut tersebut akan digunakan untuk merender Xamarin.Forms kontrol kustom. Atribut ini digunakan untuk mendaftarkan perender kustom dengan Xamarin.Forms.

Catatan

Untuk sebagian besar Xamarin.Forms elemen, adalah opsional untuk menyediakan perender kustom di setiap proyek platform. Jika perender kustom tidak terdaftar, maka perender default untuk kelas dasar kontrol akan digunakan. Namun, perender kustom diperlukan di setiap proyek platform saat merender elemen Tampilan .

Diagram berikut mengilustrasikan tanggung jawab setiap proyek dalam aplikasi sampel, bersama dengan hubungan di antara mereka:

Kamera Preview Tanggung Jawab Proyek Perender Kustom

CameraPreview Kontrol kustom dirender oleh kelas perender khusus platform, yang berasal dari ViewRenderer kelas di iOS dan UWP, dan dari FrameLayout kelas di Android. Ini menghasilkan setiap CameraPreview kontrol kustom yang dirender dengan kontrol khusus platform, seperti yang ditunjukkan pada cuplikan layar berikut:

Kamera Preview di setiap Platform

Kelas ViewRenderer mengekspos OnElementChanged metode , yang dipanggil ketika Xamarin.Forms kontrol kustom dibuat untuk merender kontrol asli yang sesuai. Metode ini mengambil ElementChangedEventArgs parameter yang berisi OldElement properti dan NewElement . Properti ini mewakili Xamarin.Forms elemen tempat perender dilampirkan, dan Xamarin.Forms elemen yang dilampirkan oleh perender. Dalam aplikasi sampel, OldElement properti akan menjadi null dan NewElement properti akan berisi referensi ke CameraPreview instans.

Versi OnElementChanged metode yang ditimpa, di setiap kelas perender khusus platform, adalah tempat untuk melakukan instans dan kustomisasi kontrol asli. Metode SetNativeControl ini harus digunakan untuk membuat instans kontrol asli, dan metode ini juga akan menetapkan referensi kontrol ke Control properti . Selain itu, referensi ke Xamarin.Forms kontrol yang sedang dirender dapat diperoleh melalui Element properti .

Dalam beberapa keadaan, OnElementChanged metode ini dapat dipanggil beberapa kali. Oleh karena itu, untuk mencegah kebocoran memori, perawatan harus dilakukan saat membuat instans kontrol asli baru. Pendekatan yang digunakan saat membuat instans kontrol asli baru dalam perender kustom diperlihatkan dalam contoh kode berikut:

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

  if (e.OldElement != null)
  {
    // Unsubscribe from event handlers and cleanup any resources
  }

  if (e.NewElement != null)
  {    
    if (Control == null)
    {
      // Instantiate the native control and assign it to the Control property with
      // the SetNativeControl method
    }
    // Configure the control and subscribe to event handlers
  }
}

Kontrol asli baru hanya boleh dibuat sekali, ketika Control properti adalah null. Selain itu, kontrol hanya boleh dibuat, dikonfigurasi, dan penanganan aktivitas berlangganan saat perender kustom dilampirkan ke elemen baru Xamarin.Forms . Demikian pula, setiap penanganan aktivitas yang berlangganan hanya boleh dihentikan langganannya ketika elemen yang dilampirkan oleh perender dilampirkan ke perubahan. Mengadopsi pendekatan ini akan membantu membuat perender kustom berkinerja yang tidak menderita kebocoran memori.

Penting

Metode SetNativeControl hanya boleh dipanggil jika e.NewElement bukan null.

Setiap kelas perender kustom dihiasi dengan ExportRenderer atribut yang mendaftarkan perender dengan Xamarin.Forms. Atribut mengambil dua parameter – nama jenis kontrol kustom yang Xamarin.Forms dirender, dan nama jenis perender kustom. assembly Awalan ke atribut menentukan bahwa atribut berlaku untuk seluruh rakitan.

Bagian berikut membahas implementasi setiap kelas perender kustom khusus platform.

Membuat Perender Kustom di iOS

Contoh kode berikut menunjukkan perender kustom untuk platform iOS:

[assembly: ExportRenderer (typeof(CameraPreview), typeof(CameraPreviewRenderer))]
namespace CustomRenderer.iOS
{
    public class CameraPreviewRenderer : ViewRenderer<CameraPreview, UICameraPreview>
    {
        UICameraPreview uiCameraPreview;

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

            if (e.OldElement != null) {
                // Unsubscribe
                uiCameraPreview.Tapped -= OnCameraPreviewTapped;
            }
            if (e.NewElement != null) {
                if (Control == null) {
                  uiCameraPreview = new UICameraPreview (e.NewElement.Camera);
                  SetNativeControl (uiCameraPreview);
                }
                // Subscribe
                uiCameraPreview.Tapped += OnCameraPreviewTapped;
            }
        }

        void OnCameraPreviewTapped (object sender, EventArgs e)
        {
            if (uiCameraPreview.IsPreviewing) {
                uiCameraPreview.CaptureSession.StopRunning ();
                uiCameraPreview.IsPreviewing = false;
            } else {
                uiCameraPreview.CaptureSession.StartRunning ();
                uiCameraPreview.IsPreviewing = true;
            }
        }
        ...
    }
}

Control Asalkan properti adalah null, SetNativeControl metode ini dipanggil untuk membuat instans kontrol baru UICameraPreview dan untuk menetapkan referensi ke Control properti . Kontrol UICameraPreview adalah kontrol kustom khusus platform yang menggunakan AVCapture API untuk menyediakan aliran pratinjau dari kamera. Ini mengekspos Tapped peristiwa yang ditangani oleh OnCameraPreviewTapped metode untuk menghentikan dan memulai pratinjau video saat diketuk. Peristiwa Tapped ini berlangganan ketika perender kustom dilampirkan ke elemen baru Xamarin.Forms , dan berhenti berlangganan hanya ketika elemen perender dilampirkan ke perubahan.

Membuat Custom Renderer di Android

Contoh kode berikut menunjukkan perender cepat untuk platform Android:

[assembly: ExportRenderer(typeof(CustomRenderer.CameraPreview), typeof(CameraPreviewRenderer))]
namespace CustomRenderer.Droid
{
    public class CameraPreviewRenderer : FrameLayout, IVisualElementRenderer, IViewRenderer
    {
        // ...
        CameraPreview element;
        VisualElementTracker visualElementTracker;
        VisualElementRenderer visualElementRenderer;
        FragmentManager fragmentManager;
        CameraFragment cameraFragment;

        FragmentManager FragmentManager => fragmentManager ??= Context.GetFragmentManager();

        public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
        public event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;

        CameraPreview Element
        {
            get => element;
            set
            {
                if (element == value)
                {
                    return;
                }

                var oldElement = element;
                element = value;
                OnElementChanged(new ElementChangedEventArgs<CameraPreview>(oldElement, element));
            }
        }

        public CameraPreviewRenderer(Context context) : base(context)
        {
            visualElementRenderer = new VisualElementRenderer(this);
        }

        void OnElementChanged(ElementChangedEventArgs<CameraPreview> e)
        {
            CameraFragment newFragment = null;

            if (e.OldElement != null)
            {
                e.OldElement.PropertyChanged -= OnElementPropertyChanged;
                cameraFragment.Dispose();
            }
            if (e.NewElement != null)
            {
                this.EnsureId();

                e.NewElement.PropertyChanged += OnElementPropertyChanged;

                ElevationHelper.SetElevation(this, e.NewElement);
                newFragment = new CameraFragment { Element = element };
            }

            FragmentManager.BeginTransaction()
                .Replace(Id, cameraFragment = newFragment, "camera")
                .Commit();
            ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(e.OldElement, e.NewElement));
        }

        async void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            ElementPropertyChanged?.Invoke(this, e);

            switch (e.PropertyName)
            {
                case "Width":
                    await cameraFragment.RetrieveCameraDevice();
                    break;
            }
        }       
        // ...
    }
}

Dalam contoh ini, OnElementChanged metode membuat CameraFragment objek, asalkan perender kustom dilampirkan ke elemen baru Xamarin.Forms . Jenisnya CameraFragment adalah kelas kustom yang menggunakan Camera2 API untuk menyediakan aliran pratinjau dari kamera. Objek CameraFragment dibuang ketika elemen perender Xamarin.Forms dilampirkan ke perubahan.

Membuat Perender Kustom di UWP

Contoh kode berikut menunjukkan perender kustom untuk UWP:

[assembly: ExportRenderer(typeof(CameraPreview), typeof(CameraPreviewRenderer))]
namespace CustomRenderer.UWP
{
    public class CameraPreviewRenderer : ViewRenderer<CameraPreview, Windows.UI.Xaml.Controls.CaptureElement>
    {
        ...
        CaptureElement _captureElement;
        bool _isPreviewing;

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

            if (e.OldElement != null)
            {
                // Unsubscribe
                Tapped -= OnCameraPreviewTapped;
                ...
            }
            if (e.NewElement != null)
            {
                if (Control == null)
                {
                  ...
                  _captureElement = new CaptureElement();
                  _captureElement.Stretch = Stretch.UniformToFill;

                  SetupCamera();
                  SetNativeControl(_captureElement);
                }
                // Subscribe
                Tapped += OnCameraPreviewTapped;
            }
        }

        async void OnCameraPreviewTapped(object sender, TappedRoutedEventArgs e)
        {
            if (_isPreviewing)
            {
                await StopPreviewAsync();
            }
            else
            {
                await StartPreviewAsync();
            }
        }
        ...
    }
}

Control Asalkan properti adalah null, yang baru CaptureElement dibuat dan SetupCamera metode dipanggil, yang menggunakan MediaCapture API untuk menyediakan streaming pratinjau dari kamera. Metode SetNativeControl ini kemudian dipanggil untuk menetapkan referensi ke CaptureElement instans ke Control properti . Kontrol CaptureElement mengekspos Tapped peristiwa yang ditangani oleh OnCameraPreviewTapped metode untuk menghentikan dan memulai pratinjau video saat diketuk. Peristiwa Tapped ini berlangganan ketika perender kustom dilampirkan ke elemen baru Xamarin.Forms , dan berhenti berlangganan hanya ketika elemen perender dilampirkan ke perubahan.

Catatan

Penting untuk menghentikan dan membuang objek yang menyediakan akses ke kamera dalam aplikasi UWP. Kegagalan untuk melakukannya dapat mengganggu aplikasi lain yang mencoba mengakses kamera perangkat. Untuk informasi selengkapnya, lihat Menampilkan pratinjau kamera.

Ringkasan

Artikel ini telah menunjukkan cara membuat perender kustom untuk Xamarin.Forms kontrol kustom yang digunakan untuk menampilkan streaming video pratinjau dari kamera perangkat. Xamarin.Forms kontrol antarmuka pengguna kustom harus berasal dari View kelas , yang digunakan untuk menempatkan tata letak dan kontrol di layar.