Partager via


Création d’applications macOS modernes

Cet article décrit plusieurs conseils, fonctionnalités et techniques qu’un développeur peut utiliser pour créer une application macOS moderne dans Xamarin.Mac.

Création d’apparences modernes avec des vues modernes

Un aspect moderne inclut une apparence moderne de fenêtre et de barre d’outils, comme l’exemple d’application illustré ci-dessous :

Exemple d’interface utilisateur d’une application Mac moderne

Activation des vues de contenu de taille complète

Pour ce faire, dans une application Xamarin.Mac, le développeur souhaite utiliser une vue de contenu de taille complète, ce qui signifie que le contenu s’étend sous les zones outils et barre de titre et sera automatiquement flou par macOS.

Pour activer cette fonctionnalité dans le code, créez une classe personnalisée pour la NSWindowController classe et faites-la ressembler à ce qui suit :

using System;
using Foundation;
using AppKit;

namespace MacModern
{
    public partial class MainWindowController : NSWindowController
    {
        #region Constructor
        public MainWindowController (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Override Methods
        public override void WindowDidLoad ()
        {
            base.WindowDidLoad ();

            // Set window to use Full Size Content View
            Window.StyleMask = NSWindowStyle.FullSizeContentView;
        }
        #endregion
    }
}

Cette fonctionnalité peut également être activée dans le Générateur d’interface de Xcode en sélectionnant la fenêtre et en vérifiant l’affichage de contenu de taille complète :

Modification du storyboard principal dans le Générateur d’interface de Xcode

Lorsque vous utilisez une vue de contenu de taille complète, le développeur peut avoir besoin de décaler le contenu sous les zones de titre et de barre d’outils afin que le contenu spécifique (par exemple, les étiquettes) ne glisse pas sous eux.

Pour compliquer ce problème, les zones De titre et barre d’outils peuvent avoir une hauteur dynamique en fonction de l’action sur laquelle l’utilisateur effectue actuellement, la version de macOS que l’utilisateur a installée et/ou le matériel Mac sur lequel l’application s’exécute.

Par conséquent, il suffit de coder en dur le décalage lors de la disposition de l’interface utilisateur ne fonctionnera pas. Le développeur devra adopter une approche dynamique.

Apple a inclus la propriété Key-Value Observable ContentLayoutRect de la NSWindow classe pour obtenir la zone de contenu actuelle dans le code. Le développeur peut utiliser cette valeur pour positionner manuellement les éléments requis lorsque la zone de contenu change.

La meilleure solution consiste à utiliser les classes de disposition et de taille automatiques pour positionner les éléments de l’interface utilisateur dans le code ou le Générateur d’interface.

Le code comme l’exemple suivant peut être utilisé pour positionner des éléments d’interface utilisateur à l’aide de classes de superposition automatique et de taille dans le contrôleur de vue de l’application :

using System;
using AppKit;
using Foundation;

namespace MacModern
{
    public partial class ViewController : NSViewController
    {
        #region Computed Properties
        public NSLayoutConstraint topConstraint { get; set; }
        #endregion

        ...

        #region Override Methods
        public override void UpdateViewConstraints ()
        {
            // Has the constraint already been set?
            if (topConstraint == null) {
                // Get the top anchor point
                var contentLayoutGuide = ItemTitle.Window?.ContentLayoutGuide as NSLayoutGuide;
                var topAnchor = contentLayoutGuide.TopAnchor;

                // Found?
                if (topAnchor != null) {
                    // Assemble constraint and activate it
                    topConstraint = topAnchor.ConstraintEqualToAnchor (topAnchor, 20);
                    topConstraint.Active = true;
                }
            }

            base.UpdateViewConstraints ();
        }
        #endregion
    }
}

Ce code crée un stockage pour une contrainte supérieure qui sera appliquée à une étiquette (ItemTitle) pour vous assurer qu’elle ne glisse pas sous la zone Titre et barre d’outils :

public NSLayoutConstraint topConstraint { get; set; }

En substituant la méthode du contrôleur de UpdateViewConstraints vue, le développeur peut tester si la contrainte nécessaire a déjà été générée et la créer si nécessaire.

Si une nouvelle contrainte doit être générée, la ContentLayoutGuide propriété de la fenêtre dont le contrôle doit être limité est accessible et converti en un NSLayoutGuide:

var contentLayoutGuide = ItemTitle.Window?.ContentLayoutGuide as NSLayoutGuide;

La propriété TopAnchor de l’objet NSLayoutGuide est accessible et, si elle est disponible, elle est utilisée pour générer une nouvelle contrainte avec la quantité de décalage souhaitée et la nouvelle contrainte est rendue active pour l’appliquer :

// Assemble constraint and activate it
topConstraint = topAnchor.ConstraintEqualToAnchor (topAnchor, 20);
topConstraint.Active = true;

Activation des barres d’outils simplifiées

Une fenêtre macOS normale comprend une barre de titre standard aux exécutions le long du bord supérieur de la fenêtre. Si la fenêtre inclut également une barre d’outils, elle s’affiche sous cette zone de barre de titre :

Barre d’outils Mac standard

Lorsque vous utilisez une barre d’outils simplifiée, la zone de titre disparaît et la barre d’outils se déplace vers le haut à la position de la barre de titre, en ligne avec les boutons Fermer, Réduire et Agrandir de la fenêtre :

Barre d’outils Mac simplifiée

La barre d’outils rationalisée est activée en remplaçant la ViewWillAppear méthode de la NSViewController barre d’outils et en la faisant ressembler à ce qui suit :

public override void ViewWillAppear ()
{
    base.ViewWillAppear ();

    // Enable streamlined Toolbars
    View.Window.TitleVisibility = NSWindowTitleVisibility.Hidden;
}

Cet effet est généralement utilisé pour les applications Shoebox (applications d’une fenêtre) telles que cartes, calendrier, notes et préférences système.

Utilisation des contrôleurs d’affichage accessoires

En fonction de la conception de l’application, le développeur peut également souhaiter compléter la zone barre de titre avec un contrôleur d’affichage accessoire qui apparaît juste en dessous de la zone De titre/barre d’outils pour fournir des contrôles contextuels à l’utilisateur en fonction de l’activité dans laquelle ils sont actuellement engagés :

Exemple de contrôleur d’affichage accessoire

Le contrôleur d’affichage accessoire est automatiquement flou et redimensionné par le système sans intervention du développeur.

Pour ajouter un contrôleur d’affichage accessoire, procédez comme suit :

