Compartir a través de


Controles personalizados en Xamarin Designer para iOS

Xamarin Designer para iOS admite la representación de controles personalizados que se crean en su proyecto o a los que se hace referencia desde orígenes externos, como el almacén de componentes de Xamarin.

Advertencia

iOS Designer quedó en desuso en la versión 16.8 de Visual Studio 2019 y la 8.8 de Visual Studio 2019 para Mac, y se ha eliminado de la versión 16.9 de Visual Studio 2019 y la 8.9 de Visual Studio para Mac. La manera recomendada de compilar interfaces de usuario de iOS es directamente en un equipo Mac que ejecute Xcode. Para obtener más información, consulte Diseño de interfaces de usuario con Xcode.

Xamarin Designer para iOS es una herramienta de gran eficacia para visualizar la interfaz de usuario de una aplicación y proporciona compatibilidad de edición WYSIWYG para la mayoría de las vistas y controladores de vista de iOS. La aplicación también puede contener controles personalizados que amplíen los ya integrados en iOS. Si estos controles personalizados se escriben teniendo en cuenta algunas directrices, también los podrá representar iOS Designer, lo que proporciona una experiencia de edición aún más completa. En este documento se examinan esas directrices.

Requisitos

En la superficie de diseño se representará un control que cumpla todos los requisitos siguientes:

  1. Es una subclase directa o indirecta de UIView o UIViewController. Otras subclases de NSObject aparecerán como icono en la superficie de diseño.
  2. Tiene un valor RegisterAttribute para exponerlo en Objective-C.
  3. Tiene el constructor IntPtr necesario.
  4. Implementa la interfaz IComponent o tiene el valor DesignTimeVisibleAttribute establecido en True.

Los controles definidos en el código que cumplan los requisitos anteriores aparecerán en el diseñador cuando el proyecto que los contiene se compile para el simulador. De forma predeterminada, todos los controles personalizados aparecerán en la sección Componentes personalizados del Cuadro de herramientas. Sin embargo, CategoryAttribute puede aplicarse a la clase del control personalizado para especificar una sección distinta.

El diseñador no admite la carga de bibliotecas Objective-C de terceros.

Propiedades personalizadas

Si se cumplen las condiciones siguientes, aparecerá una propiedad declarada por un control personalizado en el panel de propiedades:

  1. La propiedad tiene un captador y un establecedor públicos.
  2. La propiedad tiene las clases ExportAttribute y BrowsableAttribute establecidas en True.
  3. La propiedad es de tipo numérico, un tipo de enumeración, de cadena, booleano, SizeF, UIColor o UIImage. Esta lista de tipos admitidos puede ampliarse en el futuro.

La propiedad también se puede decorar con un elemento DisplayNameAttribute para especificar la etiqueta que se muestra para ella en el panel de propiedades.

Inicialización

Para las subclases de UIViewController, debe usar el método ViewDidLoad para el código que dependa de las vistas que haya creado en el diseñador.

Para UIView y otras subclases de NSObject, se recomienda el método AwakeFromNib para realizar la inicialización del control personalizado después de cargarlo desde el archivo de diseño. Esto se debe a que las propiedades personalizadas establecidas en el panel de propiedades no se establecerán cuando se ejecute el constructor del control, sino antes de llamar a AwakeFromNib:

[Register ("CustomView"), DesignTimeVisible (true)]
public class CustomView : UIView {

    public CustomView (IntPtr handle) : base (handle) { }

    public override void AwakeFromNib ()
    {
        // Initialize the view here.
    }
}

Si el control también está diseñado para crearse directamente desde el código, puede que quiera crear un método que tenga un código de inicialización común, como este:

[Register ("CustomView"), DesignTimeVisible (true)]
public class CustomView : UIView {

    public CustomView (IntPtr handle) : base (handle) { }

    public CustomView ()
    {
        // Called when created from code.
        Initialize ();
    }

    public override void AwakeFromNib ()
    {
        // Called when loaded from xib or storyboard.
        Initialize ();
    }

    void Initialize ()
    {
        // Common initialization code here.
    }
}

Inicialización de propiedades y AwakeFromNib

Hay que tener cuidado respecto a cuándo y dónde inicializar las propiedades que se pueden diseñar en un componente personalizado para no sobrescribir los valores que se hayan establecido en iOS Designer. Tome el código siguiente como ejemplo:

