Personalizzazione di un elemento ContentPage

ContentPage è un elemento visivo con visualizzazione singola che occupa la maggior parte dello schermo. Questo articolo illustra come creare un renderer personalizzato per la pagina ContentPage che consente agli sviluppatori di eseguire l'override del rendering nativo predefinito usando una personalizzazione specifica della piattaforma.

Ogni Xamarin.Forms controllo ha un renderer a corredo per ogni piattaforma che crea un'istanza di un controllo nativo. ContentPage Quando un oggetto viene sottoposto a rendering da un'applicazioneXamarin.Forms, in iOS viene creata un'istanza della PageRenderer classe , che a sua volta crea un'istanza di un controllo nativoUIViewController. Nella piattaforma Android la classe PageRenderer crea un'istanza di un controllo ViewGroup. Nella piattaforma UWP (Universal Windows Platform) la classe PageRenderer crea un'istanza di un controllo FrameworkElement. Per altre informazioni sulle classi di controllo native e del renderer a cui Xamarin.Forms viene eseguito il mapping dei controlli, vedere Classi di base del renderer e controlli nativi.

Il diagramma seguente illustra la relazione tra la classe ContentPage e i controlli nativi corrispondenti che la implementano:

Relazione tra la classe ContentPage e i controlli nativi che la implementano

È possibile sfruttare il processo di rendering per implementare personalizzazioni specifiche della piattaforma creando un renderer personalizzato per una classe ContentPage in ogni piattaforma. Il processo per eseguire questa operazione è il seguente:

  1. Creare una Xamarin.Forms pagina.
  2. Utilizzare la pagina da Xamarin.Forms.
  3. Creare il renderer personalizzato per la pagina in ogni piattaforma.

Verrà ora discusso un elemento alla volta per implementare un oggetto CameraPage che rende disponibile un feed di fotocamera live e la possibilità di scattare una foto.

Creazione della Xamarin.Forms pagina

Un oggetto non modificato ContentPage può essere aggiunto al progetto condiviso Xamarin.Forms , come illustrato nell'esempio di codice XAML seguente:

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

In modo analogo, anche il file code-behind per l'oggetto ContentPage deve rimanere invariato, come illustrato nell'esempio di codice seguente:

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

L'esempio di codice seguente illustra come creare la pagina in C#:

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

Per visualizzare il feed di fotocamera live in ogni piattaforma verrà usata un'istanza di CameraPage. La personalizzazione del controllo avviene nel renderer personalizzato. Non è pertanto necessaria alcuna implementazione aggiuntiva nella classe CameraPage.

Utilizzo della Xamarin.Forms pagina

Il valore vuoto CameraPage deve essere visualizzato dall'applicazione Xamarin.Forms . Ciò accade quando si tocca un pulsante nell'istanza di MainPage che a sua volta esegue il metodo OnTakePhotoButtonClicked, come illustrato nell'esempio di codice seguente:

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

Questo codice passa semplicemente all'oggetto CameraPage nel quale i renderer personalizzati personalizzeranno l'aspetto della pagina in ogni piattaforma.

Creazione del renderer di pagina in ogni piattaforma

Il processo di creazione della classe di renderer personalizzato è il seguente:

  1. Creare una sottoclasse della classe PageRenderer.
  2. Eseguire l'override del metodo OnElementChanged che esegue il rendering della pagina nativa e scrivere la logica per personalizzare la pagina. Il OnElementChanged metodo viene chiamato quando viene creato il controllo corrispondente Xamarin.Forms .
  3. Aggiungere un ExportRenderer attributo alla classe renderer di pagina per specificare che verrà usato per eseguire il rendering della Xamarin.Forms pagina. Questo attributo viene usato per registrare il renderer personalizzato con Xamarin.Forms.

Nota

La specifica di un renderer di pagina nel progetto di ogni piattaforma è facoltativa. Se non si registra un renderer personalizzato, verrà usato il renderer predefinito per la pagina.

Il diagramma seguente illustra le responsabilità di ogni progetto nell'applicazione di esempio, insieme alla relazione tra di esse:

Responsabilità del progetto di renderer personalizzato CameraPage

Il rendering dell'istanza di CameraPage viene eseguito dalle classi CameraPageRenderer specifiche della piattaforma che derivano tutte dalla classe PageRenderer per la piattaforma. Ciò determina il rendering di ogni istanza di CameraPage con un feed di fotocamera live, come illustrato negli screenshot seguenti:

CameraPage in ogni piattaforma