  1. Dans l’Explorateur de solutions, double-cliquez sur le fichier Main.storyboard pour l’ouvrir et le modifier.

  2. Faites glisser un contrôleur d’affichage personnalisé dans la hiérarchie de la fenêtre :

    Ajout d’un nouveau contrôleur d’affichage personnalisé

  3. Disposition de l’interface utilisateur de l’affichage accessoire :

    Conception de la nouvelle vue

  4. Exposez l’affichage accessoire en tant que point de sortie et toutes les autres actions ou points de sortie pour son interface utilisateur :

    Ajout de l’OUtlet requis

  5. Enregistrez les modifications.

  6. Revenez à Visual Studio pour Mac pour synchroniser les modifications.

Modifiez le NSWindowController fichier et faites-le ressembler à ce qui suit :

using System;
using Foundation;
using AppKit;

namespace MacModern
{
    public partial class MainWindowController : NSWindowController
    {
        #region Constructor
        public MainWindowController (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Override Methods
        public override void WindowDidLoad ()
        {
            base.WindowDidLoad ();

            // Create a title bar accessory view controller and attach
            // the view created in Interface Builder
            var accessoryView = new NSTitlebarAccessoryViewController ();
            accessoryView.View = AccessoryViewGoBar;

            // Set the location and attach the accessory view to the
            // titlebar to be displayed
            accessoryView.LayoutAttribute = NSLayoutAttribute.Bottom;
            Window.AddTitlebarAccessoryViewController (accessoryView);

        }
        #endregion
    }
}

Les points clés de ce code sont l’emplacement où la vue est définie sur la vue personnalisée définie dans le Générateur d’interface et exposée en tant que point de sortie :

accessoryView.View = AccessoryViewGoBar;

Et qui LayoutAttribute définit l’emplacement où l’accessoire sera affiché :

accessoryView.LayoutAttribute = NSLayoutAttribute.Bottom;

Étant donné que macOS est désormais entièrement localisé, les Left propriétés ont Right NSLayoutAttribute été déconseillées et doivent être remplacées par Leading et Trailing.

Utilisation de Windows à onglets

En outre, le système macOS peut ajouter des contrôleurs d’affichage accessoires à la fenêtre de l’application. Par exemple, pour créer des fenêtres à onglets où plusieurs des fenêtres de l’application sont fusionnées dans une fenêtre virtuelle :

Exemple de fenêtre Mac tabulée

En règle générale, le développeur doit prendre des mesures limitées à l’aide de Tabbed Windows dans ses applications Xamarin.Mac, le système les gère automatiquement comme suit :

  • Windows est automatiquement tabulé lorsque la OrderFront méthode est appelée.
  • Windows est automatiquement untabbed lorsque la OrderOut méthode est appelée.
  • Dans le code, toutes les fenêtres à onglets sont toujours considérées comme « visibles », mais toutes les tabulations non frontales sont masquées par le système à l’aide de CoreGraphics.
  • Utilisez la TabbingIdentifier propriété de regroupement de NSWindow Windows dans tabulations.
  • S’il s’agit d’une NSDocument application basée, plusieurs de ces fonctionnalités sont activées automatiquement (par exemple, le bouton plus ajouté à la barre d’onglets) sans action de développeur.
  • NSDocument Les applications non basées peuvent activer le bouton « plus » dans le groupe d’onglets pour ajouter un nouveau document en remplaçant la GetNewWindowForTab méthode du NSWindowsController.

Rassembler toutes les parties, l’application AppDelegate qui voulait utiliser des fenêtres tabulations basées sur le système pourrait ressembler à ceci :

using AppKit;
using Foundation;

namespace MacModern
{
    [Register ("AppDelegate")]
    public class AppDelegate : NSApplicationDelegate
    {
        #region Computed Properties
        public int NewDocumentNumber { get; set; } = 0;
        #endregion

