Création de contrôles personnalisés dans Xamarin.Mac
Lorsque vous utilisez C# et .NET dans une application Xamarin.Mac, vous avez accès aux mêmes contrôles utilisateur qu’un développeur travaillant dans Objective-C, Swift et Xcode . Étant donné que Xamarin.Mac s’intègre directement à Xcode, vous pouvez utiliser le Générateur d’interface de Xcode pour créer et gérer vos contrôles utilisateur (ou éventuellement les créer directement dans le code C#).
Bien que macOS offre une grande quantité de contrôles utilisateur intégrés, il peut arriver que vous deviez créer un contrôle personnalisé pour fournir des fonctionnalités non fournies prêtes à l’emploi ou pour correspondre à un thème d’interface utilisateur personnalisé (par exemple, une interface de jeu).
Dans cet article, nous allons aborder les principes fondamentaux de la création d’un contrôle d’interface utilisateur personnalisé réutilisable dans une application Xamarin.Mac. Il est fortement suggéré que vous travaillez tout d’abord dans l’article Hello, Mac , en particulier les sections Introduction to Xcode and Interface Builder et Outlets and Actions , car elle couvre les concepts et techniques clés que nous utiliserons dans cet article.
Vous pouvez également examiner les classes /méthodes C# exposantes dans Objective-Cla section du document interne Xamarin.Mac, ainsi que les Register
Export
instructions utilisées pour connecter vos classes C# à des objets et des Objective-C éléments d’interface utilisateur.
Présentation des contrôles personnalisés
Comme indiqué ci-dessus, il peut arriver que vous deviez créer un contrôle d’interface utilisateur personnalisé réutilisable pour fournir des fonctionnalités uniques pour l’interface utilisateur de votre application Xamarin.Mac ou pour créer un thème d’interface utilisateur personnalisé (par exemple, une interface de jeu).
Dans ces situations, vous pouvez facilement hériter d’un NSControl
outil personnalisé qui peut être ajouté à l’interface utilisateur de votre application via du code C# ou via le Générateur d’interface de Xcode. En hériter de NSControl
votre contrôle personnalisé aura automatiquement toutes les fonctionnalités standard qu’un contrôle d’interface utilisateur intégré a (par NSButton
exemple).
Si votre contrôle d’interface utilisateur personnalisé affiche simplement des informations (comme un graphique personnalisé et un outil graphique), vous souhaiterez peut-être hériter au NSView
lieu de NSControl
.
Quelle que soit la classe de base utilisée, les étapes de base de la création d’un contrôle personnalisé sont identiques.
Dans cet article, créez un composant Flip Switch personnalisé qui fournit un thème d’interface utilisateur unique et un exemple de création d’un contrôle d’interface utilisateur personnalisé entièrement fonctionnel.
Génération du contrôle personnalisé
Étant donné que le contrôle personnalisé que nous créons répond à l’entrée utilisateur (clics sur le bouton gauche de la souris), nous allons hériter de NSControl
. De cette façon, notre contrôle personnalisé aura automatiquement toutes les fonctionnalités standard qu’un contrôle d’interface utilisateur intégré a et répond comme un contrôle macOS standard.
Dans Visual Studio pour Mac, ouvrez le projet Xamarin.Mac pour lequel vous souhaitez créer un contrôle d’interface utilisateur personnalisé (ou en créer un). Ajoutez une nouvelle classe et appelez-la NSFlipSwitch
:
Ensuite, modifiez la classe et faites-la NSFlipSwitch.cs
ressembler à ce qui suit :
using Foundation;
using System;
using System.CodeDom.Compiler;
using AppKit;
using CoreGraphics;
namespace MacCustomControl
{
[Register("NSFlipSwitch")]
public class NSFlipSwitch : NSControl
{
#region Private Variables
private bool _value = false;
#endregion
#region Computed Properties
public bool Value {
get { return _value; }
set {
// Save value and force a redraw
_value = value;
NeedsDisplay = true;
}
}
#endregion
#region Constructors
public NSFlipSwitch ()
{
// Init
Initialize();
}
public NSFlipSwitch (IntPtr handle) : base (handle)
{
// Init
Initialize();
}
[Export ("initWithFrame:")]
public NSFlipSwitch (CGRect frameRect) : base(frameRect) {
// Init
Initialize();
}
private void Initialize() {
this.WantsLayer = true;
this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
}
#endregion
#region Draw Methods
public override void DrawRect (CGRect dirtyRect)
{
base.DrawRect (dirtyRect);
// Use Core Graphic routines to draw our UI
...
}
#endregion
#region Private Methods
private void FlipSwitchState() {
// Update state
Value = !Value;
}
#endregion
}
}
La première chose à noter sur notre classe personnalisée dans laquelle nous hériteons et l’utilisation de NSControl
la commande Register pour exposer cette classe au Générateur d’interface de Xcode et à Objective-C xcode :
[Register("NSFlipSwitch")]
public class NSFlipSwitch : NSControl
Dans les sections suivantes, nous allons examiner en détail le reste du code ci-dessus.
Suivi de l’état du contrôle
Étant donné que notre contrôle personnalisé est un commutateur, nous avons besoin d’un moyen de suivre l’état activé/désactivé du commutateur. Nous gérons cela avec le code suivant dans NSFlipSwitch
:
private bool _value = false;
...
public bool Value {
get { return _value; }
set {
// Save value and force a redraw
_value = value;
NeedsDisplay = true;
}
}
Lorsque l’état du commutateur change, nous avons besoin d’un moyen de mettre à jour l’interface utilisateur. Nous le faisons en forçant le contrôle à redessiner son interface utilisateur avec NeedsDisplay = true
.
Si notre contrôle nécessitait plus qu’un seul état activé/désactivé (par exemple, un commutateur à plusieurs états avec 3 positions), nous aurions pu utiliser une énumération pour suivre l’état. Pour notre exemple, un simple bool fera.
Nous avons également ajouté une méthode d’assistance pour échanger l’état du commutateur entre Activé et Désactivé :
private void FlipSwitchState() {
// Update state
Value = !Value;
}
Plus tard, nous allons développer cette classe d’assistance pour informer l’appelant lorsque l’état des commutateurs a changé.
Dessin de l’interface du contrôle
Nous allons utiliser des routines de dessin Core Graphic pour dessiner l’interface utilisateur de notre contrôle personnalisé au moment de l’exécution. Avant de pouvoir le faire, nous devons activer des couches pour notre contrôle. Nous procédons ainsi avec la méthode privée suivante :
private void Initialize() {
this.WantsLayer = true;
this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
}
Cette méthode est appelée à partir de chacun des constructeurs du contrôle pour s’assurer que le contrôle est correctement configuré. Par exemple :
public NSFlipSwitch (IntPtr handle) : base (handle)
{
// Init
Initialize();
}
Ensuite, nous devons remplacer la DrawRect
méthode et ajouter les routines Core Graphic pour dessiner le contrôle :
public override void DrawRect (CGRect dirtyRect)
{
base.DrawRect (dirtyRect);
// Use Core Graphic routines to draw our UI
...
}
Nous allons ajuster la représentation visuelle du contrôle lorsque son état change (par exemple, passer de Activé à Désactivé). Chaque fois que l’état change, nous pouvons utiliser la NeedsDisplay = true
commande pour forcer le contrôle à redessiner pour le nouvel état.
Réponse à l’entrée utilisateur
Il existe deux façons de base d’ajouter une entrée utilisateur à notre contrôle personnalisé : remplacer les routines de gestion de la souris ou les modules de reconnaissance des mouvements. Quelle méthode nous utilisons, sera basée sur les fonctionnalités requises par notre contrôle.
Important
Pour tout contrôle personnalisé que vous créez, vous devez utiliser les méthodes de remplacement ou les reconnaissances de mouvement, mais pas les deux en même temps qu’ils peuvent entrer en conflit entre eux.
Gestion des entrées utilisateur avec des méthodes de remplacement
Les objets qui héritent de (ouNSView
) ont plusieurs méthodes de NSControl
remplacement pour gérer l’entrée de la souris ou du clavier. Pour notre exemple de contrôle, nous voulons retourner l’état du commutateur entre Activé et Désactivé lorsque l’utilisateur clique sur le contrôle avec le bouton gauche de la souris. Nous pouvons ajouter les méthodes de remplacement suivantes à la NSFlipSwitch
classe pour gérer ceci :
#region Mouse Handling Methods
// --------------------------------------------------------------------------------
// Handle mouse with Override Methods.
// NOTE: Use either this method or Gesture Recognizers, NOT both!
// --------------------------------------------------------------------------------
public override void MouseDown (NSEvent theEvent)
{
base.MouseDown (theEvent);
FlipSwitchState ();
}
public override void MouseDragged (NSEvent theEvent)
{
base.MouseDragged (theEvent);
}
public override void MouseUp (NSEvent theEvent)
{
base.MouseUp (theEvent);
}
public override void MouseMoved (NSEvent theEvent)
{
base.MouseMoved (theEvent);
}
## endregion
Dans le code ci-dessus, nous appelons la FlipSwitchState
méthode (définie ci-dessus) pour retourner l’état On/Off du commutateur dans la MouseDown
méthode. Cela force également le contrôle à redessiner pour refléter l’état actuel.
Gestion des entrées utilisateur avec des modules de reconnaissance de mouvement
Si vous le souhaitez, vous pouvez utiliser des reconnaissances de mouvement pour gérer l’interaction de l’utilisateur avec le contrôle. Supprimez les remplacements ajoutés ci-dessus, modifiez la Initialize
méthode et faites-la ressembler à ce qui suit :
private void Initialize() {
this.WantsLayer = true;
this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
// --------------------------------------------------------------------------------
// Handle mouse with Gesture Recognizers.
// NOTE: Use either this method or the Override Methods, NOT both!
// --------------------------------------------------------------------------------
var click = new NSClickGestureRecognizer (() => {
FlipSwitchState();
});
AddGestureRecognizer (click);
}
Ici, nous créons une NSClickGestureRecognizer
nouvelle méthode et nous appelons notre FlipSwitchState
méthode pour modifier l’état du commutateur lorsque l’utilisateur clique dessus avec le bouton gauche de la souris. La AddGestureRecognizer (click)
méthode ajoute le Module de reconnaissance de mouvement au contrôle.
Là encore, la méthode que nous utilisons dépend de ce que nous essayons d’accomplir avec notre contrôle personnalisé. Si nous avons besoin d’un accès de bas niveau à l’interaction utilisateur, utilisez les méthodes override. Si nous avons besoin de fonctionnalités prédéfinies, telles que des clics de souris, utilisez des reconnaissances de mouvement.
Réponse aux événements de modification d’état
Lorsque l’utilisateur modifie l’état de notre contrôle personnalisé, nous avons besoin d’un moyen de répondre à la modification de l’état dans le code (par exemple, en effectuant des clics sur un bouton personnalisé).
Pour fournir cette fonctionnalité, modifiez la NSFlipSwitch
classe et ajoutez le code suivant :
#region Events
public event EventHandler ValueChanged;
internal void RaiseValueChanged() {
if (this.ValueChanged != null)
this.ValueChanged (this, EventArgs.Empty);
// Perform any action bound to the control from Interface Builder
// via an Action.
if (this.Action !=null)
NSApplication.SharedApplication.SendAction (this.Action, this.Target, this);
}
## endregion
Ensuite, modifiez la méthode et faites-la FlipSwitchState
ressembler à ce qui suit :
private void FlipSwitchState() {
// Update state
Value = !Value;
RaiseValueChanged ();
}
Tout d’abord, nous fournissons un ValueChanged
événement auquel nous pouvons ajouter un gestionnaire dans le code C# afin de pouvoir effectuer une action lorsque l’utilisateur modifie l’état du commutateur.
Deuxièmement, étant donné que notre contrôle personnalisé hérite de NSControl
, il a automatiquement une action qui peut être affectée dans le Générateur d’interface de Xcode. Pour appeler cette action lorsque l’état change, nous utilisons le code suivant :
if (this.Action !=null)
NSApplication.SharedApplication.SendAction (this.Action, this.Target, this);
Tout d’abord, nous vérifions si une action a été affectée au contrôle. Ensuite, nous appelons l’action si elle a été définie.
Utilisation du contrôle personnalisé
Avec notre contrôle personnalisé entièrement défini, nous pouvons l’ajouter à l’interface utilisateur de notre application Xamarin.Mac à l’aide de code C# ou dans le Générateur d’interface de Xcode.
Pour ajouter le contrôle à l’aide du Générateur d’interface, commencez par effectuer une build propre du projet Xamarin.Mac, puis double-cliquez sur le Main.storyboard
fichier pour l’ouvrir dans Interface Builder pour modification :
Ensuite, faites glisser une Custom View
dans la conception de l’interface utilisateur :
Une fois l’affichage personnalisé toujours sélectionné, basculez vers l’inspecteur d’identité et remplacez la classe NSFlipSwitch
de la vue par :
Basculez vers l’Éditeur Assistant et créez un point de sortie pour le contrôle personnalisé (veillez à le lier dans le ViewController.h
fichier et non au .m
fichier) :
Enregistrez vos modifications, revenez à Visual Studio pour Mac et autorisez la synchronisation des modifications. Modifiez le ViewController.cs
fichier et faites en sorte que la ViewDidLoad
méthode ressemble à ce qui suit :
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Do any additional setup after loading the view.
OptionTwo.ValueChanged += (sender, e) => {
// Display the state of the option switch
Console.WriteLine("Option Two: {0}", OptionTwo.Value);
};
}
Ici, nous répondons à l’événement ValueChanged
que nous avons défini ci-dessus sur la NSFlipSwitch
classe et écrivons la valeur actuelle lorsque l’utilisateur clique sur le contrôle.
Si vous le souhaitez, nous pourrions revenir au Générateur d’interface et définir une action sur le contrôle :
Là encore, modifiez le ViewController.cs
fichier et ajoutez la méthode suivante :
partial void OptionTwoFlipped (Foundation.NSObject sender) {
// Display the state of the option switch
Console.WriteLine("Option Two: {0}", OptionTwo.Value);
}
Important
Vous devez utiliser l’événement ou définir une action dans le Générateur d’interface, mais vous ne devez pas utiliser les deux méthodes en même temps ou elles peuvent entrer en conflit entre elles.
Résumé
Cet article a examiné en détail la création d’un contrôle d’interface utilisateur personnalisé réutilisable dans une application Xamarin.Mac. Nous avons vu comment dessiner l’interface utilisateur des contrôles personnalisés, les deux principales façons de répondre à l’entrée de la souris et de l’utilisateur et comment exposer le nouveau contrôle aux actions dans le Générateur d’interface de Xcode.