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 :
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 :
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 :
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 :
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 :
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 :
Dans l’Explorateur de solutions, double-cliquez sur le fichier
Main.storyboard
pour l’ouvrir et le modifier.Faites glisser un contrôleur d’affichage personnalisé dans la hiérarchie de la fenêtre :
Disposition de l’interface utilisateur de l’affichage accessoire :
Exposez l’affichage accessoire en tant que point de sortie et toutes les autres actions ou points de sortie pour son interface utilisateur :
Enregistrez les modifications.
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 :
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 deNSWindow
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 laGetNewWindowForTab
méthode duNSWindowsController
.
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 unNSImage
ouCGImage
qui fournit le contenu de la couche.BackgroundColor
- Définit la couleur d’arrière-plan du calque en tant queCGColor
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
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 plusDrawRect
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 unNSEdgeInsets
objet définissant le décalage qui sera appliqué en haut de l’affichage de défilement.AutomaticallyAdjustsContentInsets
- Sitrue
l’affichage de défilement gère automatiquement leContentInsets
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 etTrailing
les attributs de contrainte par opposition aux attributs existantsRight
etLeft
aux attributs.Leading
etTrailing
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
) :
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 :
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, etSelectedControlColor
). - 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 :
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 laRestorable
NSWindow
classetrue
sur . - 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 unNSFileCoordinator
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.