        #region Constructors
        public AppDelegate ()
        {
        }
        #endregion

        #region Override Methods
        public override void DidFinishLaunching (NSNotification notification)
        {
            // Insert code here to initialize your application
        }

        public override void WillTerminate (NSNotification notification)
        {
            // Insert code here to tear down your application
        }
        #endregion

        #region Custom Actions
        [Export ("newDocument:")]
        public void NewDocument (NSObject sender)
        {
            // Get new window
            var storyboard = NSStoryboard.FromName ("Main", null);
            var controller = storyboard.InstantiateControllerWithIdentifier ("MainWindow") as NSWindowController;

            // Display
            controller.ShowWindow (this);
        }
        #endregion
    }
}

Où la NewDocumentNumber propriété effectue le suivi du nombre de nouveaux documents créés et de la NewDocument méthode crée un document et l’affiche.

Le NSWindowController pourrait alors ressembler à ceci :

using System;
using Foundation;
using AppKit;

namespace MacModern
{
    public partial class MainWindowController : NSWindowController
    {
        #region Application Access
        /// <summary>
        /// A helper shortcut to the app delegate.
        /// </summary>
        /// <value>The app.</value>
        public static AppDelegate App {
            get { return (AppDelegate)NSApplication.SharedApplication.Delegate; }
        }
        #endregion

        #region Constructor
        public MainWindowController (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Public Methods
        public void SetDefaultDocumentTitle ()
        {
            // Is this the first document?
            if (App.NewDocumentNumber == 0) {
                // Yes, set title and increment
                Window.Title = "Untitled";
                ++App.NewDocumentNumber;
            } else {
                // No, show title and count
                Window.Title = $"Untitled {App.NewDocumentNumber++}";
            }
        }
        #endregion

        #region Override Methods
        public override void WindowDidLoad ()
        {
            base.WindowDidLoad ();

            // Prefer Tabbed Windows
            Window.TabbingMode = NSWindowTabbingMode.Preferred;
            Window.TabbingIdentifier = "Main";

            // Set default window title
            SetDefaultDocumentTitle ();

            // Set window to use Full Size Content View
            // Window.StyleMask = NSWindowStyle.FullSizeContentView;

            // Create a title bar accessory view controller and attach
            // the view created in Interface Builder
            var accessoryView = new NSTitlebarAccessoryViewController ();
            accessoryView.View = AccessoryViewGoBar;

            // Set the location and attach the accessory view to the
            // titlebar to be displayed
            accessoryView.LayoutAttribute = NSLayoutAttribute.Bottom;
            Window.AddTitlebarAccessoryViewController (accessoryView);

        }

        public override void GetNewWindowForTab (NSObject sender)
        {
            // Ask app to open a new document window
            App.NewDocument (this);
        }
        #endregion
    }
}

Où la propriété statique App fournit un raccourci pour accéder au AppDelegate. La SetDefaultDocumentTitle méthode définit un titre de document en fonction du nombre de nouveaux documents créés.

Le code suivant indique à macOS que l’application préfère utiliser des onglets et fournit une chaîne qui permet au windows de l’application d’être regroupée en onglets :

// Prefer Tabbed Windows
Window.TabbingMode = NSWindowTabbingMode.Preferred;
Window.TabbingIdentifier = "Main";

La méthode de remplacement suivante ajoute un bouton plus à la barre de tabulations qui crée un document en cliquant sur l’utilisateur :

public override void GetNewWindowForTab (NSObject sender)
{
    // Ask app to open a new document window
    App.NewDocument (this);
}

Utilisation de l’animation principale

Core Animation est un moteur de rendu graphique à haute puissance intégré à macOS. L’animation de base a été optimisée pour tirer parti du GPU (unité de traitement graphique) disponible dans le matériel macOS moderne, plutôt que d’exécuter les opérations graphiques sur le processeur, ce qui peut ralentir la machine.

Le CALayer, fourni par Core Animation, peut être utilisé pour les tâches telles que le défilement rapide et fluide et les animations. L’interface utilisateur d’une application doit être composée de plusieurs sous-vues et couches pour tirer pleinement parti de Core Animation.

Un CALayer objet fournit plusieurs propriétés qui permettent au développeur de contrôler ce qui est présenté à l’écran à l’utilisateur, par exemple :

