Implémentation d’une vue
Xamarin.Forms les contrôles d’interface utilisateur personnalisés doivent dériver de la classe View, qui est utilisée pour placer les dispositions et les contrôles à l’écran. Cet article explique comment créer un renderer personnalisé pour un Xamarin.Forms contrôle personnalisé utilisé pour afficher un flux vidéo en préversion à partir de l’appareil photo de l’appareil.
Chaque Xamarin.Forms vue a un renderer d’accompagnement pour chaque plateforme qui crée une instance d’un contrôle natif. Quand un View
est rendu par une Xamarin.Forms application dans iOS, la ViewRenderer
classe est instanciée, ce qui instancie à son tour un contrôle natif UIView
. Sur la plateforme Android, la classe ViewRenderer
instancie un contrôle View
natif. Sur la plateforme Windows universelle (UWP), la classe ViewRenderer
instancie un contrôle FrameworkElement
natif. Pour plus d’informations sur le convertisseur et les classes de contrôle natifs qui contrôlent Xamarin.Forms la correspondance, consultez Classes de base du convertisseur et Contrôles natifs.
Notes
Certains contrôles sur Android utilisent des convertisseurs rapides, qui ne consomment pas la ViewRenderer
classe . Pour plus d’informations sur les convertisseurs rapides, consultez Xamarin.Forms Fast Renderers.
Le diagramme suivant illustre la relation entre l’élément View
et les contrôles natifs correspondants qui l’implémentent :
Il est possible d’utiliser le processus de rendu pour implémenter des personnalisations spécifiques à la plateforme en créant un renderer personnalisé pour un élément View
sur chaque plateforme. Le processus pour y parvenir est le suivant :
- Créez un Xamarin.Forms contrôle personnalisé.
- Consommez le contrôle personnalisé à partir de Xamarin.Forms.
- Créez le renderer personnalisé pour le contrôle sur chaque plateforme.
Chaque élément va maintenant être abordé tour à tour, afin d’implémenter un renderer CameraPreview
qui affiche un flux vidéo d’aperçu à partir de la caméra de l’appareil. Le fait d’appuyer sur le flux vidéo l’arrête et le démarre.
Création du contrôle personnalisé
Un contrôle personnalisé peut être créé en sous-classant la View
classe, comme indiqué dans l’exemple de code suivant :
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); }
}
}
Le contrôle personnalisé CameraPreview
est créé dans le projet de bibliothèque .NET Standard et définit l’API pour le contrôle. Le contrôle personnalisé expose une propriété Camera
qui est utilisée pour contrôler si le flux vidéo doit être affiché à partir de la caméra avant ou arrière de l’appareil. Si aucune valeur n’est spécifiée pour la propriété Camera
lors de la création du contrôle, la caméra arrière est spécifiée par défaut.
Consommation du contrôle personnalisé
Vous pouvez référencer le contrôle personnalisé CameraPreview
en XAML dans le projet de bibliothèque .NET Standard en déclarant un espace de noms pour son emplacement et en utilisant le préfixe d’espace de noms sur l’élément de contrôle personnalisé. L’exemple de code suivant montre comment le contrôle personnalisé CameraPreview
peut être consommé par une page XAML :
<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
<StackLayout>
<Label Text="Camera Preview:" />
<local:CameraPreview Camera="Rear"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand" />
</StackLayout>
</ContentPage>
Le préfixe d’espace de noms local
peut porter n’importe quel nom. Toutefois, les valeurs clr-namespace
et assembly
doivent correspondre aux détails du contrôle personnalisé. Une fois l’espace de noms déclaré, le préfixe est utilisé pour référencer le contrôle personnalisé.
L’exemple de code suivant montre comment le contrôle personnalisé CameraPreview
peut être consommé par une page 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
}
}
};
}
}
Une instance du contrôle personnalisé CameraPreview
est utilisée pour afficher le flux vidéo d’aperçu à partir de la caméra de l’appareil. Indépendamment de la spécification éventuelle d’une valeur pour la propriété Camera
, la personnalisation du contrôle est effectuée dans le renderer personnalisé.
Un renderer personnalisé peut maintenant être ajouté à chaque projet d’application pour créer des contrôles d’aperçu de la caméra spécifiques à la plateforme.
Création du renderer personnalisé sur chaque plateforme
Le processus de création de la classe de renderer personnalisé sur iOS et UWP est le suivant :
- Créez une sous-classe de la classe
ViewRenderer<T1,T2>
qui restitue le contrôle personnalisé. Le premier argument de type doit être le contrôle personnalisé auquel le renderer est destiné ; dans le cas présent,CameraPreview
. Le deuxième argument de type doit être le contrôle natif qui implémentera le contrôle personnalisé. - Remplacez la méthode
OnElementChanged
qui restitue le contrôle personnalisé et écrivez une logique pour le personnaliser. Cette méthode est appelée lors de la création du contrôle correspondant Xamarin.Forms . - Ajoutez un
ExportRenderer
attribut à la classe de renderer personnalisé pour spécifier qu’il sera utilisé pour afficher le Xamarin.Forms contrôle personnalisé. Cet attribut est utilisé pour inscrire le convertisseur personnalisé auprès de Xamarin.Forms.
Le processus de création de la classe de renderer personnalisé sur Android, en tant que convertisseur rapide, est le suivant :
- Créez une sous-classe du contrôle Android qui restitue le contrôle personnalisé. En outre, spécifiez que la sous-classe implémente les
IVisualElementRenderer
interfaces etIViewRenderer
. - Implémentez les
IVisualElementRenderer
interfaces etIViewRenderer
dans la classe fast renderer. - Ajoutez un
ExportRenderer
attribut à la classe de renderer personnalisé pour spécifier qu’il sera utilisé pour afficher le Xamarin.Forms contrôle personnalisé. Cet attribut est utilisé pour inscrire le convertisseur personnalisé auprès de Xamarin.Forms.
Notes
Pour la plupart des Xamarin.Forms éléments, il est facultatif de fournir un renderer personnalisé dans chaque projet de plateforme. Si un renderer personnalisé n’est pas inscrit, le renderer par défaut de la classe de base du contrôle est utilisé. Toutefois, les renderers personnalisés sont nécessaires dans chaque projet de plateforme lors du rendu d’un élément View.
Le diagramme suivant illustre les responsabilités de chaque projet dans l’exemple d’application ainsi que les relations qu’ils entretiennent les uns avec les autres :
Le CameraPreview
contrôle personnalisé est rendu par des classes de renderer spécifiques à la plateforme, qui dérivent de la ViewRenderer
classe sur iOS et UWP, et de la FrameLayout
classe sur Android. Il en résulte le rendu de chaque contrôle personnalisé CameraPreview
avec des contrôles spécifiques à la plateforme, comme le montrent les captures d’écran suivantes :
La ViewRenderer
classe expose la OnElementChanged
méthode, qui est appelée lorsque le Xamarin.Forms contrôle personnalisé est créé pour afficher le contrôle natif correspondant. Cette méthode prend un paramètre ElementChangedEventArgs
qui contient les propriétés OldElement
et NewElement
. Ces propriétés représentent l’élément Xamarin.Forms auquel le convertisseur a été attaché et l’élément Xamarin.Forms auquel le convertisseur est attaché, respectivement. Dans l’exemple d’application, la propriété OldElement
sera null
et la propriété NewElement
contiendra une référence à l’instance CameraPreview
.
Une version substituée de la méthode OnElementChanged
, dans chaque classe de renderer spécifique à la plateforme, est l’emplacement où effectuer l’instanciation et la personnalisation du contrôle natif. La méthode SetNativeControl
doit être utilisée pour instancier le contrôle natif, et cette méthode affecte également la référence de contrôle à la propriété Control
. En outre, une référence au Xamarin.Forms contrôle en cours de rendu peut être obtenue via la Element
propriété .
Dans certains cas, la méthode OnElementChanged
peut être appelée plusieurs fois. Ainsi, pour éviter les fuites de mémoire, vous devez être vigilant au moment de l’instanciation d’un nouveau contrôle natif. L’approche à utiliser lors de l’instanciation d’un nouveau contrôle natif dans un renderer personnalisé est indiquée dans l’exemple de code suivant :
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
}
}
Un nouveau contrôle natif doit uniquement être instancié une seule fois, quand la propriété Control
a la valeur null
. En outre, le contrôle doit être créé, configuré et les gestionnaires d’événements abonnés uniquement lorsque le convertisseur personnalisé est attaché à un nouvel Xamarin.Forms élément. De même, vous devez vous désabonner de tous les gestionnaires d’événements auxquels vous vous êtes abonné uniquement quand l’élément auquel le renderer est attaché change. Le choix de cette approche permet de créer un renderer personnalisé performant qui ne subit pas de fuites de mémoire.
Important
La méthode SetNativeControl
doit uniquement être appelée si e.NewElement
n’est pas null
.
Chaque classe de renderer personnalisé est décorée avec un ExportRenderer
attribut qui inscrit le renderer avec Xamarin.Forms. L’attribut accepte deux paramètres : le nom de type du Xamarin.Forms contrôle personnalisé en cours de rendu et le nom de type du convertisseur personnalisé. Le préfixe assembly
de l’attribut spécifie que l’attribut s’applique à la totalité de l’assembly.
Les sections suivantes décrivent l’implémentation de chaque classe de renderer personnalisé spécifique à la plateforme.
Création du renderer personnalisé sur iOS
L’exemple de code suivant illustre le renderer personnalisé pour la plateforme 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;
}
}
...
}
}
Sous réserve que la propriété Control
ait la valeur null
, la méthode SetNativeControl
est appelée pour instancier un nouveau contrôle UICameraPreview
et lui affecter une référence à la propriété Control
. Le contrôle UICameraPreview
est un contrôle personnalisé spécifique à la plateforme qui utilise les API AVCapture
pour fournir le flux de l’aperçu de la caméra. Il expose un événement Tapped
qui est géré par la méthode OnCameraPreviewTapped
pour arrêter et démarrer l’aperçu vidéo quand l’utilisateur appuie dessus. L’événement Tapped
est abonné lorsque le renderer personnalisé est attaché à un nouvel Xamarin.Forms élément, et est annulé uniquement lorsque l’élément auquel le convertisseur est attaché est modifié.
Création du renderer personnalisé sur Android
L’exemple de code suivant montre le convertisseur rapide pour la plateforme 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;
}
}
// ...
}
}
Dans cet exemple, la OnElementChanged
méthode crée un CameraFragment
objet, à condition que le convertisseur personnalisé soit attaché à un nouvel Xamarin.Forms élément. Le CameraFragment
type est une classe personnalisée qui utilise l’API Camera2
pour fournir le flux d’aperçu à partir de l’appareil photo. L’objet CameraFragment
est supprimé lorsque l’élément Xamarin.Forms auquel le convertisseur est attaché change.
Création du renderer personnalisé sur UWP
L’exemple de code suivant illustre le renderer personnalisé pour 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();
}
}
...
}
}
Sous réserve que la propriété Control
ait la valeur null
, un nouveau CaptureElement
est instancié et la méthode SetupCamera
est appelée, entraînant l’utilisation de l’API MediaCapture
afin de fournir le flux d’aperçu à partir de la caméra. La méthode SetNativeControl
est ensuite appelée pour affecter une référence à l’instance CaptureElement
à la propriété Control
. Le contrôle CaptureElement
expose un événement Tapped
qui est géré par la méthode OnCameraPreviewTapped
pour arrêter et démarrer l’aperçu vidéo quand l’utilisateur appuie dessus. L’événement Tapped
est abonné lorsque le renderer personnalisé est attaché à un nouvel Xamarin.Forms élément, et est annulé uniquement lorsque l’élément auquel le convertisseur est attaché est modifié.
Notes
Il est important d’arrêter et de supprimer les objets qui fournissent un accès à la caméra dans une application UWP. Si vous ne le faites pas, il peut se produire une interférence avec d’autres applications qui tentent d’accéder à la caméra de l’appareil. Pour plus d’informations, consultez Afficher l’aperçu de la caméra.
Résumé
Cet article a montré comment créer un renderer personnalisé pour un Xamarin.Forms contrôle personnalisé qui est utilisé pour afficher un flux vidéo en préversion à partir de la caméra de l’appareil. Xamarin.Forms les contrôles d’interface utilisateur personnalisés doivent dériver de la View
classe , qui est utilisée pour placer les dispositions et les contrôles à l’écran.