La PageRenderer classe espone il OnElementChanged metodo , che viene chiamato quando viene creata la pagina per eseguire il Xamarin.Forms rendering del controllo nativo corrispondente. Questo metodo accetta un parametro ElementChangedEventArgs che contiene le proprietà OldElement e NewElement. Queste proprietà rappresentano l'elemento Xamarin.Forms a cui è stato associato il renderer e l'elemento Xamarin.Forms a cui è associato il renderer. Nell'applicazione di esempio la proprietà OldElement sarà null e la proprietà NewElement conterrà un riferimento all'istanza di CameraPage.

La personalizzazione della pagina nativa deve essere eseguita in una versione sostituita del metodo OnElementChanged nella classe CameraPageRenderer. È possibile ottenere un riferimento all'istanza Xamarin.Forms della pagina di cui viene eseguito il rendering tramite la Element proprietà .

Ogni classe renderer personalizzata è decorata con un ExportRenderer attributo che registra il renderer con Xamarin.Forms. L'attributo accetta due parametri: il nome del tipo della pagina di cui viene eseguito il Xamarin.Forms rendering e il nome del tipo del renderer personalizzato. Il prefisso assembly dell'attributo specifica che l'attributo viene applicato all'intero assembly.

Le sezioni seguenti illustrano l'implementazione del renderer personalizzato CameraPageRenderer per ogni piattaforma.

Creazione del renderer di pagina in iOS

L'esempio di codice seguente illustra il renderer di pagina per la piattaforma 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);
            }
        }
        ...
    }
}

La chiamata al metodo OnElementChanged della classe di base crea un'istanza di un controllo UIViewController iOS. Il rendering del flusso della fotocamera live viene eseguito solo a condizione che il renderer non sia già collegato a un elemento esistente Xamarin.Forms e a condizione che esista un'istanza di pagina di cui viene eseguito il rendering dal renderer personalizzato.

La pagina viene quindi personalizzata da una serie di metodi che usano le API AVCapture per consentire lo streaming live dalla fotocamera e la possibilità di scattare una foto.

Creazione del renderer di pagina in Android

L'esempio di codice seguente illustra il renderer di pagina per la piattaforma 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);
            }
        }
        ...
    }
}

La chiamata al metodo OnElementChanged della classe di base crea un'istanza di un controllo ViewGroup Android, ovvero un gruppo di visualizzazioni. Il rendering del flusso della fotocamera live viene eseguito solo a condizione che il renderer non sia già collegato a un elemento esistente Xamarin.Forms e a condizione che esista un'istanza di pagina di cui viene eseguito il rendering dal renderer personalizzato.

La pagina viene quindi personalizzata richiamando una serie di metodi che usano l'API Camera per consentire lo streaming live dalla fotocamera e la possibilità di scattare una foto prima che venga richiamato il metodo AddView per aggiungere l'interfaccia utente dello streaming live della fotocamera al controllo ViewGroup. Tenere presente che in Android è anche necessario eseguire l'override del metodo OnLayout per eseguire operazioni di misura e layout nella visualizzazione.

Creazione del renderer di pagina in UWP

L'esempio di codice seguente illustra il renderer di pagina per la piattaforma 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;
        }
        ...
    }
}

La chiamata al metodo OnElementChanged della classe di base crea un'istanza di un controllo FrameworkElement in cui viene eseguito il rendering della pagina. Il rendering del flusso della fotocamera live viene eseguito solo a condizione che il renderer non sia già collegato a un elemento esistente Xamarin.Forms e a condizione che esista un'istanza di pagina di cui viene eseguito il rendering dal renderer personalizzato. La pagina viene quindi personalizzata richiamando una serie di metodi che usano l'API MediaCapture per consentire lo streaming live dalla fotocamera e la possibilità di scattare una foto prima che la pagina personalizzata sia aggiunta alla raccolta Children per la visualizzazione.

Quando si implementa un renderer personalizzato che deriva da PageRenderer in UWP, è consigliabile implementare anche il metodo ArrangeOverride per disporre i controlli della pagina perché il renderer di base non è in grado di eseguire questa operazione. In caso contrario, verrà restituita una pagina vuota. In questo esempio il metodo ArrangeOverride chiama pertanto il metodo Arrange sull'istanza Page.

Nota

In un'applicazione UWP è importante arrestare ed eliminare gli oggetti che consentono l'accesso alla fotocamera. Questi possono infatti interferire con altre applicazioni che tentano di accedere alla fotocamera del dispositivo. Per altre informazioni, vedere Display the camera preview (Visualizzare l'anteprima della fotocamera).

Riepilogo

Questo articolo ha illustrato come creare un renderer personalizzato per la pagina ContentPage che consente agli sviluppatori di eseguire l'override del rendering nativo predefinito usando una personalizzazione specifica della piattaforma. ContentPage è un elemento visivo con visualizzazione singola che occupa la maggior parte dello schermo.