  • Content - Peut être un NSImage ou CGImage qui fournit le contenu de la couche.
  • BackgroundColor - Définit la couleur d’arrière-plan du calque en tant que CGColor
  • BorderWidth - Définit la largeur de la bordure.
  • BorderColor - Définit la couleur de bordure.

Pour utiliser Core Graphics dans l’interface utilisateur de l’application, il doit utiliser des vues superposées , ce qu’Apple suggère que le développeur doit toujours activer dans l’affichage de contenu de la fenêtre. De cette façon, toutes les vues enfants héritent automatiquement du stockage de couches.

En outre, Apple suggère d’utiliser des vues sauvegardées par couche plutôt que d’ajouter un nouveau CALayer sous-calque, car le système gère automatiquement plusieurs des paramètres requis (tels que ceux requis par un affichage Rétine).

Le stockage de couches peut être activé en définissant la valeur ou true l’intérieur WantsLayer du Générateur d’interface de Xcode sous l’inspecteur d’effets d’affichage en vérifiant la couche d’animation principale :NSView

Inspecteur d’effets d’affichage

Redessiner des vues avec des couches

Une autre étape importante lors de l’utilisation de vues sauvegardées par couche dans une application Xamarin.Mac définit la valeur LayerContentsRedrawPolicy de la valeur NSView OnSetNeedsDisplay dans l’application NSViewController. Par exemple :

public override void ViewWillAppear ()
{
    base.ViewWillAppear ();

    // Set the content redraw policy
    View.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
}

Si le développeur ne définit pas cette propriété, la vue est redessinée chaque fois que son origine d’image change, ce qui n’est pas souhaité pour des raisons de performances. Avec cette propriété définie sur OnSetNeedsDisplay le développeur, vous devez définir NeedsDisplay manuellement pour true forcer le contenu à redessiner, toutefois.

Lorsqu’une vue est marquée comme incorrecte, le système vérifie la WantsUpdateLayer propriété de l’affichage. Si elle retourne true alors la UpdateLayer méthode est appelée, sinon la DrawRect méthode de la vue est appelée pour mettre à jour le contenu de la vue.

Apple propose les suggestions suivantes pour mettre à jour le contenu d’une vue si nécessaire :

  • Apple préfère utiliser UpdateLater le plus DrawRect possible, car il offre une amélioration significative des performances.
  • Utilisez la même chose layer.Contents pour les éléments d’interface utilisateur qui ressemblent.
  • Apple préfère également que le développeur compose son interface utilisateur à l’aide de vues standard telles que NSTextField, à nouveau dans la mesure du possible.

Pour utiliser UpdateLayer, créez une classe personnalisée pour le NSView code et faites en sorte que le code ressemble à ce qui suit :

using System;
using Foundation;
using AppKit;

namespace MacModern
{
    public partial class MainView : NSView
    {
        #region Computed Properties
        public override bool WantsLayer {
            get { return true; }
        }

        public override bool WantsUpdateLayer {
            get { return true; }
        }
        #endregion

        #region Constructor
        public MainView (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Override Methods
        public override void DrawRect (CoreGraphics.CGRect dirtyRect)
        {
            base.DrawRect (dirtyRect);

        }

        public override void UpdateLayer ()
        {
            base.UpdateLayer ();

            // Draw view
            Layer.BackgroundColor = NSColor.Red.CGColor;
        }
        #endregion
    }
}

Utilisation du glisser-déplacer moderne

Pour présenter une expérience de glisser-déplacer moderne pour l’utilisateur, le développeur doit adopter Drag Flocking dans les opérations glisser-déplacer de son application. Faire glisser Flocking est l’endroit où chaque fichier ou élément individuel en cours de déplacement apparaît initialement en tant qu’élément individuel qui se regroupe (regrouper sous le curseur avec le nombre d’éléments) lorsque l’utilisateur poursuit l’opération de glissement.

Si l’utilisateur met fin à l’opération Glisser, les éléments individuels se déblocent et retournent à leurs emplacements d’origine.

L’exemple de code suivant permet de faire glisser le troupeau sur une vue personnalisée :

using System;
using System.Collections.Generic;
using Foundation;
using AppKit;

namespace MacModern
{
    public partial class MainView : NSView, INSDraggingSource, INSDraggingDestination
    {
        #region Constructor
        public MainView (IntPtr handle) : base (handle)
        {
        }
        #endregion

        #region Override Methods
        public override void MouseDragged (NSEvent theEvent)
        {
            // Create group of string to be dragged
            var string1 = new NSDraggingItem ((NSString)"Item 1");
            var string2 = new NSDraggingItem ((NSString)"Item 2");
            var string3 = new NSDraggingItem ((NSString)"Item 3");

            // Drag a cluster of items
            BeginDraggingSession (new [] { string1, string2, string3 }, theEvent, this);
        }
        #endregion
    }
}

L’effet de troupeau a été obtenu en envoyant chaque élément déplacé vers la méthode de l’élément BeginDraggingSession NSView en tant qu’élément distinct dans un tableau.

Lors de l’utilisation d’un NSTableView ou NSOutlineView, utilisez la PastboardWriterForRow méthode de la NSTableViewDataSource classe pour démarrer l’opération Glisser :

using System;
using System.Collections.Generic;
using Foundation;
using AppKit;

namespace MacModern
{
    public class ContentsTableDataSource: NSTableViewDataSource
    {
        #region Constructors
        public ContentsTableDataSource ()
        {
        }
        #endregion