[Register ("CustomView"), DesignTimeVisible (true)]
public class CustomView : UIView {

    [Export ("Counter"), Browsable (true)]
    public int Counter {get; set;}

    public CustomView (IntPtr handle) : base (handle) { }

    public CustomView ()
    {
        // Called when created from code.
        Initialize ();
    }

    public override void AwakeFromNib ()
    {
        // Called when loaded from xib or storyboard.
        Initialize ();
    }

    void Initialize ()
    {
        // Common initialization code here.
        Counter = 0;
    }
}

El componente CustomView expone una propiedad Counter que el desarrollador puede establecer dentro de iOS Designer. Sin embargo, independientemente del valor establecido dentro del diseñador, el valor de la propiedad Counter siempre será cero (0). Aquí se detallan los motivos:

  • Se infla una instancia de CustomControl desde el archivo Storyboard.
  • Se establecen todas las propiedades modificadas en el diseñador de iOS (por ejemplo, se establece el valor de Counter en dos [2]).
  • El método AwakeFromNib se ejecuta y se realiza una llamada al método Initialize del componente.
  • Dentro de Initialize, el valor de la propiedad Counter se restablece en cero (0).

Para corregir la situación anterior, inicialice la propiedad Counter en otro lugar (como el constructor del componente) o no reemplace el método AwakeFromNib y llame a Initialize si el componente no requiere ninguna otra inicialización aparte de la que actualmente administran sus constructores.

Modo de diseño

En la superficie de diseño, un control personalizado debe cumplir algunas restricciones:

  • Los recursos de lote de aplicaciones no están disponibles en modo de diseño. Las imágenes están disponibles cuando se cargan a través de métodos UIImage.
  • Las operaciones asincrónicas, como las solicitudes web, no deben realizarse en modo de diseño. La superficie de diseño no admite animaciones ni ninguna otra actualización asincrónica de la interfaz de usuario del control.

Un control personalizado puede implementar IComponent y usar la propiedad DesignMode para comprobar si está en la superficie de diseño. En este ejemplo, la etiqueta mostrará "Design Mode" en la superficie de diseño y "Runtime" en tiempo de ejecución:

[Register ("DesignerAwareLabel")]
public class DesignerAwareLabel : UILabel, IComponent {

    #region IComponent implementation

    public ISite Site { get; set; }
    public event EventHandler Disposed;

    #endregion

    public DesignerAwareLabel (IntPtr handle) : base (handle) { }

    public override void AwakeFromNib ()
    {
        if (Site != null && Site.DesignMode)
            Text = "Design Mode";
        else
            Text = "Runtime";
    }
}

Siempre debe comprobar la propiedad Site para null antes de intentar acceder a cualquiera de sus miembros. Si Site es null, puede suponerse que el control no se está ejecutando en el diseñador. En el modo de diseño, Site se establecerá después de que se haya ejecutado el constructor del control y antes de que se llame a AwakeFromNib.

Depuración

Un control que cumpla los requisitos anteriores se mostrará en el cuadro de herramientas y se representará en la superficie. Si un control no se representa, compruebe si hay errores en este o en una de sus dependencias.

A menudo, la superficie de diseño puede detectar excepciones producidas por controles individuales mientras sigue representando otros controles. El control defectuoso se reemplaza por un marcador de posición rojo y puede ver el seguimiento de las excepciones si hace clic en el icono de exclamación:

A faulty control as red placeholder and the exception details

Si hay símbolos de depuración disponibles para el control, el seguimiento tendrá nombres de archivo y números de línea. Al hacer doble clic en una línea del seguimiento de la pila, se saltará a esa línea en el código fuente.

Si el diseñador no puede aislar el control defectuoso, aparecerá un mensaje de advertencia en la parte superior de la superficie de diseño:

A warning message at the top of the design surface

La representación completa se reanudará cuando el control defectuoso se corrija o se quite de la superficie de diseño.

Resumen

En este artículo, se ha presentado la creación y la aplicación de controles personalizados en el diseñador de iOS. En primer lugar, se han descrito los requisitos que deben cumplir los controles para representarse en la superficie de diseño y exponer propiedades personalizadas en el panel de propiedades. Después, se ha analizado el código subyacente: la inicialización del control y la propiedad DesignMode. Por último, se ha descrito qué sucede cuando se producen excepciones y cómo resolverlo.