Creación de aplicaciones modernas de macOS
En este artículo se tratan varias sugerencias, características y técnicas que un desarrollador puede usar para crear una aplicación macOS moderna en Xamarin.Mac.
Compilación de apariencias modernas con vistas modernas
Un aspecto moderno incluirá una apariencia moderna de ventana y barra de herramientas, como la aplicación de ejemplo que se muestra a continuación:
Habilitación de vistas de contenido de tamaño completo
Para lograr este aspecto en una aplicación de Xamarin.Mac, el desarrollador querrá usar una Vista de contenido de tamaño completo, lo que significa que el contenido se extiende en las áreas de herramientas y barra de título y se desenfocará automáticamente por macOS.
Para habilitar esta característica en el código, cree una clase personalizada para el NSWindowController
y haga que tenga un aspecto similar al siguiente:
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
}
}
Esta característica también se puede habilitar en Interface Builder de Xcode seleccionando la ventana y comprobando Vista de contenido de tamaño completo:
Al usar una vista de contenido de tamaño completo, es posible que el desarrollador tenga que desplazar el contenido debajo de las áreas de título y barra de herramientas para que el contenido específico (como etiquetas) no se deslice debajo de ellos.
Para complicar este problema, las áreas Título y Barra de herramientas pueden tener un alto dinámico en función de la acción que el usuario está realizando actualmente, la versión de macOS en la que el usuario ha instalado o el hardware Mac en el que se ejecuta la aplicación.
Como resultado, simplemente codificar de forma rígida el desplazamiento al diseñar la interfaz de usuario no funcionará. El desarrollador tendrá que adoptar un enfoque dinámico.
Apple ha incluido la propiedad Key-Value Observable ContentLayoutRect
de la NSWindow
clase para obtener el área de contenido actual en el código. El desarrollador puede usar este valor para colocar manualmente los elementos necesarios cuando cambia el área de contenido.
La mejor solución consiste en usar clases de diseño automático y tamaño para colocar los elementos de la interfaz de usuario en el código o en Interface Builder.
El código como el ejemplo siguiente se puede usar para colocar elementos de la interfaz de usuario mediante Autolayout y clases de tamaño en el controlador de vista de la aplicación:
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
}
}
Este código crea almacenamiento para una restricción superior que se aplicará a una etiqueta (ItemTitle
) para asegurarse de que no se desliza bajo el área Título y Barra de herramientas:
public NSLayoutConstraint topConstraint { get; set; }
Al invalidar el método UpdateViewConstraints
del controlador de vista, el desarrollador puede probar para ver si la restricción necesaria ya se ha compilado y crearla si es necesario.
Si es necesario crear una nueva restricción, se tiene acceso a la propiedad ContentLayoutGuide
del control Window al que se debe restringir y convertir en un NSLayoutGuide
:
var contentLayoutGuide = ItemTitle.Window?.ContentLayoutGuide as NSLayoutGuide;
Se obtiene acceso a la NSLayoutGuide
propiedad TopAnchor de y, si está disponible, se usa para crear una nueva restricción con la cantidad de desplazamiento deseada y la nueva restricción se activa para aplicarla:
// Assemble constraint and activate it
topConstraint = topAnchor.ConstraintEqualToAnchor (topAnchor, 20);
topConstraint.Active = true;
Habilitación de barras de herramientas simplificadas
Una ventana macOS normal incluye una barra de título estándar en las ejecuciones a lo largo del borde superior de la ventana. Si la ventana también incluye una barra de herramientas, se mostrará en este área barra de título:
Cuando se usa una barra de herramientas simplificada, el área de título desaparece y la barra de herramientas se mueve hacia arriba a la posición de la barra de título, en línea con los botones Cerrar ventana, Minimizar y Maximizar:
La barra de herramientas simplificada está habilitada reemplazando ViewWillAppear
el método del NSViewController
y haciendo que parezca similar al siguiente:
public override void ViewWillAppear ()
{
base.ViewWillAppear ();
// Enable streamlined Toolbars
View.Window.TitleVisibility = NSWindowTitleVisibility.Hidden;
}
Este efecto se usa normalmente para Aplicaciones de Shoebox (aplicaciones de una ventana), como Mapas, Calendario, Notas y Preferencias del sistema.
Uso de controladores de vistas de accesorios
En función del diseño de la aplicación, es posible que el desarrollador también quiera complementar el área Barra de título con un controlador de vista accesorio que aparece justo debajo del área Título/Barra de herramientas para proporcionar controles contextuales al usuario en función de la actividad en la que se dedica actualmente:
El controlador de vista accesorio se desenfoque y cambiará automáticamente el tamaño del sistema sin intervención del desarrollador.
Para agregar un controlador de vista accesorio, haga lo siguiente:
Haga doble clic en el archivo
Main.storyboard
en el Explorador de soluciones para abrirlo para su edición.Arrastre un Controlador de vista personalizado a la jerarquía de la ventana:
Diseño de la interfaz de usuario de la vista accesorio:
Exponga la vista accesorio como una Salida y cualquier otras Acciones o Salidas para su interfaz de usuario:
Guarde los cambios.
Vuelva a Visual Studio para Mac para sincronizar los cambios.
Edite el NSWindowController
y fíjese en lo siguiente:
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
}
}
Los puntos clave de este código son donde la vista se establece en la vista personalizada definida en Interface Builder y expuesta como una Salida:
accessoryView.View = AccessoryViewGoBar;
Y el LayoutAttribute
que define donde se mostrará el accesorio:
accessoryView.LayoutAttribute = NSLayoutAttribute.Bottom;
Dado que macOS ahora está totalmente localizado, las Left
propiedades y Right
NSLayoutAttribute
han quedado en desuso y deben reemplazarse por Leading
y Trailing
.
Uso de Ventanas con pestañas
Además, el sistema macOS podría agregar controladores de vista accesorio a la ventana de la aplicación. Por ejemplo, para crear Ventanas con pestañas en las que varias de las ventanas de la aplicación se combinan en una ventana virtual:
Normalmente, el desarrollador tendrá que realizar acciones limitadas para usar Windows con pestañas en sus aplicaciones de Xamarin.Mac, el sistema los controlará automáticamente de la siguiente manera:
- Windows se tabulará automáticamente cuando se invoque el método
OrderFront
. - Windows se anulará automáticamente cuando se invoque el método
OrderOut
. - En el código, todas las ventanas con pestañas todavía se consideran "visibles", pero el sistema oculta las pestañas no frontales mediante CoreGraphics.
- Use la
TabbingIdentifier
propiedad deNSWindow
para agrupar Windows en pestañas. - Si es una aplicación basada en
NSDocument
, varias de estas características se habilitarán automáticamente (como el botón más que se agrega a la barra de pestañas) sin ninguna acción de desarrollador. - Las aplicaciones
NSDocument
no basadas en pueden habilitar el botón "más" en el grupo de pestañas para agregar un nuevo documento reemplazando elGetNewWindowForTab
método delNSWindowsController
.
Reunir todas las piezas, el AppDelegate
de una aplicación que quería usar Windows con pestañas basada en el sistema podría ser similar a la siguiente:
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
}
}
Donde la propiedad NewDocumentNumber
realiza un seguimiento del número de nuevos documentos creados y el método NewDocument
crea un nuevo documento y lo muestra.
A continuación, el NSWindowController
podría tener el siguiente aspecto:
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
}
}
Donde la propiedad de App
estática proporciona un acceso directo para ir al AppDelegate
. El método SetDefaultDocumentTitle
establece un nuevo título de documentos en función del número de documentos nuevos creados.
El código siguiente indica a macOS que la aplicación prefiere usar pestañas y proporciona una cadena que permite que Windows de la aplicación se agrupe en pestañas:
// Prefer Tabbed Windows
Window.TabbingMode = NSWindowTabbingMode.Preferred;
Window.TabbingIdentifier = "Main";
Y el siguiente método de invalidación agrega un botón más a la barra de pestañas que creará un nuevo documento cuando el usuario haga clic en él:
public override void GetNewWindowForTab (NSObject sender)
{
// Ask app to open a new document window
App.NewDocument (this);
}
Uso de la animación principal
Core Animation es un motor de representación de gráficos de alta potencia integrado en macOS. Core Animation se ha optimizado para aprovechar las ventajas de la GPU (unidad de procesamiento de gráficos) disponible en el hardware macOS moderno, en lugar de ejecutar las operaciones de gráficos en la CPU, lo que puede ralentizar la máquina.
El CALayer
, proporcionado por Core Animation, se puede usar para tareas como desplazamiento rápido y fluido y animaciones. La interfaz de usuario de una aplicación debe estar compuesta de varias subvistas y capas para aprovechar completamente Core Animation.
Un objeto CALayer
proporciona varias propiedades que permiten al desarrollador controlar lo que se presenta en pantalla al usuario, como:
Content
: puede ser unNSImage
oCGImage
que proporciona el contenido de la capa.BackgroundColor
: Establece el color de fondo de la capa como unCGColor
BorderWidth
: Establece el ancho del borde.BorderColor
: Establece el color del borde.
Para usar gráficos principales en la interfaz de usuario de la aplicación, debe usar vistas con Respaldo de capas, lo que Apple sugiere que el desarrollador siempre debe habilitar en la vista de contenido de la ventana. De este modo, todas las vistas secundarias también heredarán automáticamente la copia de seguridad de la capa.
Además, Apple sugiere usar vistas respaldadas por capas en lugar de agregar un nuevo CALayer
como una subcapa porque el sistema controlará automáticamente varias de las configuraciones necesarias (como las requeridas por una pantalla de Retina).
La copia de seguridad de capas se puede habilitar estableciendo el WantsLayer
de un NSView
a true
o dentro del Interface Builder de Xcode en el Inspector de efectos de vista comprobando Capa de Core Animation:
Volver a dibujar vistas con capas
Otro paso importante al usar vistas respaldadas por capas en una aplicación de Xamarin.Mac consiste en establecer el LayerContentsRedrawPolicy
de la NSView
a OnSetNeedsDisplay
en el NSViewController
. Por ejemplo:
public override void ViewWillAppear ()
{
base.ViewWillAppear ();
// Set the content redraw policy
View.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
}
Si el desarrollador no establece esta propiedad, la vista se volverá a dibujar cada vez que cambie su origen de marco, lo que no se desea por motivos de rendimiento. Con esta propiedad establecida en OnSetNeedsDisplay
el desarrollador tendrá que establecer manualmente NeedsDisplay
a true
para obligar al contenido a volver a dibujar, sin embargo.
Cuando una vista está marcada como desfasada, el sistema comprueba la propiedad WantsUpdateLayer
de la vista. Si devuelve true
se llama al método UpdateLayer
, de lo contrario, se llama al método DrawRect
de la vista para actualizar el contenido de la vista.
Apple tiene las siguientes sugerencias para actualizar un contenido de Vistas cuando sea necesario:
- Apple prefiere usar
UpdateLater
sobreDrawRect
siempre que sea posible, ya que proporciona un aumento significativo del rendimiento. - Use la misma
layer.Contents
para los elementos de la interfaz de usuario que tienen un aspecto similar. - Apple también prefiere que el desarrollador componga su interfaz de usuario mediante vistas estándar como
NSTextField
, de nuevo siempre que sea posible.
Para usar UpdateLayer
, cree una clase personalizada para el NSView
y haga que el código tenga un aspecto similar al siguiente:
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 de arrastrar y colocar modernos
Para presentar una experiencia moderna de arrastrar y colocar para el usuario, el desarrollador debe adoptar Drag Flocking en las operaciones de arrastrar y colocar de su aplicación. Drag Flocking es donde cada archivo o elemento individual que se arrastra inicialmente aparece como un elemento individual que se agrupa (agrupa en el cursor con un recuento del número de elementos) a medida que el usuario continúa la operación de arrastre.
Si el usuario finaliza la operación de arrastrar, los elementos individuales desbloquearán y volverán a sus ubicaciones originales.
El código de ejemplo siguiente habilita Drag Flocking en una vista personalizada:
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
}
}
El efecto de bandada se logra enviando cada elemento que se arrastra al BeginDraggingSession
método del NSView
como un elemento independiente de una matriz.
Al trabajar con una NSTableView
o NSOutlineView
, use el método PastboardWriterForRow
de la clase NSTableViewDataSource
para iniciar la operación de arrastre:
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
}
}
Esto permite al desarrollador proporcionar una NSDraggingItem
individual para cada elemento de la tabla que se está arrastrando en lugar del método anterior WriteRowsWith
que escriben todas las filas como un único grupo en el panel de pegado.
Al trabajar con NSCollectionViews
, use de nuevo el método PasteboardWriterForItemAt
en lugar del método de WriteItemsAt
cuando comience arrastrar.
El desarrollador siempre debe evitar colocar archivos grandes en el panel de pegado. Novedad de macOS Sierra, Promesas de archivo permiten al desarrollador colocar referencias a archivos dados en el panel de pegado que se cumplirán más adelante cuando el usuario finalice la operación Drop con las nuevas clases de NSFilePromiseProvider
y NSFilePromiseReceiver
.
Uso del seguimiento de eventos modernos
Para un elemento de interfaz de usuario (como un NSButton
) que se ha agregado a un área título o barra de herramientas, el usuario debe poder hacer clic en el elemento y hacer que active un evento como normal (como mostrar una ventana emergente). Sin embargo, dado que el elemento también está en el área Título o Barra de herramientas, el usuario debería poder hacer clic y arrastrar el elemento para mover también la ventana.
Para ello en el código, cree una clase personalizada para el elemento (como NSButton
) e invalide el evento MouseDown
de la siguiente manera:
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);
}
}
Este código usa el TrackEventsMatching
método del NSWindow
que el elemento de interfaz de usuario está asociado para interceptar los eventos LeftMouseUp
y LeftMouseDragged
. Para un evento de LeftMouseUp
, el elemento de la interfaz de usuario responde como normal. Para el LeftMouseDragged
evento, el evento se pasa al NSWindow
método del PerformWindowDrag
objeto para mover la ventana en pantalla.
Llamar al método PerformWindowDrag
de la clase NSWindow
proporciona las siguientes ventajas:
- Permite que la ventana se mueva, incluso si la aplicación está bloqueada (por ejemplo, al procesar un bucle profundo).
- El cambio de espacio funcionará según lo previsto.
- La barra de espacios se mostrará como normal.
- El ajuste de ventanas y la alineación funcionan de forma normal.
Uso de controles modernos de vista de contenedor
macOS Sierra proporciona muchas mejoras modernas a los controles de vista de contenedor existentes disponibles en la versión anterior del sistema operativo.
Mejoras en la vista de tabla
El desarrollador siempre debe usar la nueva NSView
versión basada de controles de vista de contenedor, como NSTableView
. Por ejemplo:
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
}
}
Esto permite adjuntar acciones de fila de tabla personalizadas a filas dadas de la tabla (por ejemplo, deslizar el botón derecho para eliminar la fila). Para habilitar este comportamiento, invalide el RowActions
método del 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
}
}
La estática NSTableViewRowAction.FromStyle
se usa para crear una nueva acción de fila de tabla de los estilos siguientes:
Regular
: Realiza una acción no destructiva estándar, como editar el contenido de la fila.Destructive
: Realiza una acción destructiva, como eliminar la fila de la tabla. Estas acciones se representarán con un fondo rojo.
Mejoras en la vista de desplazamiento
Cuando se usa directamente una vista de desplazamiento (NSScrollView
) o como parte de otro control (como NSTableView
), el contenido de la vista de desplazamiento puede deslizarse debajo de las áreas Título y Barra de herramientas de una aplicación de Xamarin.Mac mediante una vista y vistas modernas.
Como resultado, el primer elemento del área de contenido Vista de desplazamiento puede ocultarse parcialmente por el área Título y Barra de herramientas.
Para corregir este problema, Apple ha agregado dos nuevas propiedades a la clase NSScrollView
:
ContentInsets
: Permite al desarrollador proporcionar un objetoNSEdgeInsets
que define el desplazamiento que se aplicará a la parte superior de la vista de desplazamiento.AutomaticallyAdjustsContentInsets
: Sitrue
la vista de desplazamiento controlará automáticamente elContentInsets
para el desarrollador.
Mediante el uso del ContentInsets
desarrollador puede ajustar el inicio de la vista de desplazamiento para permitir la inclusión de accesorios como:
- Indicador de ordenación como el que se muestra en la aplicación Correo.
- Un campo de búsqueda.
- Un botón Actualizar o Actualizar.
Diseño automático y localización en aplicaciones modernas
Apple ha incluido varias tecnologías en Xcode que permiten al desarrollador crear fácilmente una aplicación macOS internacionalizada. Xcode ahora permite al desarrollador separar el texto orientado al usuario del diseño de la interfaz de usuario de la aplicación en sus archivos storyboard y proporciona herramientas para mantener esta separación si cambia la interfaz de usuario.
Para obtener más información, vea Guía de internacionalización y localización de Apple.
Implementación de la internacionalización base
Al implementar la internacionalización base, el desarrollador puede proporcionar un único archivo de Guión gráfico para representar la interfaz de usuario de la aplicación y separar todas las cadenas orientadas al usuario.
Cuando el desarrollador crea el archivo gráfico inicial (o archivos) que definen la interfaz de usuario de la aplicación, se compilarán en la Internacionalización base (el idioma que habla el desarrollador).
A continuación, el desarrollador puede exportar las localización y las cadenas de internacionalización base (en el diseño de la interfaz de usuario de Guión gráfico) que se pueden traducir a varios idiomas.
Más adelante, estas localización se pueden importar y Xcode generará los archivos de cadena específicos del idioma para storyboard.
Implementación del diseño automático para admitir la localización
Dado que las versiones localizadas de valores de cadena pueden tener tamaños y/o direcciones de lectura muy diferentes, el desarrollador debe usar el diseño automático para colocar y ajustar el tamaño de la interfaz de usuario de la aplicación en un archivo Storyboard.
Apple sugiere hacer lo siguiente:
- Quitar restricciones de ancho fijo: Todas las vistas basadas en texto deben tener permiso para cambiar el tamaño en función de su contenido. La vista de ancho fijo puede recortar su contenido en idiomas específicos.
- Usar tamaños de contenido intrínsecos: De forma predeterminada, las vistas basadas en texto ajustarán automáticamente su contenido. Para ver la vista basada en texto que no ajuste el tamaño correctamente, selecciónelas en Interface Builder de Xcode y, a continuación, elija Editar>Tamaño para ajustar contenido.
- Aplicar atributos iniciales y finales: Dado que la dirección del texto puede cambiar en función del idioma del usuario, use los atributos nuevos
Leading
yTrailing
de restricción en lugar de los atributosRight
yLeft
existentes.Leading
yTrailing
se ajustarán automáticamente en función de la dirección de los idiomas. - Anclar vistas a vistas adyacentes: Esto permite que las vistas cambien de posición y cambio de tamaño a medida que cambien las vistas en respuesta al idioma seleccionado.
- No establecer un tamaño mínimo o máximo de Windows: Permitir que Windows cambie el tamaño a medida que el idioma seleccionado cambie el tamaño de sus áreas de contenido.
- Cambios de diseño de prueba constantemente: Durante el desarrollo en la aplicación se debe probar constantemente en diferentes lenguajes. Consulte la documentación de Prueba de su aplicación internacionalizada de Apple para obtener más información.
- Usar NSStackViews para anclar vistas juntas -
NSStackViews
permite que su contenido cambie de forma predecible y el tamaño del cambio de contenido en función del idioma seleccionado.
Localizar en Interface Builder de Xcode
Apple ha proporcionado varias características en Interface Builder de Xcode que el desarrollador puede usar al diseñar o editar la interfaz de usuario de una aplicación para admitir la localización. La sección Dirección de texto del Inspector de atributos permite al desarrollador proporcionar sugerencias sobre cómo se debe usar y actualizar la dirección en una vista basada en texto seleccionada (por ejemplo, NSTextField
):
Hay tres valores posibles para la Dirección del texto:
- Natural: El diseño se basa en la cadena asignada al control.
- De izquierda a derecha: El diseño siempre se ve obligado a izquierda a derecha.
- De derecha a izquierda: El diseño siempre se ve obligado a derecha a izquierda.
Hay dos valores posibles para el Diseño:
- De izquierda a derecha: El diseño siempre es de izquierda a derecha.
- De derecha a izquierda: El diseño siempre está de derecha a izquierda.
Normalmente, estos no deben cambiarse a menos que se requiera una alineación específica.
La propiedad Mirror indica al sistema que voltee propiedades de control específicas (como la posición de la imagen de celda). Tiene tres valores posibles:
- Automáticamente: La posición cambiará automáticamente en función de la dirección del idioma seleccionado.
- En la interfaz de derecha a izquierda: La posición solo se cambiará en idiomas basados en derecha a izquierda.
- Nunca: La posición nunca cambiará.
Si el desarrollador ha especificado Centrar, Justificar o Completa alineación en el contenido de una vista basada en texto, nunca se voltearán en función del idioma seleccionado.
Antes de macOS Sierra, los controles creados en el código no se reflejarían automáticamente. El desarrollador tenía que usar código como el siguiente para controlar la creación de reflejos:
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;
}
}
Donde se establecen los Alignment
y ImagePosition
en funciónUserInterfaceLayoutDirection
del control.
macOS Sierra agrega varios constructores de conveniencia nuevos (a través del método estático CreateButton
) que toman varios parámetros (como Title, Image y Action) y se reflejarán automáticamente correctamente. Por ejemplo:
var button2 = NSButton.CreateButton (myTitle, myImage, () => {
// Take action when the button is pressed
...
});
Uso de apariencias del sistema
Las aplicaciones modernas de macOS pueden adoptar una nueva apariencia de interfaz oscura que funcione bien para la creación, edición o presentación de aplicaciones de imagen:
Para ello, agregue una línea de código antes de que se presente la ventana. Por ejemplo:
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
}
}
El método estático GetAppearance
de la clase NSAppearance
se usa para obtener una apariencia con nombre del sistema (en este caso NSAppearance.NameVibrantDark
).
Apple tiene las siguientes sugerencias para usar apariencias del sistema:
- Prefiere colores con nombre sobre valores codificados de forma rígida (como
LabelColor
ySelectedControlColor
). - Use el estilo de control estándar del sistema siempre que sea posible.
Una aplicación macOS que usa las apariencias del sistema funcionará automáticamente para los usuarios que han habilitado características de accesibilidad desde la aplicación Preferencias del sistema. Como resultado, Apple sugiere que el desarrollador siempre debe usar Apariencias del sistema en sus aplicaciones macOS.
Diseño de interfaces de usuario con guiones gráficos
Los guiones gráficos permiten al desarrollador no solo diseñar los elementos individuales que componen la interfaz de usuario de una aplicación, sino visualizar y diseñar el flujo de la interfaz de usuario y la jerarquía de los elementos especificados.
Los controladores permiten al desarrollador recopilar elementos en una unidad de composición y Segues abstracta y quitar el típico "código de pegamento" necesario para moverse a lo largo de la jerarquía de vistas:
Para obtener más información, vea nuestra documentación Introducción a guiones gráficos.
Hay muchas instancias en las que una escena determinada definida en un guión gráfico requerirá datos de una escena anterior en la jerarquía de vistas. Apple tiene las siguientes sugerencias para pasar información entre escenas:
- Las dependencias de datos siempre deben estar en cascada hacia abajo a través de la jerarquía.
- Evite la codificación de dependencias estructurales de la interfaz de usuario, ya que esto limita la flexibilidad de la interfaz de usuario.
- Use interfaces de C# para proporcionar dependencias de datos genéricas.
El controlador de vista que actúa como origen de Segue, puede invalidar el método PrepareForSegue
y realizar cualquier inicialización necesaria (como pasar datos) antes de que se ejecute Segue para mostrar el controlador de vista de destino. Por ejemplo:
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;
}
}
Para obtener más información, vea nuestra documentación de Segues.
Propagación de acciones
En función del diseño de la aplicación macOS, puede haber ocasiones en las que el mejor controlador para una acción en un control de interfaz de usuario podría estar en otro lugar de la jerarquía de la interfaz de usuario. Esto suele ser cierto en menús y elementos de menú que residen en su propia escena, separados del resto de la interfaz de usuario de la aplicación.
Para controlar esta situación, el desarrollador puede crear una acción personalizada y pasar la acción a la cadena del respondedor. Para obtener más información, vea nuestra documentación de Trabajar con acciones de ventana personalizadas.
Características modernas de Mac
Apple ha incluido varias características orientadas al usuario en macOS Sierra que permiten al desarrollador sacar el máximo partido a la plataforma Mac, como:
- NSUserActivity: Esto permite a la aplicación describir la actividad en la que está implicado el usuario.
NSUserActivity
se creó inicialmente para admitir HandOff, donde una actividad iniciada en uno de los dispositivos del usuario se podía recoger y continuar en otro dispositivo.NSUserActivity
funciona igual en macOS que en iOS, por lo que vea nuestra documentación introducción a Handoff de iOS para obtener más detalles. - Siri en Mac: Siri usa la actividad actual (
NSUserActivity
) para proporcionar contexto a los comandos que un usuario puede emitir. - Restauración de estado: Cuando el usuario abandona una aplicación en macOS y, después, vuelve a iniciarla, la aplicación se devolverá automáticamente a su estado anterior. El desarrollador puede usar la API de Restauración de estado para codificar y restaurar estados de interfaz de usuario transitorios antes de que se muestre la interfaz de usuario al usuario. Si la aplicación está basada en
NSDocument
, Restauración de estado se controla automáticamente. Para habilitar Restauración de estado para aplicaciones no basadas enNSDocument
, establezca elRestorable
de la claseNSWindow
entrue
. - Documentos en la nube: Antes de macOS Sierra, una aplicación tenía que optar explícitamente por trabajar con documentos en iCloud Drive del usuario. En macOS Sierra, el Escritoriodel usuario y carpetas de Documentos se pueden sincronizar automáticamente con su iCloud Drive. Como resultado, se pueden eliminar copias locales de documentos para liberar espacio en el equipo del usuario.
NSDocument
aplicaciones basadas en se controlarán automáticamente este cambio. Todos los demás tipos de aplicaciones deberán usar unaNSFileCoordinator
para sincronizar la lectura y escritura de documentos.
Resumen
En este artículo se han tratado varias sugerencias, características y técnicas que un desarrollador puede usar para crear una aplicación macOS moderna en Xamarin.Mac.