        #region Override Methods
        public override INSPasteboardWriting GetPasteboardWriterForRow (NSTableView tableView, nint row)
        {
            // Return required pasteboard writer
            ...

            // Pasteboard writer failed
            return null;
        }
        #endregion
    }
}

Cela permet au développeur de fournir un individu NSDraggingItem pour chaque élément de la table qui est déplacé par opposition à l’ancienne méthode WriteRowsWith qui écrit toutes les lignes en tant que groupe unique dans le collage.

Lorsque vous travaillez avec NSCollectionViews, utilisez à nouveau la PasteboardWriterForItemAt méthode par opposition à la méthode lors du WriteItemsAt démarrage de dragage.

Le développeur doit toujours éviter de placer des fichiers volumineux dans le collage. Nouveautés de macOS Sierra, les promesses de fichiers permettent au développeur de placer des références à des fichiers donnés dans le collage qui seront ultérieurement remplis lorsque l’utilisateur termine l’opération Drop à l’aide des nouvelles NSFilePromiseProvider classes.NSFilePromiseReceiver

Utilisation du suivi d’événements moderne

Pour un élément Interface utilisateur (tel qu’un NSButton) qui a été ajouté à une zone Titre ou barre d’outils, l’utilisateur doit pouvoir cliquer sur l’élément et déclencher un événement comme normal (par exemple, afficher une fenêtre contextuelle). Toutefois, étant donné que l’élément se trouve également dans la zone Titre ou Barre d’outils, l’utilisateur doit pouvoir cliquer et faire glisser l’élément pour déplacer la fenêtre également.

Pour ce faire dans le code, créez une classe personnalisée pour l’élément (par exemple NSButton) et remplacez l’événement MouseDown comme suit :

public override void MouseDown (NSEvent theEvent)
{
    var shouldCallSuper = false;

    Window.TrackEventsMatching (NSEventMask.LeftMouseUp, 2000, NSRunLoop.NSRunLoopEventTracking, (NSEvent evt, ref bool stop) => {
        // Handle event as normal
        stop = true;
        shouldCallSuper = true;
    });

    Window.TrackEventsMatching(NSEventMask.LeftMouseDragged, 2000, NSRunLoop.NSRunLoopEventTracking, (NSEvent evt, ref bool stop) => {
        // Pass drag event to window
        stop = true;
        Window.PerformWindowDrag (evt);
    });

    // Call super to handle mousedown
    if (shouldCallSuper) {
        base.MouseDown (theEvent);
    }
}

Ce code utilise la TrackEventsMatching méthode de l’élément NSWindow d’interface utilisateur attaché pour intercepter les événements et LeftMouseDragged les LeftMouseUp événements. Pour un LeftMouseUp événement, l’élément d’interface utilisateur répond normalement. Pour l’événementLeftMouseDragged, l’événement est passé à la méthode de PerformWindowDrag la fenêtre à l’écranNSWindow.

L’appel de la PerformWindowDrag méthode de la NSWindow classe offre les avantages suivants :

  • Il permet à la fenêtre de se déplacer, même si l’application est suspendue (par exemple, lors du traitement d’une boucle profonde).
  • Le changement d’espace fonctionnera comme prévu.
  • La barre d’espaces s’affiche normalement.
  • L’alignement et l’alignement de fenêtre fonctionnent normalement.

Utilisation de contrôles d’affichage de conteneur modernes

macOS Sierra fournit de nombreuses améliorations modernes apportées aux contrôles d’affichage de conteneur existants disponibles dans la version précédente du système d’exploitation.

Améliorations apportées à l’affichage des tables

Le développeur doit toujours utiliser la nouvelle NSView version basée sur les contrôles d’affichage conteneur, comme NSTableView. Par exemple :

using System;
using System.Collections.Generic;
using Foundation;
using AppKit;

namespace MacModern
{
    public class ContentsTableDelegate : NSTableViewDelegate
    {
        #region Constructors
        public ContentsTableDelegate ()
        {
        }
        #endregion

        #region Override Methods
        public override NSView GetViewForItem (NSTableView tableView, NSTableColumn tableColumn, nint row)
        {
            // Build new view
            var view = new NSView ();
            ...

            // Return the view representing the item to display
            return view;
        }
        #endregion
    }
}

Cela permet d’attacher des actions de ligne de table personnalisées à des lignes données dans la table (par exemple, le balayage vers la droite pour supprimer la ligne). Pour activer ce comportement, remplacez la RowActions méthode du NSTableViewDelegate:

using System;
using System.Collections.Generic;
using Foundation;
using AppKit;

namespace MacModern
{
    public class ContentsTableDelegate : NSTableViewDelegate
    {
        #region Constructors
        public ContentsTableDelegate ()
        {
        }
        #endregion

