Creazione di app macOS moderne
Questo articolo illustra diversi suggerimenti, funzionalità e tecniche che uno sviluppatore può usare per creare un'app macOS moderna in Xamarin.Mac.
Costruzione di look moderni con viste moderne
Un aspetto moderno includerà un aspetto moderno della finestra e della barra degli strumenti, ad esempio l'app di esempio illustrata di seguito:
Abilitazione delle visualizzazioni contenuto con dimensioni complete
Per ottenere questo risultato in un'app Xamarin.Mac, lo sviluppatore vuole usare una visualizzazione contenuto a dimensioni complete, ovvero il contenuto si estende nelle aree Strumento e Barra del titolo e verrà sfocato automaticamente da macOS.
Per abilitare questa funzionalità nel codice, creare una classe personalizzata per NSWindowController
e renderla simile alla seguente:
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
}
}
Questa funzionalità può essere abilitata anche in Interface Builder di Xcode selezionando la finestra e selezionando Visualizzazione contenuto con dimensioni complete:
Quando si usa una visualizzazione contenuto a dimensioni complete, lo sviluppatore potrebbe dover compensare il contenuto sotto le aree del titolo e della barra degli strumenti, in modo che contenuto specifico (ad esempio le etichette) non venga spostato sotto di essi.
Per complicare questo problema, le aree Titolo e Barra degli strumenti possono avere un'altezza dinamica in base all'azione attualmente eseguita dall'utente, alla versione di macOS installata dall'utente e/o all'hardware Mac su cui è in esecuzione l'app.
Di conseguenza, è sufficiente impostare come hardcoded l'offset quando si dispone l'interfaccia utente non funzionerà. Lo sviluppatore dovrà adottare un approccio dinamico.
Apple ha incluso la proprietà Key-Value Observable ContentLayoutRect
della NSWindow
classe per ottenere l'area di contenuto corrente nel codice. Lo sviluppatore può usare questo valore per posizionare manualmente gli elementi necessari quando viene modificata l'area di contenuto.
La soluzione migliore consiste nell'usare classi layout automatico e dimensioni per posizionare gli elementi dell'interfaccia utente nel codice o in Interface Builder.
Il codice simile all'esempio seguente può essere usato per posizionare gli elementi dell'interfaccia utente usando classi AutoLayout e Size nel controller di visualizzazione dell'app:
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
}
}
Questo codice crea l'archiviazione per un vincolo principale che verrà applicato a un'etichetta (ItemTitle
) per assicurarsi che non venga inserito nell'area Titolo e Barra degli strumenti:
public NSLayoutConstraint topConstraint { get; set; }
Eseguendo l'override del metodo del UpdateViewConstraints
controller di visualizzazione, lo sviluppatore può testare per verificare se il vincolo necessario è già stato compilato e crearlo, se necessario.
Se è necessario compilare un nuovo vincolo, la ContentLayoutGuide
proprietà del controllo Window a cui è necessario limitare l'accesso e il cast in un oggetto NSLayoutGuide
:
var contentLayoutGuide = ItemTitle.Window?.ContentLayoutGuide as NSLayoutGuide;
La proprietà TopAnchor di è accessibile e, se disponibile, viene usata per compilare un nuovo vincolo con la quantità di NSLayoutGuide
offset desiderata e il nuovo vincolo viene reso attivo per applicarlo:
// Assemble constraint and activate it
topConstraint = topAnchor.ConstraintEqualToAnchor (topAnchor, 20);
topConstraint.Active = true;
Abilitazione delle barre degli strumenti semplificate
Una normale finestra macOS include una barra del titolo standard in esecuzione lungo il bordo superiore della finestra. Se la finestra include anche una barra degli strumenti, verrà visualizzata sotto questa area della barra del titolo:
Quando si usa una barra degli strumenti semplificata, l'area del titolo scompare e la barra degli strumenti si sposta verso l'alto nella posizione della barra del titolo, in linea con i pulsanti Chiudi finestra, Riduci a icona e Ingrandisci:
La barra degli strumenti semplificata è abilitata eseguendo l'override del ViewWillAppear
metodo di NSViewController
e rendendola simile alla seguente:
public override void ViewWillAppear ()
{
base.ViewWillAppear ();
// Enable streamlined Toolbars
View.Window.TitleVisibility = NSWindowTitleVisibility.Hidden;
}
Questo effetto viene in genere usato per le applicazioni Shoebox (un'app per finestre), ad esempio Mappe, Calendario, Note e Preferenze di sistema.
Uso dei controller di visualizzazione accessori
A seconda della progettazione dell'app, lo sviluppatore potrebbe anche voler integrare l'area della barra del titolo con un controller di visualizzazione accessorio visualizzato proprio sotto l'area della barra degli strumenti/titolo per fornire controlli sensibili al contesto all'utente in base all'attività in cui sono attualmente coinvolti:
Il controller Di visualizzazione accessorio verrà automaticamente sfocato e ridimensionato dal sistema senza l'intervento dello sviluppatore.
Per aggiungere un controller di visualizzazione accessori, eseguire le operazioni seguenti:
In Esplora soluzioni fare doppio clic sul file
Main.storyboard
per aprirlo e modificarlo.Trascinare un controller di visualizzazione personalizzato nella gerarchia della finestra:
Layout dell'interfaccia utente della visualizzazione accessoria:
Esporre la visualizzazione accessoria come outlet e qualsiasi altra azione o outlet per l'interfaccia utente:
Salvare le modifiche.
Tornare a Visual Studio per Mac per sincronizzare le modifiche.
Modificare e NSWindowController
renderlo simile al seguente:
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
}
}
I punti chiave di questo codice sono la posizione in cui la visualizzazione è impostata sulla visualizzazione personalizzata definita in Interface Builder ed esposta come outlet:
accessoryView.View = AccessoryViewGoBar;
E che LayoutAttribute
definisce dove verrà visualizzato l'accessorio:
accessoryView.LayoutAttribute = NSLayoutAttribute.Bottom;
Poiché macOS è ora completamente localizzato, le Left
proprietà e NSLayoutAttribute
Right
sono state deprecate e devono essere sostituite con Leading
e Trailing
.
Uso di finestre a schede
Inoltre, il sistema macOS potrebbe aggiungere controller di visualizzazione accessori alla finestra dell'app. Ad esempio, per creare finestre a schede in cui diverse finestre dell'app vengono unite in una finestra virtuale:
In genere, lo sviluppatore dovrà eseguire azioni limitate usando Windows a schede nelle app Xamarin.Mac, il sistema li gestirà automaticamente come segue:
- Windows verrà automaticamente tabulato quando viene richiamato il
OrderFront
metodo . - Windows verrà automaticamente untabbed quando viene richiamato il
OrderOut
metodo . - Nel codice tutte le finestre a schede sono ancora considerate "visibili", tuttavia tutte le schede non iniziali sono nascoste dal sistema tramite CoreGraphics.
- Utilizzare la
TabbingIdentifier
proprietà diNSWindow
per raggruppare Le finestre in Schede. - Se si tratta di un'app
NSDocument
basata, diverse di queste funzionalità verranno abilitate automaticamente (ad esempio il pulsante più aggiunto alla barra delle schede) senza alcuna azione dello sviluppatore. NSDocument
Le app non basate possono abilitare il pulsante "più" nel gruppo di schede per aggiungere un nuovo documento eseguendo l'overrideNSWindowsController
delGetNewWindowForTab
metodo di .
Riunire tutte le parti, di AppDelegate
un'app che voleva usare windows a schede basate sul sistema potrebbe essere simile alla seguente:
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
}
}
Dove la NewDocumentNumber
proprietà tiene traccia del numero di nuovi documenti creati e il NewDocument
metodo crea un nuovo documento e lo visualizza.
L'oggetto NSWindowController
potrebbe quindi essere simile al seguente:
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
}
}
Dove la proprietà statica App
fornisce un collegamento per passare a AppDelegate
. Il SetDefaultDocumentTitle
metodo imposta un nuovo titolo dei documenti in base al numero di nuovi documenti creati.
Il codice seguente indica a macOS che l'app preferisce usare le schede e fornisce una stringa che consente il raggruppamento di Windows dell'app in Schede:
// Prefer Tabbed Windows
Window.TabbingMode = NSWindowTabbingMode.Preferred;
Window.TabbingIdentifier = "Main";
Il metodo di override seguente aggiunge un pulsante più alla barra delle schede che creerà un nuovo documento quando si fa clic sull'utente:
public override void GetNewWindowForTab (NSObject sender)
{
// Ask app to open a new document window
App.NewDocument (this);
}
Uso dell'animazione core
Core Animation è un motore di rendering grafico ad alta potenza integrato in macOS. L'animazione core è stata ottimizzata per sfruttare i vantaggi della GPU (unità di elaborazione grafica) disponibile nell'hardware macOS moderno anziché eseguire le operazioni grafiche sulla CPU, che può rallentare il computer.
L'oggetto CALayer
, fornito da Core Animation, può essere usato per attività quali scorrimento rapido e fluido e animazioni. L'interfaccia utente di un'app deve essere costituita da più visualizzazioni secondarie e livelli per sfruttare appieno l'animazione principale.
Un CALayer
oggetto fornisce diverse proprietà che consentono allo sviluppatore di controllare ciò che viene presentato sullo schermo all'utente, ad esempio:
Content
- Può essere un oggettoNSImage
oCGImage
che fornisce il contenuto del livello.BackgroundColor
- Imposta il colore di sfondo del livello come oggettoCGColor
BorderWidth
- Imposta la larghezza del bordo.BorderColor
- Imposta il colore del bordo.
Per usare Core Graphics nell'interfaccia utente dell'app, deve usare le visualizzazioni supportate dal livello, che Apple suggerisce che lo sviluppatore deve sempre abilitare nella visualizzazione contenuto della finestra. In questo modo, anche tutte le visualizzazioni figlio erediteranno automaticamente il backup del livello.
Inoltre, Apple suggerisce l'uso di visualizzazioni supportate dal livello anziché aggiungere un nuovo CALayer
sottostrato come sottostrato, perché il sistema gestirà automaticamente diverse delle impostazioni necessarie (ad esempio quelle richieste da un display Retina).
Il backup dei livelli può essere abilitato impostando su WantsLayer
NSView
true
o all'interno di Interface Builder di Xcode sotto Controllo effetti visualizzazione controllando il livello di animazione principale:
Ridisegno delle visualizzazioni con livelli
Un altro passaggio importante quando si usano le viste supportate dal livello in un'app Xamarin.Mac è l'impostazione LayerContentsRedrawPolicy
NSView
OnSetNeedsDisplay
di su in NSViewController
. Ad esempio:
public override void ViewWillAppear ()
{
base.ViewWillAppear ();
// Set the content redraw policy
View.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
}
Se lo sviluppatore non imposta questa proprietà, la visualizzazione verrà ridisegnata ogni volta che cambia l'origine dei fotogrammi, che non è desiderata per motivi di prestazioni. Con questa proprietà impostata sullo OnSetNeedsDisplay
sviluppatore sarà necessario impostare NeedsDisplay
manualmente su true
per forzare il ridisegno del contenuto.
Quando una visualizzazione è contrassegnata come dirty, il sistema controlla la WantsUpdateLayer
proprietà della visualizzazione. Se restituisce true
, viene chiamato il UpdateLayer
metodo , altrimenti viene chiamato il DrawRect
metodo della vista per aggiornare il contenuto di View.
Apple offre i suggerimenti seguenti per l'aggiornamento di un contenuto delle visualizzazioni quando necessario:
- Apple preferisce usare
UpdateLater
il piùDrawRect
possibile in quanto offre un aumento significativo delle prestazioni. - Usa la stessa opzione
layer.Contents
per gli elementi dell'interfaccia utente simili. - Apple preferisce anche lo sviluppatore di comporre l'interfaccia utente usando visualizzazioni standard,
NSTextField
ad esempio , quando possibile.
Per usare UpdateLayer
, creare una classe personalizzata per NSView
e rendere il codice simile al seguente:
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
}
}
Uso del trascinamento e della selezione moderni
Per presentare un'esperienza di trascinamento e rilascio moderna per l'utente, lo sviluppatore deve adottare drag flocking nelle operazioni di trascinamento della selezione dell'app. Il trascinamento di Flocking è il punto in cui ogni singolo file o elemento trascinato viene inizialmente visualizzato come singolo elemento che esegue il raggruppamento (raggruppato sotto il cursore con un conteggio del numero di elementi) man mano che l'utente continua l'operazione di trascinamento.
Se l'utente termina l'operazione di trascinamento, i singoli elementi ribloccheranno e torneranno alle posizioni originali.
Il codice di esempio seguente abilita Drag Flocking in una visualizzazione personalizzata:
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'effetto flocking è stato ottenuto inviando ogni elemento trascinato al BeginDraggingSession
metodo di NSView
come elemento separato in una matrice.
Quando si utilizza un NSTableView
oggetto o NSOutlineView
, usare il PastboardWriterForRow
metodo della NSTableViewDataSource
classe per avviare l'operazione Di trascinamento:
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
}
}
In questo modo lo sviluppatore può fornire un singolo elemento NSDraggingItem
per ogni elemento della tabella trascinato anziché il metodo WriteRowsWith
precedente che scrive tutte le righe come singolo gruppo nella lavagna.
Quando si lavora con NSCollectionViews
, usare di nuovo il PasteboardWriterForItemAt
metodo anziché il metodo all'inizio WriteItemsAt
del trascinamento.
Lo sviluppatore deve sempre evitare di inserire file di grandi dimensioni nella lavagna. Novità di macOS Sierra, Le promesse di file consentono allo sviluppatore di inserire riferimenti ai file specificati nella lavagna che verrà soddisfatta in un secondo momento quando l'utente completa l'operazione Drop usando le nuove NSFilePromiseProvider
classi e NSFilePromiseReceiver
.
Uso del rilevamento eventi moderno
Per un elemento dell'interfaccia utente ( ad esempio un NSButton
) aggiunto a un'area Titolo o Barra degli strumenti, l'utente deve essere in grado di fare clic sull'elemento e di attivare un evento come di consueto, ad esempio la visualizzazione di una finestra popup. Tuttavia, poiché l'elemento si trova anche nell'area Titolo o Barra degli strumenti, l'utente dovrebbe essere in grado di fare clic e trascinare anche l'elemento per spostare la finestra.
A tale scopo nel codice, creare una classe personalizzata per l'elemento (ad esempio NSButton
) ed eseguire l'override dell'evento MouseDown
come indicato di seguito:
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);
}
}
Questo codice usa il TrackEventsMatching
metodo dell'elemento NSWindow
associato all'interfaccia utente per intercettare gli LeftMouseUp
eventi e LeftMouseDragged
. Per un LeftMouseUp
evento, l'elemento dell'interfaccia utente risponde come di consueto. Per l'evento, l'evento LeftMouseDragged
viene passato al NSWindow
metodo del PerformWindowDrag
per spostare la finestra sullo schermo.
La chiamata al PerformWindowDrag
metodo della NSWindow
classe offre i vantaggi seguenti:
- Consente lo spostamento della finestra, anche se l'app è bloccata, ad esempio durante l'elaborazione di un ciclo profondo.
- Il cambio di spazio funzionerà come previsto.
- La barra spazi verrà visualizzata normalmente.
- L'allineamento e l'allineamento della finestra funzionano normalmente.
Uso di controlli di visualizzazione contenitori moderni
macOS Sierra offre molti miglioramenti moderni ai controlli visualizzazione contenitore esistenti disponibili nella versione precedente del sistema operativo.
Miglioramenti alla visualizzazione tabella
Lo sviluppatore deve usare sempre la nuova NSView
versione basata dei controlli visualizzazione contenitore, NSTableView
ad esempio . Ad esempio:
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
}
}
In questo modo è possibile allegare azioni di riga di tabella personalizzate alle righe della tabella, ad esempio scorrendo a destra per eliminare la riga. Per abilitare questo comportamento, eseguire l'override NSTableViewDelegate
del RowActions
metodo di :
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
}
}
L'oggetto statico NSTableViewRowAction.FromStyle
viene usato per creare una nuova azione di riga di tabella degli stili seguenti:
Regular
- Esegue un'azione standard non distruttiva, ad esempio la modifica del contenuto della riga.Destructive
- Esegue un'azione distruttiva, ad esempio eliminare la riga dalla tabella. Il rendering di queste azioni verrà eseguito con uno sfondo rosso.
Miglioramenti alla visualizzazione scorrimento
Quando si usa direttamente una visualizzazione di scorrimento (NSScrollView
) o come parte di un altro controllo (ad esempio NSTableView
), il contenuto della visualizzazione di scorrimento può scorrere nelle aree Titolo e Barra degli strumenti in un'app Xamarin.Mac usando un aspetto e visualizzazioni moderne.
Di conseguenza, il primo elemento nell'area contenuto Visualizzazione scorrimento può essere parzialmente nascosto dall'area Titolo e Barra degli strumenti.
Per risolvere questo problema, Apple ha aggiunto due nuove proprietà alla NSScrollView
classe :
ContentInsets
- Consente allo sviluppatore di fornire unNSEdgeInsets
oggetto che definisce l'offset che verrà applicato alla parte superiore della visualizzazione di scorrimento.AutomaticallyAdjustsContentInsets
- Setrue
la visualizzazione di scorrimento gestirà automaticamente l'oggettoContentInsets
per lo sviluppatore.
Usando lo ContentInsets
sviluppatore può regolare l'inizio della visualizzazione di scorrimento per consentire l'inclusione di accessori come:
- Indicatore di ordinamento simile a quello visualizzato nell'app Posta.
- Campo di ricerca.
- Pulsante Aggiorna o Aggiorna.
Layout automatico e localizzazione nelle app moderne
Apple ha incluso diverse tecnologie in Xcode che consentono allo sviluppatore di creare facilmente un'app macOS internazionalizzata. Xcode consente ora allo sviluppatore di separare il testo rivolto all'utente dalla progettazione dell'interfaccia utente dei file storyboard dell'app e fornisce strumenti per mantenere questa separazione se l'interfaccia utente cambia.
Per altre informazioni, vedere la Guida alla localizzazione e all'internazionalizzazione di Apple.
Implementazione dell'internazionalizzazione di base
Implementando l'internazionalizzazione di base, lo sviluppatore può fornire un singolo file Storyboard per rappresentare l'interfaccia utente dell'app e separare tutte le stringhe rivolte all'utente.
Quando lo sviluppatore crea il file storyboard iniziale (o i file) che definiscono l'interfaccia utente dell'app, verranno compilati nell'internazionalizzazione di base (il linguaggio parlato dallo sviluppatore).
Successivamente, lo sviluppatore può esportare le localizzazioni e le stringhe di internazionalizzazione di base (nella progettazione dell'interfaccia utente storyboard) che possono essere tradotte in più lingue.
Successivamente, queste localizzazioni possono essere importate e Xcode genererà i file di stringa specifici della lingua per lo Storyboard.
Implementazione del layout automatico per supportare la localizzazione
Poiché le versioni localizzate dei valori stringa possono avere dimensioni molto diverse e/o direzione di lettura, lo sviluppatore deve usare layout automatico per posizionare e ridimensionare l'interfaccia utente dell'app in un file Storyboard.
Apple consiglia di eseguire le operazioni seguenti:
- Rimuovi vincoli di larghezza fissa: tutte le visualizzazioni basate su testo devono essere ridimensionate in base al contenuto. Visualizzazione a larghezza fissa può ritagliare il contenuto in lingue specifiche.
- Usa dimensioni intrinseche del contenuto: per impostazione predefinita, le visualizzazioni basate su testo verranno ridimensionate automaticamente per adattarne il contenuto. Per la visualizzazione basata su testo che non ridimensionano correttamente, selezionarle in Generatore interfacce di Xcode e quindi scegliere Modifica>dimensioni per adattare il contenuto.
- Applica attributi iniziali e finali: poiché la direzione del testo può cambiare in base alla lingua dell'utente, usare gli attributi nuovi
Leading
eTrailing
vincoli anziché gli attributi eLeft
esistentiRight
.Leading
eTrailing
regola automaticamente in base alla direzione delle lingue. - Aggiungi visualizzazioni a visualizzazioni adiacenti: consente alle visualizzazioni di riposizionare e ridimensionare quando le visualizzazioni vengono modificate in risposta alla lingua selezionata.
- Non impostare dimensioni minime e/o massime di Windows: consente a Windows di modificare le dimensioni quando la lingua selezionata ridimensiona le aree di contenuto.
- Modifiche al layout dei test in modo costante: durante lo sviluppo in un'app deve essere testato costantemente in linguaggi diversi. Per altri dettagli, vedere la documentazione relativa al test dell'app internazionalizzata di Apple.
- Usare NSStackViews per aggiungere visualizzazioni insieme -
NSStackViews
consente al contenuto di spostarsi e crescere in modi prevedibili e le dimensioni del contenuto cambiano in base alla lingua selezionata.
Localizzazione in Interface Builder di Xcode
Apple ha fornito diverse funzionalità in Interface Builder di Xcode che lo sviluppatore può usare durante la progettazione o la modifica dell'interfaccia utente di un'app per supportare la localizzazione. La sezione Direzione del testo di Controllo attributi consente allo sviluppatore di fornire suggerimenti su come usare e aggiornare la direzione in una visualizzazione basata su testo selezionata, ad esempio NSTextField
:
Esistono tre valori possibili per La direzione del testo:
- Naturale : il layout si basa sulla stringa assegnata al controllo.
- Da sinistra a destra : il layout viene sempre forzato a sinistra verso destra.
- Da destra a sinistra : il layout viene sempre forzato da destra a sinistra.
Per Layout sono disponibili due valori possibili:
- Da sinistra a destra : il layout è sempre da sinistra a destra.
- Da destra a sinistra : il layout è sempre da destra a sinistra.
In genere, questi non devono essere modificati a meno che non sia necessario un allineamento specifico.
La proprietà Mirror indica al sistema di capovolgere proprietà di controllo specifiche, ad esempio la posizione dell'immagine della cella. Ha tre possibili valori:
- Automatico: la posizione verrà modificata automaticamente in base alla direzione della lingua selezionata.
- In Interfaccia da destra a sinistra - La posizione verrà modificata solo in lingue basate su destra a sinistra.
- Mai - La posizione non cambierà mai.
Se lo sviluppatore ha specificato Center, Justify o Full alignment on the content of a text-based View, these will never be flipped based on language selected.If the developer has specified Center, Justify or Full alignment on the content of a text-based View, these will never flipped based language.
Prima di macOS Sierra, i controlli creati nel codice non verrebbero con mirroring automatico. Lo sviluppatore doveva usare codice simile al seguente per gestire il mirroring:
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;
}
}
Posizione in Alignment
cui e ImagePosition
vengono impostati in base all'oggetto UserInterfaceLayoutDirection
del controllo .
macOS Sierra aggiunge diversi nuovi costruttori pratici (tramite il metodo statico CreateButton
) che accettano diversi parametri (ad esempio Title, Image e Action) e eseguiranno automaticamente il mirroring. Ad esempio:
var button2 = NSButton.CreateButton (myTitle, myImage, () => {
// Take action when the button is pressed
...
});
Uso degli aspetti di sistema
Le app macOS moderne possono adottare un nuovo aspetto dell'interfaccia scura che funziona bene per la creazione di immagini, la modifica o le app di presentazione:
Questa operazione può essere eseguita aggiungendo una riga di codice prima che venga presentata la finestra. Ad esempio:
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
}
}
Il metodo statico GetAppearance
della NSAppearance
classe viene usato per ottenere un aspetto denominato dal sistema (in questo caso NSAppearance.NameVibrantDark
).
Apple offre i suggerimenti seguenti per l'uso degli aspetti del sistema:
- Preferisce i colori denominati rispetto ai valori hardcoded (ad esempio
LabelColor
eSelectedControlColor
). - Usa lo stile di controllo standard di sistema, se possibile.
Un'app macOS che usa l'aspetto del sistema funzionerà automaticamente per gli utenti che hanno abilitato le funzionalità di accessibilità dall'app Preferenze di sistema. Di conseguenza, Apple suggerisce che lo sviluppatore deve usare sempre aspetto di sistema nelle app macOS.
Progettazione di interfacce utente con storyboard
Gli storyboard consentono allo sviluppatore di progettare non solo i singoli elementi che costituiscono l'interfaccia utente di un'app, ma di visualizzare e progettare il flusso dell'interfaccia utente e la gerarchia degli elementi specificati.
I controller consentono allo sviluppatore di raccogliere gli elementi in un'unità di composizione e Segues astratti e rimuovere il tipico "codice glue" necessario per spostarsi in tutta la gerarchia di visualizzazione:
Per altre informazioni, vedere la documentazione introduttiva agli storyboard .
Esistono molte istanze in cui una determinata scena definita in uno storyboard richiederà i dati di una scena precedente nella gerarchia di visualizzazione. Apple offre i suggerimenti seguenti per passare informazioni tra le scene:
- Le dipendenze dei dati devono sempre scorrere verso il basso attraverso la gerarchia.
- Evitare l'hardcoding delle dipendenze strutturali dell'interfaccia utente, perché questo limita la flessibilità dell'interfaccia utente.
- Usare le interfacce C# per fornire dipendenze di dati generici.
Il controller di visualizzazione che funge da origine di Segue può eseguire l'override del PrepareForSegue
metodo ed eseguire qualsiasi inizializzazione necessaria (ad esempio il passaggio di dati) prima dell'esecuzione di Segue per visualizzare il controller di visualizzazione di destinazione. Ad esempio:
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;
}
}
Per altre informazioni, vedere la documentazione di Segues .
Propagazione di azioni
In base alla progettazione dell'app macOS, potrebbe verificarsi un momento in cui il gestore migliore per un'azione su un controllo dell'interfaccia utente potrebbe trovarsi altrove nella gerarchia dell'interfaccia utente. Questo è in genere vero dei menu e delle voci di menu che risiedono nella propria scena, separati dal resto dell'interfaccia utente dell'app.
Per gestire questa situazione, lo sviluppatore può creare un'azione personalizzata e passare l'azione fino alla catena del risponditore. Per altre informazioni, vedere la documentazione Sull'uso delle azioni finestra personalizzate.
Funzionalità Mac moderne
Apple ha incluso diverse funzionalità rivolte agli utenti in macOS Sierra che consentono allo sviluppatore di sfruttare al meglio la piattaforma Mac, ad esempio:
- NSUserActivity : consente all'app di descrivere l'attività attualmente coinvolta dall'utente.
NSUserActivity
è stato inizialmente creato per supportare HandOff, in cui un'attività avviata in uno dei dispositivi dell'utente potrebbe essere prelevata e continuata in un altro dispositivo.NSUserActivity
funziona allo stesso modo in macOS come in iOS, quindi vedere la documentazione introduttiva a Handoff iOS per altri dettagli. - Siri su Mac : Siri usa l'attività corrente (
NSUserActivity
) per fornire contesto ai comandi che un utente può eseguire. - Ripristino dello stato: quando l'utente chiude un'app in macOS e quindi la riavvia in un secondo momento, l'app verrà ripristinata automaticamente allo stato precedente. Lo sviluppatore può usare l'API ripristino dello stato per codificare e ripristinare gli stati temporanei dell'interfaccia utente prima che l'interfaccia utente venga visualizzata all'utente. Se l'app è
NSDocument
basata, il ripristino dello stato viene gestito automaticamente. Per abilitare il ripristino dello stato per le app nonNSDocument
basate, impostare laRestorable
proprietà dellaNSWindow
classe sutrue
. - Documenti nel cloud : prima di macOS Sierra, un'app doveva acconsentire esplicitamente all'uso dei documenti nell'iCloud Drive dell'utente. In macOS Sierra le cartelle Desktop e Documenti dell'utente possono essere sincronizzate automaticamente con il proprio iCloud Drive dal sistema. Di conseguenza, le copie locali dei documenti possono essere eliminate per liberare spazio nel computer dell'utente.
NSDocument
le app basate gestiranno automaticamente questa modifica. Tutti gli altri tipi di app dovranno usare perNSFileCoordinator
sincronizzare la lettura e la scrittura di documenti.
Riepilogo
Questo articolo ha illustrato diversi suggerimenti, funzionalità e tecniche che uno sviluppatore può usare per creare un'app macOS moderna in Xamarin.Mac.