uso de los controles personalizados con iOS Designer

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.

Requisitos

Xamarin Designer para iOS está disponible en Visual Studio para Mac y Visual Studio 2017 y versiones posteriores en Windows.

En esta guía se supone que está familiarizado con el contenido descrito en las guías de introducción.

Tutorial

Importante

A partir de Xamarin.Studio 5.5, la forma en que se crean controles personalizados es ligeramente diferente a las versiones anteriores. Para crear un control personalizado, se requiere la interfaz IComponent (con los métodos de implementación asociados) o la clase se puede anotar con [DesignTimeVisible(true)]. El último método se usa en el siguiente ejemplo de tutorial.

  1. Cree una nueva solución a partir de la plantilla iOS > Aplicación > Vista única de aplicación> C#, asígnele el nombre ScratchTicket y continúe con el Asistente para nuevo proyecto:

    Crear una solución nueva

  2. Cree un nuevo archivo de clase vacío denominado ScratchTicketView:

    Creación de una nueva clase ScratchTicketView

  3. Agregue el código siguiente a la clase ScratchTicketView:

    using System;
    using System.ComponentModel;
    using CoreGraphics;
    using Foundation;
    using UIKit;
    
    namespace ScratchTicket
    {
        [Register("ScratchTicketView"), DesignTimeVisible(true)]
        public class ScratchTicketView : UIView
        {
            CGPath path;
            CGPoint initialPoint;
            CGPoint latestPoint;
            bool startNewPath = false;
            UIImage image;
    
            [Export("Image"), Browsable(true)]
            public UIImage Image
            {
                get { return image; }
                set
                {
                    image = value;
                    SetNeedsDisplay();
                }
            }
    
            public ScratchTicketView(IntPtr p)
                : base(p)
            {
                Initialize();
            }
    
            public ScratchTicketView()
            {
                Initialize();
            }
    
            void Initialize()
            {
                initialPoint = CGPoint.Empty;
                latestPoint = CGPoint.Empty;
                BackgroundColor = UIColor.Clear;
                Opaque = false;
                path = new CGPath();
                SetNeedsDisplay();
            }
    
            public override void TouchesBegan(NSSet touches, UIEvent evt)
            {
                base.TouchesBegan(touches, evt);
    
                var touch = touches.AnyObject as UITouch;
    
                if (touch != null)
                {
                    initialPoint = touch.LocationInView(this);
                }
            }
    
            public override void TouchesMoved(NSSet touches, UIEvent evt)
            {
                base.TouchesMoved(touches, evt);
    
                var touch = touches.AnyObject as UITouch;
    
                if (touch != null)
                {
                    latestPoint = touch.LocationInView(this);
                    SetNeedsDisplay();
                }
            }
    
            public override void TouchesEnded(NSSet touches, UIEvent evt)
            {
                base.TouchesEnded(touches, evt);
                startNewPath = true;
            }
    
            public override void Draw(CGRect rect)
            {
                base.Draw(rect);
    
                using (var g = UIGraphics.GetCurrentContext())
                {
                    if (image != null)
                        g.SetFillColor((UIColor.FromPatternImage(image).CGColor));
                    else
                        g.SetFillColor(UIColor.LightGray.CGColor);
                    g.FillRect(rect);
    
                    if (!initialPoint.IsEmpty)
                    {
                        g.SetLineWidth(20);
                        g.SetBlendMode(CGBlendMode.Clear);
                        UIColor.Clear.SetColor();
    
                        if (path.IsEmpty || startNewPath)
                        {
                            path.AddLines(new CGPoint[] { initialPoint, latestPoint });
                            startNewPath = false;
                        }
                        else
                        {
                            path.AddLineToPoint(latestPoint);
                        }
    
                        g.SetLineCap(CGLineCap.Round);
                        g.AddPath(path);
                        g.DrawPath(CGPathDrawingMode.Stroke);
                    }
                }
            }
        }
    }
    
  4. Agregue los archivos FillTexture.png, FillTexture2.png y Monkey.png (disponibles en GitHub) a la carpeta Recursos.

  5. Haga doble clic en el archivo Main.storyboard para abrirlo en el Diseñador de iOS.

    Diseñador de iOS

  6. Arrastre o coloque una vista de imagen desde el cuadro de herramientas hasta la vista del guion gráfico.

    Una vista de imagen agregada al diseño

  7. Seleccione la vista de imagen y cambie su propiedad Image a Monkey.png.

    Establecimiento de la propiedad de imagen de la vista de imagen en Monkey.png

  8. A medida que se usan clases de tamaño, es necesario restringir esta vista de imagen. Haga clic en la imagen dos veces para colocarla en modo de restricción. Para restringirlo al centro, haga clic en el controlador de anclaje central y alinee tanto vertical como horizontalmente:

    Centrado de la imagen

  9. Para restringir el alto y el ancho, haga clic en los controladores de anclaje de tamaño (los mangos con forma "hueso") y seleccione ancho y alto, respectivamente:

    Adición de restricciones

  10. Actualice el marco en función de las restricciones haciendo clic en el botón actualizar de la barra de herramientas:

    Barra de herramientas Restricciones

  11. A continuación, compile el proyecto para que la vista de vale de rascado aparezca en Componentes personalizados en el cuadro de herramientas:

    Cuadro de herramientas Componentes personalizados

  12. Arrastre y coloque una vista de vale de rascado para que aparezca sobre la imagen del mono. Ajuste los controladores de arrastre para que la vista de vale de rascado cubra completamente el mono, como se muestra a continuación:

    Una vista de vale temporal sobre la vista de imagen

  13. Restrinja la vista de vale de rascado a la vista de imagen dibujando un rectángulo delimitador para seleccionar ambas vistas. Seleccione las opciones para restringirla a los marcos Width, Height, Center y Middle y update en función de las restricciones, como se muestra a continuación:

    Centrado y adición de restricciones

  14. Ejecute la aplicación y "rasque" la imagen para mostrar el mono.

    Ejecución de una aplicación de ejemplo