        #region Override Methods
        public override NSView GetViewForItem (NSTableView tableView, NSTableColumn tableColumn, nint row)
        {
            // Build new view
            var view = new NSView ();
            ...

            // Return the view representing the item to display
            return view;
        }

        public override NSTableViewRowAction [] RowActions (NSTableView tableView, nint row, NSTableRowActionEdge edge)
        {
            // Take action based on the edge
            if (edge == NSTableRowActionEdge.Trailing) {
                // Create row actions
                var editAction = NSTableViewRowAction.FromStyle (NSTableViewRowActionStyle.Regular, "Edit", (action, rowNum) => {
                    // Handle row being edited
                    ...
                });

                var deleteAction = NSTableViewRowAction.FromStyle (NSTableViewRowActionStyle.Destructive, "Delete", (action, rowNum) => {
                    // Handle row being deleted
                    ...
                });

                // Return actions
                return new [] { editAction, deleteAction };
            } else {
                // No matching actions
                return null;
            }
        }
        #endregion
    }
}

Le statique NSTableViewRowAction.FromStyle est utilisé pour créer une action de ligne de table des styles suivants :

  • Regular - Effectue une action standard non destructrice telle que la modification du contenu de la ligne.
  • Destructive - Effectue une action destructrice telle que la suppression de la ligne de la table. Ces actions seront rendues avec un arrière-plan rouge.

Améliorations apportées à la vue de défilement

Lors de l’utilisation d’un affichage de défilement (NSScrollView) directement ou dans le cadre d’un autre contrôle (par exemple NSTableView), le contenu de la vue de défilement peut glisser sous les zones Titre et Barre d’outils dans une application Xamarin.Mac à l’aide d’un look et d’une vue modernes.

Par conséquent, le premier élément de la zone de contenu De la vue de défilement peut être partiellement masqué par la zone Titre et barre d’outils.

Pour corriger ce problème, Apple a ajouté deux nouvelles propriétés à la NSScrollView classe :

  • ContentInsets - Permet au développeur de fournir un NSEdgeInsets objet définissant le décalage qui sera appliqué en haut de l’affichage de défilement.
  • AutomaticallyAdjustsContentInsets - Si true l’affichage de défilement gère automatiquement le ContentInsets développeur.

En utilisant le ContentInsets développeur peut ajuster le début de la vue de défilement pour permettre l’inclusion d’accessoires tels que :

  • Indicateur de tri comme celui affiché dans l’application Courrier.
  • Champ de recherche.
  • Bouton Actualiser ou Mettre à jour.

Disposition et localisation automatiques dans les applications modernes

Apple a inclus plusieurs technologies dans Xcode qui permettent au développeur de créer facilement une application macOS internationalisée. Xcode permet désormais au développeur de séparer le texte accessible par l’utilisateur de la conception de l’interface utilisateur de l’application dans ses fichiers Storyboard et fournit des outils pour maintenir cette séparation si l’interface utilisateur change.

Pour plus d’informations, consultez le Guide d’internationalisation et de localisation d’Apple.

Implémentation de l’internationalisation de base

En implémentant Base Internationalization, le développeur peut fournir un fichier Storyboard unique pour représenter l’interface utilisateur de l’application et séparer toutes les chaînes orientées utilisateur.

Lorsque le développeur crée le fichier Storyboard initial (ou les fichiers) qui définissent l’interface utilisateur de l’application, il est intégré à l’internationalisation de base (langue que le développeur parle).

Ensuite, le développeur peut exporter des localisations et des chaînes d’internationalisation de base (dans la conception de l’interface utilisateur storyboard) qui peuvent être traduites en plusieurs langues.

Plus tard, ces localisations peuvent être importées et Xcode génèreront les fichiers de chaîne spécifiques à la langue pour le Storyboard.

Implémentation de la disposition automatique pour prendre en charge la localisation

Étant donné que les versions localisées des valeurs de chaîne peuvent avoir des tailles et/ou des instructions de lecture très différentes, le développeur doit utiliser la disposition automatique pour positionner et dimensionner l’interface utilisateur de l’application dans un fichier Storyboard.

Apple suggère d’effectuer les opérations suivantes :

