Creación de controles personalizados en Xamarin.Mac
Al trabajar con C# y .NET en una aplicación de Xamarin.Mac, tiene acceso a los mismos controles de usuario que un desarrollador que trabaja en Objective-C , Objective-Cy Xcode. Dado que Xamarin.Mac se integra directamente con Xcode, puede usar el Interface Builder de Xcode para crear y mantener los controles de usuario (o, opcionalmente, crearlos directamente en código de C#).
Aunque macOS proporciona una gran cantidad de controles de usuario integrados, es posible que tenga que crear un control personalizado para proporcionar funcionalidad que no se proporciona de forma integrada o para que coincida con un tema de interfaz de usuario personalizado (como una interfaz de juego).
En este artículo, se tratarán los conceptos básicos de la creación de un control personalizado Interfaz de usuario personalizado en una aplicación Xamarin.Mac. Se recomienda encarecidamente que trabaje primero en el artículo Hello, Mac, en concreto en las secciones Introduction to Xcode and Interface Builder and Outlets and Actions (Introducción a Xcode y Interface Builder y salidas y acciones), ya que trata los conceptos y técnicas clave que se usarán en este artículo.
También puede echar un vistazo a la sección del documento Exposing C# classes / methods to Objective-CExposing C# classes / methods to Objective-C internos de Xamarin.Mac), donde se explican los comandos y que se usan para conectar las clases de C# a objetos y elementos de interfaz de RegisterExportObjective-C usuario.
Introducción a los controles personalizados
Como se indicó anteriormente, puede haber ocasiones en las que necesite crear un control Interfaz de usuario personalizado reutilizable para proporcionar una funcionalidad única para la interfaz de usuario de la aplicación Xamarin.Mac o para crear un tema de interfaz de usuario personalizado (como una interfaz de juego).
En estas situaciones, puede heredar fácilmente de y crear una herramienta personalizada que se pueda agregar a la interfaz de usuario de la aplicación a través de código de C# o a través del código de NSControl Xcode Interface Builder. Al heredar del control personalizado, tendrá automáticamente todas las características estándar que tiene un control de Interfaz de usuario NSControl integrado (por ejemplo, NSButton ).
Si el control Interfaz de usuario personalizado simplemente muestra información (como una herramienta personalizada de gráficos y gráficos), es posible que quiera heredar de en NSView lugar de NSControl .
Independientemente de la clase base que se utilice, los pasos básicos para crear un control personalizado son los mismos.
En este artículo, creará un componente flip switch personalizado que proporciona un tema de Interfaz de usuario único y un ejemplo de creación de un control de Interfaz de usuario personalizado totalmente funcional.
Compilar el control personalizado
Dado que el control personalizado que estamos creando responderá a la entrada del usuario (clics del botón izquierdo del mouse), vamos a heredar de NSControl . De esta manera, nuestro control personalizado tendrá automáticamente todas las características estándar que un control Interfaz de usuario Control integrado tiene y responderá como un control macOS estándar.
En Visual Studio para Mac, abra el proyecto de Xamarin.Mac para el que desea crear un control de Interfaz de usuario personalizado (o cree uno). Agregue una nueva clase y llámela NSFlipSwitch :
A continuación, NSFlipSwitch.cs edite la clase y haga que se parezca a la siguiente:
using Foundation;
using System;
using System.CodeDom.Compiler;
using AppKit;
using CoreGraphics;
namespace MacCustomControl
{
[Register("NSFlipSwitch")]
public class NSFlipSwitch : NSControl
{
#region Private Variables
private bool _value = false;
#endregion
#region Computed Properties
public bool Value {
get { return _value; }
set {
// Save value and force a redraw
_value = value;
NeedsDisplay = true;
}
}
#endregion
#region Constructors
public NSFlipSwitch ()
{
// Init
Initialize();
}
public NSFlipSwitch (IntPtr handle) : base (handle)
{
// Init
Initialize();
}
[Export ("initWithFrame:")]
public NSFlipSwitch (CGRect frameRect) : base(frameRect) {
// Init
Initialize();
}
private void Initialize() {
this.WantsLayer = true;
this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
}
#endregion
#region Draw Methods
public override void DrawRect (CGRect dirtyRect)
{
base.DrawRect (dirtyRect);
// Use Core Graphic routines to draw our UI
...
}
#endregion
#region Private Methods
private void FlipSwitchState() {
// Update state
Value = !Value;
}
#endregion
}
}
Lo primero que hay que tener en cuenta sobre nuestra clase personalizada es que se hereda de y se usa el comando Register para exponer esta clase a y la clase de NSControlNSControlObjective-C Xcode Interface Builder:
[Register("NSFlipSwitch")]
public class NSFlipSwitch : NSControl
En las secciones siguientes, echaremos un vistazo al resto del código anterior en detalle.
Seguimiento del estado del control
Puesto que el control personalizado es un modificador, necesitamos una manera de realizar un seguimiento del estado de encendido y apagado del conmutador. Esto se controla con el código siguiente en NSFlipSwitch :
private bool _value = false;
...
public bool Value {
get { return _value; }
set {
// Save value and force a redraw
_value = value;
NeedsDisplay = true;
}
}
Cuando cambia el estado del conmutador, necesitamos una manera de actualizar la interfaz de usuario. Para ello, obligamos al control a volver a dibujar su interfaz de usuario con NeedsDisplay = true .
Si nuestro control requería más que un único estado de encendido y apagado (por ejemplo, un conmutador de varios estados con 3 posiciones), podríamos haber usado una enumeración para realizar el seguimiento del estado. En nuestro ejemplo, lo hará un simple bool.
También hemos agregado un método auxiliar para intercambiar el estado del conmutador entre On y Off:
private void FlipSwitchState() {
// Update state
Value = !Value;
}
Más adelante, expandiremos esta clase auxiliar para informar al autor de la llamada cuando el estado de los modificadores haya cambiado.
Dibujar la interfaz del control
Vamos a usar rutinas de dibujo de gráficos principales para dibujar las características de nuestro control personalizado Interfaz de usuario en tiempo de ejecución. Antes de poder hacerlo, es necesario activar las capas para nuestro control. Esto se hace con el siguiente método privado:
private void Initialize() {
this.WantsLayer = true;
this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
}
Se llama a este método desde cada uno de los constructores del control para asegurarse de que el control está configurado correctamente. Por ejemplo:
public NSFlipSwitch (IntPtr handle) : base (handle)
{
// Init
Initialize();
}
A continuación, es necesario invalidar el DrawRect método y agregar las rutinas core graphic para dibujar el control:
public override void DrawRect (CGRect dirtyRect)
{
base.DrawRect (dirtyRect);
// Use Core Graphic routines to draw our UI
...
}
Ajustaremos la representación visual del control cuando cambie su estado (por ejemplo, pasar de On a Off). Cada vez que cambia el estado, podemos usar el comando para forzar que el control vuelva a NeedsDisplay = true dibujarse para el nuevo estado.
Respuesta a la entrada del usuario
Hay dos maneras básicas de agregar entradas de usuario a nuestro control personalizado: Invalidar rutinas de control del mouse o Reconocedores de gestos. El método que usamos se basará en la funcionalidad requerida por nuestro control.
Importante
Para cualquier control personalizado que cree, debe usar Métodosde invalidación o Reconocedores de gestos,pero no ambos al mismo tiempo, ya que pueden estar en conflicto entre sí.
Control de la entrada del usuario con métodos de invalidación
Los objetos que heredan de (o ) tienen varios NSControlNSView métodos de invalidación para controlar la entrada del mouse o del teclado. Para nuestro control de ejemplo, queremos cambiar el estado del conmutador entre Activar y Desactivar cuando el usuario hace clic en el control con el botón izquierdo del mouse. Podemos agregar los siguientes métodos de invalidación a la NSFlipSwitch clase para controlar esto:
#region Mouse Handling Methods
// --------------------------------------------------------------------------------
// Handle mouse with Override Methods.
// NOTE: Use either this method or Gesture Recognizers, NOT both!
// --------------------------------------------------------------------------------
public override void MouseDown (NSEvent theEvent)
{
base.MouseDown (theEvent);
FlipSwitchState ();
}
public override void MouseDragged (NSEvent theEvent)
{
base.MouseDragged (theEvent);
}
public override void MouseUp (NSEvent theEvent)
{
base.MouseUp (theEvent);
}
public override void MouseMoved (NSEvent theEvent)
{
base.MouseMoved (theEvent);
}
## endregion
En el código anterior, llamamos al método (definido anteriormente) para cambiar el estado FlipSwitchState On/Off del modificador en el MouseDown método . Esto también forzará que el control se vuelva a dibujar para reflejar el estado actual.
Control de la entrada del usuario con reconocedores de gestos
Opcionalmente, puede usar Reconocedores de gestos para controlar al usuario que interactúa con el control. Quite las invalidaciones agregadas anteriormente, edite Initialize el método y haga que sea parecido al siguiente:
private void Initialize() {
this.WantsLayer = true;
this.LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay;
// --------------------------------------------------------------------------------
// Handle mouse with Gesture Recognizers.
// NOTE: Use either this method or the Override Methods, NOT both!
// --------------------------------------------------------------------------------
var click = new NSClickGestureRecognizer (() => {
FlipSwitchState();
});
AddGestureRecognizer (click);
}
En este caso, estamos creando un nuevo y llamando a nuestro método para cambiar el estado del conmutador cuando el usuario hace clic en él con el NSClickGestureRecognizerFlipSwitchState botón izquierdo del mouse. El AddGestureRecognizer (click) método agrega gesture recognizer al control .
De nuevo, el método que usamos depende de lo que intentamos lograr con nuestro control personalizado. Si necesitamos acceso de bajo nivel a la interacción del usuario, use los métodos de invalidación. Si necesitamos funcionalidad predefinida, como clics del mouse, use Reconocedores de gestos.
Responder a eventos de cambio de estado
Cuando el usuario cambia el estado de nuestro control personalizado, necesitamos una manera de responder al cambio de estado en el código (por ejemplo, hacer algo al hacer clic en un botón personalizado).
Para proporcionar esta funcionalidad, edite la NSFlipSwitch clase y agregue el código siguiente:
#region Events
public event EventHandler ValueChanged;
internal void RaiseValueChanged() {
if (this.ValueChanged != null)
this.ValueChanged (this, EventArgs.Empty);
// Perform any action bound to the control from Interface Builder
// via an Action.
if (this.Action !=null)
NSApplication.SharedApplication.SendAction (this.Action, this.Target, this);
}
## endregion
A continuación, FlipSwitchState edite el método y haga que sea parecido al siguiente:
private void FlipSwitchState() {
// Update state
Value = !Value;
RaiseValueChanged ();
}
En primer lugar, se proporciona un evento al que se puede agregar un controlador en código de C# para que podamos realizar una acción cuando el usuario cambie el ValueChanged estado del modificador.
En segundo lugar, dado que nuestro control personalizado hereda de , tiene automáticamente una acción que se puede asignar en la configuración NSControl de Xcode NSControl Interface Builder. Para llamar a esta acción cuando cambia el estado, usamos el código siguiente:
if (this.Action !=null)
NSApplication.SharedApplication.SendAction (this.Action, this.Target, this);
En primer lugar, se comprueba si se ha asignado una acción al control. A continuación, llamamos a la acción si se ha definido.
Uso del control personalizado
Con nuestro control personalizado totalmente definido, podemos agregarlo a la interfaz de usuario de la aplicación Xamarin.Mac mediante código C# o en la interfaz de usuario de Xcode Interface Builder.
Para agregar el control mediante Interface Builder, primero realice una compilación limpia del proyecto de Xamarin.Mac y, a continuación, haga doble clic en el archivo para abrirlo en Main.storyboard Interface Builder para su edición:
A continuación, arrastre Custom View un al Interfaz de usuario diseño:
Con la vista personalizada aún seleccionada, cambie a Identity Inspector y cambie la clase de la vista a :
Cambie al Editor del asistente y cree una salida para el control personalizado (asegúrese de enlazarlo en el archivo y no en el archivo):
Guarde los cambios, vuelva a Visual Studio para Mac y permita que los cambios se sincronicen. Edite ViewController.cs el archivo y haga que el método sea parecido al ViewDidLoad siguiente:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Do any additional setup after loading the view.
OptionTwo.ValueChanged += (sender, e) => {
// Display the state of the option switch
Console.WriteLine("Option Two: {0}", OptionTwo.Value);
};
}
En este caso, respondemos al evento que definimos anteriormente en la clase y escribimos el valor actual cuando el usuario hace clic ValueChangedNSFlipSwitch en el control. ValueChanged
Opcionalmente, podríamos volver a Interface Builder y definir una acción en el control :
De nuevo, ViewController.cs edite el archivo y agregue el método siguiente:
partial void OptionTwoFlipped (Foundation.NSObject sender) {
// Display the state of the option switch
Console.WriteLine("Option Two: {0}", OptionTwo.Value);
}
Importante
Debe usar el evento o definir una acción en Interface Builder, pero no debe usar ambos métodos al mismo tiempo o pueden estar en conflicto entre sí.
Resumen
En este artículo se ha realizado un análisis detallado de la creación de un control de Interfaz de usuario personalizado reutilizable en una aplicación Xamarin.Mac. Hemos visto cómo dibujar la interfaz de usuario de controles personalizados, las dos formas principales de responder a la entrada del mouse y del usuario y cómo exponer el nuevo control a acciones en la interfaz de usuario de Xcode Interface Builder.
Vínculos relacionados
- MacCustomControl (ejemplo)
- Hello, Mac
- Enlace de datos y codificación de clave-valor
- OS X Human Interface Guidelines (Directrices de interfaz humana de OS X)
- Controlar eventos del mouse






