Erstellen moderner macOS-Apps
In diesem Artikel werden mehrere Tipps, Features und Techniken behandelt, die ein Entwickler zum Erstellen einer modernen macOS-App in Xamarin.Mac verwenden kann.
Erstellen moderner Designs mit modernen Ansichten
Ein modernes Aussehen enthält eine moderne Fenster- und Symbolleistendarstellung, z. B. die unten gezeigte Beispiel-App:
Aktivieren von Inhaltsansichten in voller Größe
Um dies in einer Xamarin.Mac-App zu erreichen, möchte der Entwickler eine Inhaltsansicht mit voller Größe verwenden, was bedeutet, dass sich der Inhalt unter den Bereichen Tool und Titelleiste erweitert und von macOS automatisch verschwommen wird.
Um dieses Feature im Code zu aktivieren, erstellen Sie eine benutzerdefinierte Klasse für die NSWindowController
und lassen sie wie folgt aussehen:
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
}
}
Dieses Feature kann auch im Benutzeroberflächen-Generator von Xcode aktiviert werden, indem sie das Fenster auswählen und die Inhaltsansicht in voller Größe überprüfen:
Wenn Sie eine Inhaltsansicht mit voller Größe verwenden, muss der Entwickler den Inhalt möglicherweise unter den Titel- und Symbolleistenbereichen versatzen, sodass bestimmte Inhalte (z. B. Bezeichnungen) nicht darunter geschoben werden.
Um dieses Problem zu erschweren, können die Bereiche "Titel" und "Toolleiste" eine dynamische Höhe basierend auf der Aktion aufweisen, die der Benutzer gerade ausführt, die Version von macOS, die der Benutzer installiert hat, und/oder die Mac-Hardware, auf der die App ausgeführt wird.
Daher funktioniert das Einfache hartcodieren des Offsets beim Gestalten der Benutzeroberfläche nicht. Der Entwickler muss einen dynamischen Ansatz verfolgen.
Apple enthält die Key-Value Observable-EigenschaftContentLayoutRect
der NSWindow
Klasse, um den aktuellen Inhaltsbereich im Code abzurufen. Der Entwickler kann diesen Wert verwenden, um die erforderlichen Elemente manuell zu positionieren, wenn sich der Inhaltsbereich ändert.
Die bessere Lösung ist die Verwendung von AutoLayout- und Größenklassen, um die UI-Elemente entweder im Code oder im Schnittstellen-Generator zu positionieren.
Code wie das folgende Beispiel kann verwendet werden, um UI-Elemente mithilfe von AutoLayout- und Größenklassen im Ansichtscontroller der App zu positionieren:
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
}
}
Dieser Code erstellt Speicher für eine obere Einschränkung, die auf eine Bezeichnung (ItemTitle
) angewendet wird, um sicherzustellen, dass sie nicht unter den Bereich "Titel" und "Symbolleiste" fällt:
public NSLayoutConstraint topConstraint { get; set; }
Durch Überschreiben der Methode des Ansichtscontrollers UpdateViewConstraints
kann der Entwickler testen, ob die erforderliche Einschränkung bereits erstellt und bei Bedarf erstellt wurde.
Wenn eine neue Einschränkung erstellt werden muss, wird auf die ContentLayoutGuide
Eigenschaft des Window-Steuerelements zugegriffen, auf das eingeschränkt werden muss, und in eine NSLayoutGuide
:
var contentLayoutGuide = ItemTitle.Window?.ContentLayoutGuide as NSLayoutGuide;
Auf die TopAnchor-Eigenschaft der Datei NSLayoutGuide
wird zugegriffen, und wenn sie verfügbar ist, wird sie verwendet, um eine neue Einschränkung mit dem gewünschten Offsetbetrag zu erstellen, und die neue Einschränkung wird aktiviert, um sie anzuwenden:
// Assemble constraint and activate it
topConstraint = topAnchor.ConstraintEqualToAnchor (topAnchor, 20);
topConstraint.Active = true;
Aktivieren optimierter Symbolleisten
Ein normales macOS-Fenster enthält eine standardmäßige Titelleiste, die am oberen Rand des Fensters ausgeführt wird. Wenn das Fenster auch eine Symbolleiste enthält, wird es unter diesem Titelleistenbereich angezeigt:
Wenn Sie eine optimierte Symbolleiste verwenden, verschwindet der Titelbereich, und die Symbolleiste wird in der Position der Titelleiste in Übereinstimmung mit den Schaltflächen "Fenster schließen", "Minimieren" und "Maximieren" nach oben verschoben:
Die optimierte Symbolleiste wird durch Überschreiben der ViewWillAppear
Methode der NSViewController
optimierten Symbolleiste aktiviert und sieht wie folgt aus:
public override void ViewWillAppear ()
{
base.ViewWillAppear ();
// Enable streamlined Toolbars
View.Window.TitleVisibility = NSWindowTitleVisibility.Hidden;
}
Dieser Effekt wird in der Regel für Shoebox-Anwendungen (eine Fenster-Apps) wie Karten, Kalender, Notizen und Systemeinstellungen verwendet.
Verwenden von Zubehöransichtscontrollern
Je nach Design der App möchte der Entwickler möglicherweise auch den Titelleistenbereich durch einen Zubehör-Ansichtscontroller ergänzen, der direkt unterhalb des Bereichs "Titel-/Toolleiste" angezeigt wird, um kontextabhängige Steuerelemente für den Benutzer basierend auf der aktivität bereitzustellen, an der sie derzeit beteiligt sind:
Der Zubehöransichtscontroller wird automatisch verschwommen und die Größe des Systems ohne Eingreifen des Entwicklers geändert.
Gehen Sie wie folgt vor, um einen Zubehör-Ansichtscontroller hinzuzufügen:
Doppelklicken Sie im Projektmappen-Explorer auf die Datei
Main.storyboard
, um sie zur Bearbeitung zu öffnen.Ziehen Sie einen benutzerdefinierten Ansichtscontroller in die Hierarchie des Fensters:
Layout der Ui der Zubehöransicht:
Machen Sie die Zubehöransicht als Steckdose und alle anderen Aktionen oder Outlets für die Benutzeroberfläche verfügbar:
Speichern Sie die Änderungen.
Kehren Sie zu Visual Studio für Mac zurück, um die Änderungen zu synchronisieren.
Bearbeiten Sie das NSWindowController
Und machen Sie es wie folgt aussehen:
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
}
}
Die wichtigsten Punkte dieses Codes sind der Ort, an dem die Ansicht auf die benutzerdefinierte Ansicht festgelegt ist, die im Schnittstellen-Generator definiert und als Steckdose verfügbar gemacht wurde:
accessoryView.View = AccessoryViewGoBar;
Und das LayoutAttribute
definiert , wo das Zubehör angezeigt wird:
accessoryView.LayoutAttribute = NSLayoutAttribute.Bottom;
Da macOS jetzt vollständig lokalisiert ist, sind die Left
Eigenschaften Right
NSLayoutAttribute
veraltet und sollten durch Leading
und Trailing
ersetzt werden.
Verwenden von Windows-Registerkarten
Darüber hinaus kann das macOS-System Zubehör-Ansichtscontroller zum Fenster der App hinzufügen. Um beispielsweise Tabbed Windows zu erstellen, in dem mehrere der Windows-Apps in einem virtuellen Fenster zusammengeführt werden:
In der Regel muss der Entwickler in seinen Xamarin.Mac-Apps tabbed Windows verwenden, das System behandelt sie automatisch wie folgt:
- Windows wird beim Aufrufen der
OrderFront
Methode automatisch Tabstopps angezeigt. - Windows wird beim Aufrufen der
OrderOut
Methode automatisch untabbediert. - Im Code werden alle Tabbed-Fenster weiterhin als "sichtbar" betrachtet, jedoch werden alle Nicht-Front-Tabs vom System mit CoreGraphics ausgeblendet.
- Verwenden Sie die
TabbingIdentifier
Eigenschaft,NSWindow
um Windows in Registerkarten zu gruppieren. - Wenn es sich um eine
NSDocument
basierte App handelt, werden mehrere dieser Features automatisch aktiviert (z. B. die Plusschaltfläche, die der Registerkartenleiste hinzugefügt wird) ohne Entwickleraktion. NSDocument
Nicht basierende Apps können die Schaltfläche "Plus" in der Registerkartengruppe aktivieren, um ein neues Dokument hinzuzufügen, indem dieGetNewWindowForTab
Methode derNSWindowsController
.
Wenn Sie alle Teile zusammenführen, könnte die AppDelegate
App, die systembasierte Windows-Registerkarten verwenden wollte, wie folgt aussehen:
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
}
}
Wo die NewDocumentNumber
Eigenschaft die Anzahl der neuen Dokumente nachverfolgt, die erstellt wurden, und die NewDocument
Methode erstellt ein neues Dokument und zeigt es an.
Die NSWindowController
könnte dann wie folgt aussehen:
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
}
}
Wo die statische App
Eigenschaft eine Verknüpfung zum Aufrufen der AppDelegate
. Die SetDefaultDocumentTitle
Methode legt basierend auf der Anzahl der erstellten neuen Dokumente einen neuen Dokumenttitel fest.
Der folgende Code teilt macOS mit, dass die App Registerkarten bevorzugt, und stellt eine Zeichenfolge bereit, mit der die Windows-App in Registerkarten gruppiert werden kann:
// Prefer Tabbed Windows
Window.TabbingMode = NSWindowTabbingMode.Preferred;
Window.TabbingIdentifier = "Main";
Die folgende Überschreibungsmethode fügt der Registerkartenleiste eine Plusschaltfläche hinzu, die ein neues Dokument erstellt, wenn der Benutzer darauf klickt:
public override void GetNewWindowForTab (NSObject sender)
{
// Ask app to open a new document window
App.NewDocument (this);
}
Verwenden der Kernanimation
Kernanimation ist ein leistungsstarkes Grafikrenderingmodul, das in macOS integriert ist. Die Kernanimation wurde optimiert, um die GPU (Graphics Processing Unit) zu nutzen, die in moderner macOS-Hardware verfügbar ist, anstatt die Grafikvorgänge auf der CPU auszuführen, was den Computer verlangsamen kann.
Die CALayer
von der Kernanimation bereitgestellte Animation kann für Aufgaben wie schnelles und flüssiges Scrollen und Animationen verwendet werden. Die Benutzeroberfläche einer App sollte aus mehreren Unteransichten und Ebenen bestehen, um die Hauptanimation vollständig nutzen zu können.
Ein CALayer
Objekt bietet mehrere Eigenschaften, mit denen der Entwickler steuern kann, was dem Benutzer auf dem Bildschirm angezeigt wird, z. B.:
Content
- Dies kann einNSImage
oderCGImage
der den Inhalt der Ebene bereitstellt.BackgroundColor
- Legt die Hintergrundfarbe der Ebene als eineCGColor
BorderWidth
- Legt die Rahmenbreite fest.BorderColor
- Legt die Rahmenfarbe fest.
Um Kerngrafiken in der Benutzeroberfläche der App zu verwenden, muss sie Layer Backed Views verwenden, was Apple vorschlägt, dass der Entwickler immer in der Inhaltsansicht des Fensters aktivieren sollte. Auf diese Weise erben alle untergeordneten Ansichten automatisch auch layer backing.
Darüber hinaus schlägt Apple vor, layer backed Views zu verwenden, anstatt eine neue CALayer
als Unterlayer hinzuzufügen, da das System automatisch mehrere der erforderlichen Einstellungen verarbeitet (z. B. diejenigen, die von einem Retina Display benötigt werden).
Die Layersicherung kann aktiviert werden, indem sie den WantsLayer
Schnittstellen-Generator von NSView
true
Xcode im Ansichtseffekt-Inspektor festlegen, indem Sie die Kernanimationsschicht überprüfen:
Neuauszeichnen von Ansichten mit Ebenen
Ein weiterer wichtiger Schritt bei der Verwendung von Layer Backed Views in einer Xamarin.Mac-App ist das LayerContentsRedrawPolicy
Festlegen des Werts NSView
OnSetNeedsDisplay
in der NSViewController
Zum Beispiel:
public override void ViewWillAppear ()
{
base.ViewWillAppear ();
// Set the content redraw policy
View.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
}
Wenn der Entwickler diese Eigenschaft nicht festlegt, wird die Ansicht immer neu gezeichnet, wenn sich der Frameursprung ändert, was aus Leistungsgründen nicht gewünscht wird. Wenn diese Eigenschaft auf OnSetNeedsDisplay
den Entwickler festgelegt ist, muss dies manuell festgelegt werden NeedsDisplay
, damit true
der Inhalt jedoch neu gezeichnet wird.
Wenn eine Ansicht als modifiziert markiert ist, überprüft das System die WantsUpdateLayer
Eigenschaft der Ansicht. Wenn die Methode zurückgegeben true
wird, wird die UpdateLayer
Methode aufgerufen, andernfalls wird die DrawRect
Methode der Ansicht aufgerufen, um den Inhalt der Ansicht zu aktualisieren.
Apple hat bei Bedarf die folgenden Vorschläge zum Aktualisieren eines Views-Inhalts:
- Apple bevorzugt die Verwendung
UpdateLater
nach Möglichkeit,DrawRect
da es eine erhebliche Leistungssteigerung bietet. - Verwenden Sie dasselbe
layer.Contents
für UI-Elemente, die ähnlich aussehen. - Apple bevorzugt auch den Entwickler, seine Benutzeroberfläche mithilfe von Standardansichten zu verfassen, z
NSTextField
. B. immer wieder.
Erstellen Sie zum Verwenden UpdateLayer
eine benutzerdefinierte Klasse für den NSView
Code, und gestalten Sie den Code wie folgt:
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
}
}
Verwenden des modernen Ziehens und Ablegens
Um dem Benutzer eine moderne Drag- und Drop-Oberfläche zu bieten, sollte der Entwickler Drag Flocking in den Drag and Drop-Vorgängen ihrer App übernehmen. Drag Flocking ist der Ort, an dem jede einzelne Datei oder jedes Element, das gezogen wird, anfangs als einzelnes Element angezeigt wird, das sich zusammen unter dem Cursor mit einer Anzahl der Elemente gruppieren kann, während der Benutzer den Ziehvorgang fortsetzt.
Wenn der Benutzer den Drag-Vorgang beendet, werden die einzelnen Elemente entflockt und zu ihren ursprünglichen Positionen zurückkehren.
Im folgenden Beispielcode wird Drag Flocking in einer benutzerdefinierten Ansicht aktiviert:
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
}
}
Der Herdeeffekt wurde erreicht, indem jedes Element an die BeginDraggingSession
Methode des NSView
als separates Element in einem Array gezogen wird.
Verwenden Sie beim Arbeiten mit einer oder oder NSTableView
NSOutlineView
der Klasse die PastboardWriterForRow
Methode, NSTableViewDataSource
um den Dragging-Vorgang zu starten:
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
}
}
Dadurch kann der Entwickler eine Einzelperson NSDraggingItem
für jedes Element in der Tabelle bereitstellen, das gezogen wird, im Gegensatz zu der älteren Methode WriteRowsWith
, die alle Zeilen als einzelne Gruppe in das Einfügebrett schreibt.
Verwenden Sie beim Arbeiten mit NSCollectionViews
der Methode erneut die PasteboardWriterForItemAt
Methode im Gegensatz zu der WriteItemsAt
Methode, wenn das Ziehen beginnt.
Der Entwickler sollte immer vermeiden, große Dateien auf dem Einfügebrett zu platzieren. New to macOS Sierra, File Promises allow the developer to place references to given files on the pasteboard that will later be erfüllt when the user finishes the Drop operation using the new NSFilePromiseProvider
and NSFilePromiseReceiver
classes.
Verwenden der modernen Ereignisverfolgung
Bei einem Benutzeroberflächenelement (z. B. a NSButton
), das einem Titel- oder Toolleistenbereich hinzugefügt wurde, sollte der Benutzer auf das Element klicken und ein Ereignis als normal auslösen lassen (z. B. anzeigen eines Popupfensters). Da sich das Element jedoch auch im Bereich "Titel" oder "Symbolleiste" befindet, sollte der Benutzer auch auf das Element klicken und ziehen können, um das Fenster zu verschieben.
Erstellen Sie dazu im Code eine benutzerdefinierte Klasse für das Element (z NSButton
. B. ) und überschreiben Sie das MouseDown
Ereignis wie folgt:
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);
}
}
Dieser Code verwendet die TrackEventsMatching
Methode, mit der NSWindow
das UI-Element verknüpft ist, um die LeftMouseUp
Ereignisse abzufangen LeftMouseDragged
. Bei einem LeftMouseUp
Ereignis antwortet das UI-Element normal. Für das LeftMouseDragged
Ereignis wird das Ereignis an die NSWindow
's PerformWindowDrag
Methode übergeben, um das Fenster auf dem Bildschirm zu verschieben.
Das Aufrufen der PerformWindowDrag
Methode der NSWindow
Klasse bietet die folgenden Vorteile:
- Das Fenster kann verschoben werden, auch wenn die App nicht mehr reagiert (z. B. beim Verarbeiten einer Deep-Schleife).
- Der Leerraumwechsel funktioniert wie erwartet.
- Die Leerzeichenleiste wird normal angezeigt.
- Das Ausrichten und Ausrichten von Fenstern funktionieren normal.
Verwenden moderner Containeransichtssteuerelemente
macOS Sierra bietet viele moderne Verbesserungen an den vorhandenen Containeransichtssteuerelementen, die in früheren Versionen des Betriebssystems verfügbar sind.
Verbesserungen der Tabellenansicht
Der Entwickler sollte immer die neue NSView
basierte Version von Containeransichtssteuerelementen verwenden, z NSTableView
. B. . Zum Beispiel:
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
}
}
Dadurch können benutzerdefinierte Tabellenzeilenaktionen an bestimmte Zeilen in der Tabelle angefügt werden (z. B. Wischen nach rechts zum Löschen der Zeile). Um dieses Verhalten zu aktivieren, überschreiben Sie die RowActions
Methode der 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
}
}
Die statische Wird verwendet, um eine neue Tabellenzeilenaktion NSTableViewRowAction.FromStyle
der folgenden Formatvorlagen zu erstellen:
Regular
– Führt eine standardmäßige, nicht destruktive Aktion aus, z. B. das Bearbeiten des Zeileninhalts.Destructive
– Führt eine destruktive Aktion aus, z. B. das Löschen der Zeile aus der Tabelle. Diese Aktionen werden mit einem roten Hintergrund gerendert.
Verbesserungen der Bildlaufansicht
Wenn Sie eine Bildlaufansicht (NSScrollView
) direkt oder als Teil eines anderen Steuerelements (z NSTableView
. B. ) verwenden, kann der Inhalt der Bildlaufansicht unter den Bereichen Titel und Symbolleiste in einer Xamarin.Mac-App mit einem modernen Aussehen und Ansichten schieben.
Daher kann das erste Element im Inhaltsbereich der Bildlaufansicht teilweise vom Bereich "Titel" und "Symbolleiste" verdeckt werden.
Um dieses Problem zu beheben, hat Apple der NSScrollView
Klasse zwei neue Eigenschaften hinzugefügt:
ContentInsets
– Ermöglicht es dem Entwickler, einNSEdgeInsets
Objekt bereitzustellen, das den Offset definiert, der oben in der Bildlaufansicht angewendet wird.AutomaticallyAdjustsContentInsets
– Wenntrue
die Bildlaufansicht denContentInsets
Entwickler automatisch behandelt.
Mithilfe des ContentInsets
Entwicklers kann der Start der Bildlaufansicht angepasst werden, um die Aufnahme von Zubehör wie:
- Eine Sortieranzeige wie die in der Mail-App angezeigte.
- Ein Suchfeld.
- Eine Schaltfläche "Aktualisieren" oder "Aktualisieren".
Automatisches Layout und Lokalisierung in modernen Apps
Apple enthält mehrere Technologien in Xcode, mit denen der Entwickler problemlos eine internationalisierte macOS-App erstellen kann. Xcode ermöglicht es dem Entwickler jetzt, benutzergerichteten Text aus dem Benutzeroberflächendesign der App in den Storyboarddateien zu trennen und Tools zum Standard beibehalten, wenn sich die Benutzeroberfläche ändert.
Weitere Informationen finden Sie im Internationalisierungs- und Lokalisierungshandbuch von Apple.
Implementieren der Basis-Internationalisierung
Durch die Implementierung der Base Internationalization kann der Entwickler eine einzelne Storyboarddatei bereitstellen, um die Benutzeroberfläche der App darzustellen und alle benutzerorientierten Zeichenfolgen zu trennen.
Wenn der Entwickler die anfängliche Storyboarddatei (oder Dateien) erstellt, die die Benutzeroberfläche der App definieren, werden sie in der Base Internationalization (die Sprache, die der Entwickler spricht) erstellt.
Als Nächstes kann der Entwickler Lokalisierungen und die Base Internationalization-Zeichenfolgen (im Storyboard-UI-Design) exportieren, die in mehrere Sprachen übersetzt werden können.
Später können diese Lokalisierungen importiert werden, und Xcode generiert die sprachspezifischen Zeichenfolgendateien für das Storyboard.
Implementieren des automatischen Layouts zur Unterstützung der Lokalisierung
Da lokalisierte Versionen von Zeichenfolgenwerten sehr große Größen und/oder Leserichtung aufweisen können, sollte der Entwickler das automatische Layout verwenden, um die Benutzeroberfläche der App in einer Storyboarddatei zu positionieren und zu vergrößern.
Apple schlägt Folgendes vor:
- Einschränkungen für feste Breite entfernen – Alle textbasierten Ansichten sollten die Größe basierend auf ihrem Inhalt ändern dürfen. Die Ansicht mit fester Breite kann ihre Inhalte in bestimmten Sprachen zuschneiden.
- Verwenden Sie systeminterne Inhaltsgrößen : Standardmäßig werden textbasierte Ansichten automatisch so angepasst, dass sie ihren Inhalt anpassen. Wählen Sie für textbasierte Ansicht, die nicht ordnungsgemäß angepasst wird, diese im Schnittstellen-Generator von Xcode aus, und wählen Sie dann "Größe an Inhalt anpassen">aus.
- Anwenden von vorangestellten und nachgestellten Attributen – Da sich die Richtung des Texts basierend auf der Sprache des Benutzers ändern kann, verwenden Sie die neuen
Leading
und Einschränkungsattribute im Gegensatz zu den vorhandenenRight
undTrailing
Left
Attributen.Leading
undTrailing
wird basierend auf der Sprachenrichtung automatisch angepasst. - An angrenzende Ansichten anheften – Dies ermöglicht es den Ansichten, die Position zu ändern und ihre Größe zu ändern, wenn sich die Ansichten um sie herum ändern, als Reaktion auf die ausgewählte Sprache.
- Legen Sie keine Windows-Mindest- und/oder Maximalgrößen fest: Windows kann die Größe ändern, wenn die ausgewählte Sprache die Größe ihrer Inhaltsbereiche ändert.
- Ständiges Testen des Layouts – Während der Entwicklung bei der App sollte ständig in verschiedenen Sprachen getestet werden. Weitere Details finden Sie in der Dokumentation zu Apple Testing Your Internationalized App .
- Mit NSStackViews können Sie Ansichten zusammen -
NSStackViews
anheften, sodass ihre Inhalte auf vorhersehbare Weise verschoben und vergrößert werden können und die Größe der Inhalte basierend auf der ausgewählten Sprache geändert wird.
Lokalisieren im Schnittstellen-Generator von Xcode
Apple hat mehrere Features im Benutzeroberflächen-Generator von Xcode bereitgestellt, die der Entwickler beim Entwerfen oder Bearbeiten der Benutzeroberfläche einer App verwenden kann, um die Lokalisierung zu unterstützen. Der Abschnitt "Textrichtung " des Attributinspektors ermöglicht es dem Entwickler, Hinweise zur Verwendung und Aktualisierung der Richtung in einer ausgewählten textbasierten Ansicht (z NSTextField
. B. ):
Es gibt drei mögliche Werte für die Textrichtung:
- Natürlich – Das Layout basiert auf der Zeichenfolge, die dem Steuerelement zugewiesen ist.
- Von links nach rechts – Das Layout wird immer nach links nach rechts gezwungen.
- Von rechts nach links – Das Layout wird immer nach rechts nach links gezwungen.
Für das Layout gibt es zwei mögliche Werte:
- Von links nach rechts - Das Layout ist immer von links nach rechts.
- Von rechts nach links - Das Layout ist immer von rechts nach links.
Diese sollten in der Regel nur geändert werden, wenn eine bestimmte Ausrichtung erforderlich ist.
Die Mirror-Eigenschaft weist das System an, bestimmte Steuerelementeigenschaften (z. B. die Zellenbildposition) zu kippen. Es gibt drei mögliche Werte:
- Automatisch – Die Position ändert sich automatisch basierend auf der richtung der ausgewählten Sprache.
- In der Schnittstelle von rechts nach links – Die Position wird nur in Rechts-nach-links-basierten Sprachen geändert.
- Nie - Die Position wird sich nie ändern.
Wenn der Entwickler die Ausrichtung "Center", "Blocksatz" oder "Vollständig" für den Inhalt einer textbasierten Ansicht angegeben hat, werden diese basierend auf der ausgewählten Sprache niemals gekippt.
Vor macOS Sierra wurden steuerelemente, die im Code erstellt wurden, nicht automatisch Spiegel. Der Entwickler musste Code wie den folgenden verwenden, um Spiegel ing zu behandeln:
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;
}
}
Gibt an, wo das Alignment
Steuerelement ImagePosition
basierend auf UserInterfaceLayoutDirection
dem Steuerelement festgelegt wird.
macOS Sierra fügt mehrere neue Komfortkonstruktoren (über die statische CreateButton
Methode) hinzu, die mehrere Parameter (z. B. Title, Image und Action) verwenden und automatisch ordnungsgemäß Spiegel. Zum Beispiel:
var button2 = NSButton.CreateButton (myTitle, myImage, () => {
// Take action when the button is pressed
...
});
Verwenden von Systemdarstellungen
Moderne macOS-Apps können ein neues Dunkles Interface-Aussehen übernehmen, das gut für Die Bilderstellung, -bearbeitung oder -präsentations-Apps geeignet ist:
Dazu können Sie eine Codezeile hinzufügen, bevor das Fenster angezeigt wird. Zum Beispiel:
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
}
}
Die statische GetAppearance
Methode der NSAppearance
Klasse wird verwendet, um eine benannte Darstellung aus dem System zu erhalten (in diesem Fall NSAppearance.NameVibrantDark
).
Apple hat die folgenden Vorschläge für die Verwendung von Systemdarstellungen:
- Bevorzugen Sie benannte Farben gegenüber hartcodierten Werten (z
LabelColor
. B. undSelectedControlColor
). - Verwenden Sie nach Möglichkeit das Systemstandard-Steuerelementformat.
Eine macOS-App, die die Systemdarstellungen verwendet, funktioniert automatisch ordnungsgemäß für Benutzer, die Barrierefreiheitsfeatures über die Systemeinstellungen-App aktiviert haben. Daher schlägt Apple vor, dass der Entwickler immer Systemdarstellungen in ihren macOS-Apps verwenden sollte.
Entwerfen von UIs mit Storyboards
Storyboards ermöglichen es entwicklern, nicht nur die einzelnen Elemente zu entwerfen, aus denen die Benutzeroberfläche einer App besteht, sondern den UI-Fluss und die Hierarchie der angegebenen Elemente visualisieren und entwerfen.
Controller ermöglichen es dem Entwickler, Elemente in einer Einheit von Komposition und Segues abstrakt zu sammeln und den typischen "Klebecode" zu entfernen, der zum Verschieben in der Ansichtshierarchie erforderlich ist:
Weitere Informationen finden Sie in unserer Dokumentation zur Einführung in Storyboards .
Es gibt viele Instanzen, in denen eine bestimmte Szene, die in einem Storyboard definiert ist, Daten aus einer vorherigen Szene in der Ansichtshierarchie erfordert. Apple hat die folgenden Vorschläge zum Übergeben von Informationen zwischen Szenen:
- Die Abhängigkeiten von Daten sollten immer nach unten durch die Hierarchie überlappen.
- Vermeiden Sie strukturelle Abhängigkeiten der Benutzeroberfläche, da dies die Flexibilität der Benutzeroberfläche begrenzt.
- Verwenden Sie C#-Schnittstellen, um generische Datenabhängige bereitzustellen.
Der Ansichtscontroller, der als Quelle der Segue fungiert, kann die Methode überschreiben und alle PrepareForSegue
erforderlichen Initialisierungen (z. B. Das Übergeben von Daten) ausführen, bevor der Segue ausgeführt wird, um den Zielansichtscontroller anzuzeigen. Zum Beispiel:
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;
}
}
Weitere Informationen finden Sie in unserer Segues-Dokumentation .
Verteilen von Aktionen
Basierend auf dem Design der macOS-App kann es vorkommen, dass sich der beste Handler für eine Aktion für ein UI-Steuerelement an einer anderen Stelle in der UI-Hierarchie befindet. Dies gilt in der Regel für Menüs und Menüelemente, die sich in ihrer eigenen Szene befinden, getrennt von der restlichen Benutzeroberfläche der App.
Um diese Situation zu behandeln, kann der Entwickler eine benutzerdefinierte Aktion erstellen und die Aktion an die Antwortkette übergeben. Weitere Informationen finden Sie in der Dokumentation "Arbeiten mit benutzerdefinierten Fensteraktionen ".
Moderne Mac-Features
Apple hat mehrere benutzerorientierte Features in macOS Sierra enthalten, die es dem Entwickler ermöglichen, die Mac-Plattform optimal zu nutzen, z. B.:
- NSUserActivity – Auf diese Weise kann die App die Aktivität beschreiben, an der der Benutzer derzeit beteiligt ist.
NSUserActivity
wurde ursprünglich erstellt, um HandOff zu unterstützen, wo eine Aktivität auf einem der Geräte des Benutzers aufgenommen und auf einem anderen Gerät fortgesetzt werden konnte.NSUserActivity
funktioniert in macOS genauso wie in iOS. Weitere Details finden Sie in unserer Dokumentation zur Handoff iOS. - Siri auf dem Mac – Siri verwendet die aktuelle Aktivität (
NSUserActivity
), um Kontext zu den Befehlen bereitzustellen, die ein Benutzer ausgeben kann. - Zustandswiederherstellung – Wenn der Benutzer eine App unter macOS beendet und später neu gestartet wird, wird die App automatisch in den vorherigen Zustand zurückgegeben. Der Entwickler kann die Zustandswiederherstellungs-API verwenden, um vorübergehende UI-Zustände zu codieren und wiederherzustellen, bevor die Benutzeroberfläche dem Benutzer angezeigt wird. Wenn die App
NSDocument
basiert, wird die Zustandswiederherstellung automatisch behandelt. Um die Zustandswiederherstellung für nichtNSDocument
basierte Apps zu aktivieren, legen Sie dieRestorable
NSWindow
Klasse auftrue
. - Dokumente in der Cloud – Vor macOS Sierra musste sich eine App explizit für die Arbeit mit Dokumenten im iCloud-Laufwerk des Benutzers anmelden. In macOS Sierra werden die Ordner "Desktop" und "Dokumente" des Benutzers möglicherweise automatisch mit ihrem iCloud-Laufwerk vom System synchronisiert. Daher können lokale Kopien von Dokumenten gelöscht werden, um Speicherplatz auf dem Computer des Benutzers freizugeben.
NSDocument
Basierende Apps behandeln diese Änderung automatisch. Alle anderen App-Typen müssen zumNSFileCoordinator
Synchronisieren von Lese- und Schreibvorgängen von Dokumenten verwendet werden.
Zusammenfassung
Dieser Artikel enthält mehrere Tipps, Features und Techniken, die ein Entwickler zum Erstellen einer modernen macOS-App in Xamarin.Mac verwenden kann.