  • Supprimer les contraintes de largeur fixe : tous les affichages textuels doivent être autorisés à redimensionner en fonction de leur contenu. La vue largeur fixe peut rogner leur contenu dans des langues spécifiques.
  • Utiliser des tailles de contenu intrinsèques : par défaut, les vues basées sur du texte sont automatiquement dimensionnant leur contenu. Pour l’affichage textuel qui ne dimensionne pas correctement, sélectionnez-les dans le Générateur d’interface de Xcode, puis choisissez Modifier>la taille pour ajuster le contenu.
  • Appliquer des attributs de début et de fin : étant donné que la direction du texte peut changer en fonction de la langue de l’utilisateur, utilisez les nouveaux Leading attributs et Trailing les attributs de contrainte par opposition aux attributs existants Right et Left aux attributs. Leading et Trailing s’ajuste automatiquement en fonction de la direction des langues.
  • Épingler des vues aux vues adjacentes : cela permet aux vues de repositionner et de redimensionner à mesure que les vues autour d’elles changent en réponse à la langue sélectionnée.
  • Ne définissez pas de tailles minimales et/ou maximales Windows : autorisez Windows à modifier la taille à mesure que la langue sélectionnée redimensionne leurs zones de contenu.
  • Modifications de disposition de test constantes : pendant le développement au niveau de l’application, les tests doivent être testés constamment dans différentes langues. Pour plus d’informations, consultez la documentation relative au test de votre application internationalisée d’Apple.
  • L’utilisation de NSStackViews pour épingler des vues ensemble - NSStackViews permet à leur contenu de changer et de croître de manière prévisible et de modifier la taille du contenu en fonction de la langue sélectionnée.

Localisation dans le Générateur d’interface de Xcode

Apple a fourni plusieurs fonctionnalités dans le Générateur d’interface de Xcode que le développeur peut utiliser lors de la conception ou de la modification de l’interface utilisateur d’une application pour prendre en charge la localisation. La section Direction du texte de l’inspecteur d’attributs permet au développeur de fournir des conseils sur la façon dont l’orientation doit être utilisée et mise à jour sur une vue de texte sélectionnée (par exempleNSTextField) :

Options Direction du texte

Il existe trois valeurs possibles pour la direction du texte :

  • Naturel : la disposition est basée sur la chaîne affectée au contrôle.
  • Gauche à droite : la disposition est toujours forcée de gauche à droite.
  • Droite à gauche : la disposition est toujours forcée de droite à gauche.

Il existe deux valeurs possibles pour la disposition :

  • Gauche à droite : la disposition est toujours de gauche à droite.
  • Droite à gauche : la disposition est toujours de droite à gauche.

En règle générale, elles ne doivent pas être modifiées, sauf si un alignement spécifique est requis.

La propriété Mirror indique au système d’retourner des propriétés de contrôle spécifiques (telles que la position de l’image de cellule). Il a trois valeurs possibles :

  • Automatiquement : la position change automatiquement en fonction de la direction de la langue sélectionnée.
  • Dans l’interface de droite à gauche : la position n’est modifiée que dans les langues de droite à gauche.
  • Jamais - La position ne changera jamais.

Si le développeur a spécifié le Centre, Justifiez ou l’alignement complet sur le contenu d’une vue textuelle, ceux-ci ne seront jamais retournés en fonction de la langue sélectionnée.

Avant macOS Sierra, les contrôles créés dans le code ne sont pas mis en miroir automatiquement. Le développeur a dû utiliser du code comme suit pour gérer la mise en miroir :

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();

    // Setting a button's mirroring based on the layout direction
    var button = new NSButton ();
    if (button.UserInterfaceLayoutDirection == NSUserInterfaceLayoutDirection.LeftToRight) {
        button.Alignment = NSTextAlignment.Right;
        button.ImagePosition = NSCellImagePosition.ImageLeft;
    } else {
        button.Alignment = NSTextAlignment.Left;
        button.ImagePosition = NSCellImagePosition.ImageRight;
    }
}

Où le Alignment ImagePosition contrôle est défini et défini UserInterfaceLayoutDirection .

macOS Sierra ajoute plusieurs nouveaux constructeurs pratiques (via la méthode statique CreateButton ) qui prennent plusieurs paramètres (tels que Title, Image et Action) et sont automatiquement mis en miroir correctement. Par exemple :

var button2 = NSButton.CreateButton (myTitle, myImage, () => {
    // Take action when the button is pressed
    ...
});

Utilisation des apparences système

Les applications macOS modernes peuvent adopter une nouvelle apparence d’interface sombre qui fonctionne bien pour la création d’images, la modification ou les applications de présentation :

Exemple d’interface utilisateur de fenêtre Mac sombre

Pour ce faire, ajoutez une ligne de code avant la présentation de la fenêtre. Par exemple :

using System;
using AppKit;
using Foundation;

namespace MacModern
{
    public partial class ViewController : NSViewController
    {
        ...

        #region Override Methods
        public override void ViewWillAppear ()
        {
            base.ViewWillAppear ();

            // Apply the Dark Interface Appearance
            View.Window.Appearance = NSAppearance.GetAppearance (NSAppearance.NameVibrantDark);

            ...
        }
        #endregion
    }
}

La méthode statique GetAppearance de la NSAppearance classe est utilisée pour obtenir une apparence nommée à partir du système (dans ce cas NSAppearance.NameVibrantDark).

Apple propose les suggestions suivantes pour l’utilisation des apparences système :