Agregar propiedades en tiempo de diseño

El diseñador también incluye compatibilidad en tiempo de diseño para controles personalizados de tipo de propiedad numeric, enumeration, string, bool, CGSize, UIColor y UIImage. Para demostrarlo, vamos a agregar una propiedad a ScratchTicketView para establecer la imagen "rascada".

Agregue el código siguiente a la clase ScratchTicketView para la propiedad:

[Export("Image"), Browsable(true)]
public UIImage Image
{
    get { return image; }
    set {
            image = value;
              SetNeedsDisplay ();
        }
}

También es posible que deseemos agregar una comprobación nula al método Draw, de la siguiente manera:

public override void Draw(CGRect rect)
{
    base.Draw(rect);

    using (var g = UIGraphics.GetCurrentContext())
    {
        if (image != null)
            g.SetFillColor ((UIColor.FromPatternImage (image).CGColor));
        else
            g.SetFillColor (UIColor.LightGray.CGColor);

        g.FillRect(rect);

        if (!initialPoint.IsEmpty)
        {
             g.SetLineWidth(20);
             g.SetBlendMode(CGBlendMode.Clear);
             UIColor.Clear.SetColor();

             if (path.IsEmpty || startNewPath)
             {
                 path.AddLines(new CGPoint[] { initialPoint, latestPoint });
                 startNewPath = false;
             }
             else
             {
                 path.AddLineToPoint(latestPoint);
             }

             g.SetLineCap(CGLineCap.Round);
             g.AddPath(path);
             g.DrawPath(CGPathDrawingMode.Stroke);
        }
    }
}

Incluir un ExportAttribute y un BrowsableAttribute con el argumento establecido en true da como resultado la propiedad que se muestra en el panel Propiedad del diseñador. Cambiar la propiedad a otra imagen incluida con el proyecto, como FillTexture2.png, da como resultado la actualización del control en tiempo de diseño, como se muestra a continuación:

Edición de propiedades de tiempo de diseño

Resumen

En este artículo se explica cómo crear un control personalizado, así como consumirlo en una aplicación de iOS mediante el diseñador de iOS. Hemos visto cómo crear y compilar el control para que esté disponible para una aplicación en el cuadro de herramientas del diseñador. Además, hemos visto cómo implementar el control de forma que se represente correctamente en tiempo de diseño y en tiempo de ejecución, así como cómo exponer propiedades de control personalizadas en el diseñador.