  • Préférer les couleurs nommées sur les valeurs codées en dur (par LabelColor exemple, et SelectedControlColor).
  • Utilisez le style de contrôle standard du système si possible.

Une application macOS qui utilise les apparences système fonctionne automatiquement pour les utilisateurs qui ont activé les fonctionnalités d’accessibilité à partir de l’application Préférences système. Par conséquent, Apple suggère que le développeur doit toujours utiliser les apparences système dans leurs applications macOS.

Conception d’interfaces utilisateur avec des storyboards

Les storyboards permettent au développeur de concevoir non seulement les éléments individuels qui composent l’interface utilisateur d’une application, mais également de visualiser et de concevoir le flux d’interface utilisateur et la hiérarchie des éléments donnés.

Les contrôleurs permettent au développeur de collecter des éléments dans une unité de composition et segues abstraites et de supprimer le « code de collage » classique requis pour se déplacer dans toute la hiérarchie d’affichage :

Modification de l’interface utilisateur dans le Générateur d’interface de Xcode

Pour plus d’informations, consultez notre documentation Présentation des storyboards .

Il existe de nombreuses instances où une scène donnée définie dans un storyboard nécessite des données d’une scène précédente dans la hiérarchie d’affichage. Apple propose les suggestions suivantes pour transmettre des informations entre scènes :

  • Les dépendances de données doivent toujours descendre en cascade dans la hiérarchie.
  • Évitez les dépendances structurelles de l’interface utilisateur en dur, car cela limite la flexibilité de l’interface utilisateur.
  • Utilisez des interfaces C# pour fournir des dépendances de données génériques.

Le contrôleur de vue qui agit comme source de segue peut remplacer la PrepareForSegue méthode et effectuer toute initialisation requise (par exemple, le passage de données) avant l’exécution du segue pour afficher le contrôleur de vue cible. Par exemple :

public override void PrepareForSegue (NSStoryboardSegue segue, NSObject sender)
{
    base.PrepareForSegue (segue, sender);

    // Take action based on Segue ID
    switch (segue.Identifier) {
    case "MyNamedSegue":
        // Prepare for the segue to happen
        ...
        break;
    }
}

Pour plus d’informations, consultez notre documentation Segues .

Propagation d’actions

En fonction de la conception de l’application macOS, il peut arriver que le meilleur gestionnaire d’une action sur un contrôle d’interface utilisateur se trouve ailleurs dans la hiérarchie de l’interface utilisateur. Il s’agit généralement de menus et d’éléments de menu qui vivent dans leur propre scène, séparés du reste de l’interface utilisateur de l’application.

Pour gérer cette situation, le développeur peut créer une action personnalisée et transmettre l’action à la chaîne du répondeur. Pour plus d’informations, consultez notre documentation Sur l’utilisation des actions de fenêtre personnalisées.

Fonctionnalités Mac modernes

Apple a inclus plusieurs fonctionnalités orientées utilisateur dans macOS Sierra qui permettent au développeur de tirer le meilleur parti de la plateforme Mac, par exemple :

  • NSUserActivity : cela permet à l’application de décrire l’activité dans laquelle l’utilisateur est actuellement impliqué. NSUserActivity a été initialement créé pour prendre en charge HandOff, où une activité démarrée sur l’un des appareils de l’utilisateur peut être récupérée et poursuivie sur un autre appareil. NSUserActivity fonctionne de la même façon dans macOS que dans iOS. Pour plus d’informations, consultez notre documentation Introduction à handoff iOS.
  • Siri sur Mac : Siri utilise l’activité actuelle (NSUserActivity) pour fournir un contexte aux commandes qu’un utilisateur peut émettre.
  • Restauration de l’état : lorsque l’utilisateur quitte une application sur macOS, puis la relance ultérieurement, l’application est automatiquement retournée à son état précédent. Le développeur peut utiliser l’API Restauration d’état pour encoder et restaurer les états temporaires de l’interface utilisateur avant que l’interface utilisateur ne s’affiche à l’utilisateur. Si l’application est NSDocument basée, la restauration de l’état est gérée automatiquement. Pour activer la restauration de l’état pour les applications nonNSDocument basées, définissez la Restorable NSWindow classe truesur .
  • Documents dans le cloud - Avant macOS Sierra, une application a dû choisir explicitement d’utiliser des documents dans le lecteur iCloud de l’utilisateur. Dans macOS Sierra, les dossiers Desktop et Documents de l’utilisateur peuvent être synchronisés automatiquement avec leur lecteur iCloud par le système. Par conséquent, des copies locales de documents peuvent être supprimées pour libérer de l’espace sur l’ordinateur de l’utilisateur. NSDocument les applications basées sur des applications gérées automatiquement cette modification. Tous les autres types d’applications devront utiliser un NSFileCoordinator pour synchroniser la lecture et l’écriture de documents.

Résumé

Cet article a abordé plusieurs conseils, fonctionnalités et techniques qu’un développeur peut utiliser pour créer une application macOS moderne dans Xamarin.Mac.