Creación de interfaces de usuario de iOS en código en Xamarin.iOS

La interfaz de usuario de una aplicación iOS es como un escaparate: la aplicación normalmente obtiene una ventana, pero puede llenar la ventana con tantos objetos como necesite, y los objetos y las disposiciones se pueden cambiar en función de lo que la aplicación quiera mostrar. Los objetos de este escenario, lo que el usuario ve, se denominan "vistas". Para compilar una sola pantalla en una aplicación, las vistas se apilan unas sobre otras en una jerarquía de vistas de contenido y la jerarquía se administra mediante un solo controlador de vistas. Las aplicaciones con varias pantallas tienen varias jerarquías de vistas de contenido, cada una con su propio controlador de vistas. La aplicación coloca las vistas en la ventana para crear una jerarquía de vistas de contenido diferente basándose en la pantalla en la que se encuentra el usuario.

En el diagrama siguiente se muestran las relaciones entre la ventana, las vistas, las subvistas y el controlador de vistas que, de forma conjunta, proporcionan la interfaz de usuario a la pantalla del dispositivo:

En este diagrama se muestran las relaciones entre la ventana, las vistas, las subvistas y el controlador de vistas.

Estas jerarquías de vistas se pueden construir mediante el Interface Builder de Xcode, pero es bueno tener una comprensión fundamental de cómo trabajar completamente en el código. Este artículo le guía por algunos puntos básicos para empezar a trabajar con el desarrollo de la interfaz de usuario de solo código.

Creación de un proyecto de solo código

Plantilla de proyecto en blanco de iOS

En primer lugar, cree un proyecto de iOS en Visual Studio mediante el proyecto File New Project Visual > C# iPhone iPad >&> iOS App (Xamarin) (Aplicación iOS [Xamarin]), que se muestra a continuación:

Cuadro de Project nuevo

A continuación, seleccione la plantilla de proyecto Aplicación en blanco:

Cuadro de diálogo Seleccionar plantilla

La plantilla Project vacía agrega 4 archivos al proyecto:

Project Files

  1. AppDelegate.cs: contiene una subclase, , que se AppDelegate usa para controlar eventos de aplicación desde iOS. La ventana de la aplicación se crea en AppDelegate el FinishedLaunching método del .
  2. Main.cs: contiene el punto de entrada de la aplicación, que especifica la clase para .
  3. Info.plist: archivo de lista de propiedades que contiene información de configuración de la aplicación.
  4. Entitlements.plist: archivo de lista de propiedades que contiene información sobre las funcionalidades y permisos de la aplicación.

Las aplicaciones iOS se han creado con el patrón MVC. La primera pantalla que muestra una aplicación se crea a partir del controlador de vista raíz de la ventana. Consulte la guía hello, iOS multipantalla para obtener más detalles sobre el propio patrón MVC.

La implementación del agregado por la plantilla crea la ventana de aplicación, de la que solo hay una para cada aplicación iOS, y la hace visible con AppDelegate el código siguiente:

public class AppDelegate : UIApplicationDelegate
{
    public override UIWindow Window
            {
                get;
                set;
            }

    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
        // create a new window instance based on the screen size
        Window = new UIWindow(UIScreen.MainScreen.Bounds);

        // make the window visible
        Window.MakeKeyAndVisible();

        return true;
    }
}

Si ejecutara esta aplicación ahora, es probable que se produjese una excepción que indica que Application windows are expected to have a root view controller at the end of application launch . Vamos a agregar un controlador y convertirlo en el controlador de vista raíz de la aplicación.

Agregar un controlador

La aplicación puede contener muchos controladores de vista, pero debe tener un controlador de vista raíz para controlar todos los controladores de vista. Agregue un controlador a la ventana mediante la creación de una UIViewController instancia y su establecimiento en la propiedad Window.RootViewController :

public class AppDelegate : UIApplicationDelegate
{
    // class-level declarations

    public override UIWindow Window
    {
        get;
        set;
    }

    public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
    {
        // create a new window instance based on the screen size
        Window = new UIWindow(UIScreen.MainScreen.Bounds);

        var controller = new UIViewController();
        controller.View.BackgroundColor = UIColor.LightGray;

        Window.RootViewController = controller;

        // make the window visible
        Window.MakeKeyAndVisible();

        return true;
    }
}

Cada controlador tiene una vista asociada, a la que se puede acceder desde la View propiedad . El código anterior cambia la propiedad de la vista a para BackgroundColorUIColor.LightGray que sea visible, como se muestra a continuación:

El fondo de la vista es un gris claro visible

También podríamos establecer cualquier subclase como de esta manera, incluidos los controladores de UIKit, así como los que UIViewControllerRootViewController escribimos nosotros mismos. Por ejemplo, el código siguiente agrega UINavigationController un como RootViewController :

public class AppDelegate : UIApplicationDelegate
{
    // class-level declarations

    public override UIWindow Window
    {
        get;
        set;
    }

    public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
    {
        // create a new window instance based on the screen size
        Window = new UIWindow(UIScreen.MainScreen.Bounds);

        var controller = new UIViewController();
        controller.View.BackgroundColor = UIColor.LightGray;
        controller.Title = "My Controller";

        var navController = new UINavigationController(controller);

        Window.RootViewController = navController;

        // make the window visible
        Window.MakeKeyAndVisible();

        return true;
    }
}

Esto genera el controlador anidado dentro del controlador de navegación, como se muestra a continuación:

Controlador anidado dentro del controlador de navegación

Creación de un controlador de vistas

Ahora que hemos visto cómo agregar un controlador como de la ventana, veamos cómo crear un controlador de vista RootViewController personalizado en el código.

Agregue una nueva clase denominada como CustomViewController se muestra a continuación:

La clase debe heredar de UIViewController , que se encuentra en el espacio de nombres , como se muestra a UIKit continuación:

using System;
using UIKit;

namespace CodeOnlyDemo
{
    class CustomViewController : UIViewController
    {
    }
}

Inicialización de la vista

UIViewController contiene un método llamado ViewDidLoad al que se llama cuando el controlador de vista se carga por primera vez en la memoria. Este es un lugar adecuado para realizar la inicialización de la vista, como establecer sus propiedades.

Por ejemplo, el código siguiente agrega un botón y un controlador de eventos para insertar un nuevo controlador de vistas en la pila de navegación cuando se presiona el botón:

using System;
using CoreGraphics;
using UIKit;

namespace CodyOnlyDemo
{
    public class CustomViewController : UIViewController
    {
        public CustomViewController ()
        {
        }

        public override void ViewDidLoad ()
        {
            base.ViewDidLoad ();

            View.BackgroundColor = UIColor.White;
            Title = "My Custom View Controller";

            var btn = UIButton.FromType (UIButtonType.System);
            btn.Frame = new CGRect (20, 200, 280, 44);
            btn.SetTitle ("Click Me", UIControlState.Normal);

            var user = new UIViewController ();
            user.View.BackgroundColor = UIColor.Magenta;

            btn.TouchUpInside += (sender, e) => {
                this.NavigationController.PushViewController (user, true);
            };

            View.AddSubview (btn);

        }
    }
}

Para cargar este controlador en la aplicación y mostrar la navegación simple, cree una nueva instancia de CustomViewController . Cree un nuevo controlador de navegación, pase la instancia del controlador de vista y establezca el nuevo controlador de navegación en el de la ventana RootViewController como AppDelegate antes:

var cvc = new CustomViewController ();

var navController = new UINavigationController (cvc);

Window.RootViewController = navController;

Ahora, cuando se carga la aplicación, CustomViewController se carga dentro de un controlador de navegación:

CustomViewController se carga dentro de un controlador de navegación

Al hacer clic en el botón , se insertará un nuevo controlador de vistas en la pila de navegación:

Un nuevo controlador de vista que se inserta en la pila de navegación

Creación de la jerarquía de vistas

En el ejemplo anterior, empezamos a crear una interfaz de usuario en el código agregando un botón al controlador de vista.

Las interfaces de usuario de iOS se componen de una jerarquía de vistas. Las vistas adicionales, como etiquetas, botones, controles deslizantes, etc., se agregan como subvistas de alguna vista primaria.

Por ejemplo, vamos a editar para crear una pantalla de inicio de sesión en la que el usuario CustomViewController puede escribir un nombre de usuario y una contraseña. La pantalla constará de dos campos de texto y un botón.

Agregar los campos de texto

En primer lugar, quite el botón y el controlador de eventos que se agregaron en la sección Inicializar la vista.

Agregue un control para el nombre de usuario mediante la creación e inicialización de un y, a continuación, agrégrélo a la jerarquía UITextField de vistas, como se muestra a continuación:

class CustomViewController : UIViewController
{
    UITextField usernameField;

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();

        View.BackgroundColor = UIColor.Gray;

        nfloat h = 31.0f;
        nfloat w = View.Bounds.Width;

        usernameField = new UITextField
        {
            Placeholder = "Enter your username",
            BorderStyle = UITextBorderStyle.RoundedRect,
            Frame = new CGRect(10, 82, w - 20, h)
        };

        View.AddSubview(usernameField);
    }
}

Cuando creamos UITextField , establecemos la Frame propiedad para definir su ubicación y tamaño. En iOS, la coordenada 0,0 está en la parte superior izquierda con +x a la derecha y +y hacia abajo. Después de establecer Frame junto con otras dos propiedades, llamamos a View.AddSubview para agregar a la jerarquía de UITextField vistas. Esto hace que usernameField la subvista de la UIView instancia a la que hace referencia la View propiedad. Una subvista se agrega con un orden Z superior a su vista primaria, por lo que aparece delante de la vista primaria en la pantalla.

A continuación se muestra UITextField la aplicación con el incluido:

La aplicación con UITextField incluido

Podemos agregar un para la contraseña de forma similar, solo que esta vez establezcamos la propiedad UITextFieldSecureTextEntry en true, como se muestra a continuación:

public class CustomViewController : UIViewController
{
    UITextField usernameField, passwordField;
    public override void ViewDidLoad()
    {
       // keep the code the username UITextField
        passwordField = new UITextField
        {
            Placeholder = "Enter your password",
            BorderStyle = UITextBorderStyle.RoundedRect,
            Frame = new CGRect(10, 114, w - 20, h),
            SecureTextEntry = true
        };

      View.AddSubview(usernameField);
      View.AddSubview(passwordField);
   }
}

La SecureTextEntry = true configuración oculta el texto escrito en el elemento por el UITextField usuario, como se muestra a continuación:

Si se establece SecureTextEntry true, se oculta el texto escrito por el usuario.

Agregar el botón

A continuación, agregaremos un botón para que el usuario pueda enviar el nombre de usuario y la contraseña. El botón se agrega a la jerarquía de vistas como cualquier otro control, pasando de nuevo como argumento al método de la AddSubview vista primaria.

El código siguiente agrega el botón y registra un controlador de eventos para el TouchUpInside evento:

var submitButton = UIButton.FromType (UIButtonType.RoundedRect);

submitButton.Frame = new CGRect (10, 170, w - 20, 44);
submitButton.SetTitle ("Submit", UIControlState.Normal);

submitButton.TouchUpInside += (sender, e) => {
    Console.WriteLine ("Submit button pressed");
};

View.AddSubview(submitButton);

Con esto en su lugar, la pantalla de inicio de sesión ahora aparece como se muestra a continuación:

Pantalla de inicio de sesión

A diferencia de las versiones anteriores de iOS, el fondo del botón predeterminado es transparente. La modificación de la propiedad BackgroundColor del botón cambia lo siguiente:

submitButton.BackgroundColor = UIColor.White;

Esto dará como resultado un botón cuadrado en lugar del típico botón con bordes redondeados. Para obtener el borde redondeado, use el siguiente fragmento de código:

submitButton.Layer.CornerRadius = 5f;

Con estos cambios, la vista tendrá el siguiente aspecto:

Ejecución de ejemplo de la vista

Agregar varias vistas a la jerarquía de vistas

iOS proporciona un recurso para agregar varias vistas a la jerarquía de vistas mediante AddSubviews .

View.AddSubviews(new UIView[] { usernameField, passwordField, submitButton });

Agregar funcionalidad de botón

Cuando se hace clic en un botón, los usuarios esperarán que suceda algo. Por ejemplo, se muestra una alerta o se realiza la navegación a otra pantalla.

Vamos a agregar código para insertar un segundo controlador de vista en la pila de navegación.

En primer lugar, cree el segundo controlador de vista:

var loginVC = new UIViewController () { Title = "Login Success!"};
loginVC.View.BackgroundColor = UIColor.Purple;

A continuación, agregue la funcionalidad al TouchUpInside evento :

submitButton.TouchUpInside += (sender, e) => {
                this.NavigationController.PushViewController (loginVC, true);
            };

A continuación se muestra la navegación:

La navegación se muestra en este gráfico

Tenga en cuenta que, de forma predeterminada, cuando se usa un controlador de navegación, iOS proporciona a la aplicación una barra de navegación y un botón Atrás para que pueda volver a través de la pila.

Iteración por la jerarquía de vistas

Es posible recorrer en iteración la jerarquía de subvistas y seleccionar cualquier vista determinada. Por ejemplo, para buscar cada uno de ellos y darle un botón diferente, se puede usar el UIButtonBackgroundColor siguiente fragmento de código.

foreach(var subview in View.Subviews)
{
    if (subview is UIButton)
    {
         var btn = subview as UIButton;
         btn.BackgroundColor = UIColor.Green;
    }
}

Sin embargo, esto no funcionará si la vista para la que se está iterando es , ya que todas las vistas volverán a ser como un objeto , ya que los objetos agregados a la vista primaria heredan UIViewUIViewUIView .

Control de la rotación

Si el usuario gira el dispositivo a horizontal, los controles no cambian de tamaño correctamente, como se muestra en la captura de pantalla siguiente:

Si el usuario gira el dispositivo a horizontal, los controles no cambian de tamaño correctamente.

Una manera de corregirlo es estableciendo la AutoresizingMask propiedad en cada vista. En este caso, queremos que los controles se ajusten horizontalmente, por lo que estableceríamos cada AutoresizingMask . El ejemplo siguiente es para , pero se tendría que aplicar lo mismo a cada usernameField clase de la jerarquía de vistas.

usernameField.AutoresizingMask = UIViewAutoresizing.FlexibleWidth;

Ahora, cuando giramos el dispositivo o el simulador, todo se extiende para rellenar el espacio adicional, como se muestra a continuación:

Todos los controles se extienden para rellenar el espacio adicional.

Creación de vistas personalizadas

Además de usar controles que forman parte de UIKit, también se pueden usar vistas personalizadas. Una vista personalizada se puede crear mediante la herencia de y UIView la invalidación de Draw . Vamos a crear una vista personalizada y agregarla a la jerarquía de vistas para mostrarla.

Heredar de UIView

Lo primero que debemos hacer es crear una clase para la vista personalizada. Para ello, usaremos la plantilla Clase de Visual Studio agregar una clase vacía denominada . La clase base debe establecerse en UIView , que recuperamos que está en el espacio de UIKit nombres . También se necesitará el espacio System.Drawing de nombres . Los otros espacios de nombres no se usarán en este ejemplo, así que System.* no dude en quitarlos.

La clase debería tener el siguiente aspecto:

using System;

namespace CodeOnlyDemo
{
    class CircleView : UIView
    {
    }
}

Dibujar en un UIView

Cada UIView tiene un método al que llama el sistema cuando es necesario Draw dibujarlo. Draw nunca se debe llamar directamente a . El sistema lo llama durante el procesamiento del bucle de ejecución. La primera vez que se pasa por el bucle de ejecución después de agregar una vista a la jerarquía de vistas, se Draw llama a su método . Las llamadas posteriores se producen cuando la vista se marca como necesario dibujar mediante una llamada Draw a o en la SetNeedsDisplaySetNeedsDisplayInRect vista.

Podemos agregar código de dibujo a nuestra vista agregando dicho código dentro del método Draw invalidado, como se muestra a continuación:

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

    //get graphics context
    using (var g = UIGraphics.GetCurrentContext())
    {
        // set up drawing attributes
        g.SetLineWidth(10.0f);
        UIColor.Green.SetFill();
        UIColor.Blue.SetStroke();

        // create geometry
        var path = new CGPath();
        path.AddArc(Bounds.GetMidX(), Bounds.GetMidY(), 50f, 0, 2.0f * (float)Math.PI, true);

        // add geometry to graphics context and draw
        g.AddPath(path);
        g.DrawPath(CGPathDrawingMode.FillStroke);
    }
}

Puesto CircleView que es , también podemos establecer UIViewUIView propiedades. Por ejemplo, podemos establecer en BackgroundColor el constructor :

public CircleView()
{
    BackgroundColor = UIColor.White;
}

Para usar el que acaba de crear, podemos agregarlo como una subvista a la jerarquía de vistas de un controlador existente, como hicimos con y anteriormente, o bien podemos cargarlo como la vista de un nuevo CircleViewUILabelsUIButton controlador. Vamos a hacer lo último.

Carga de una vista

UIViewController tiene un método denominado LoadView al que llama el controlador para crear su vista. Se trata de un lugar adecuado para crear una vista y asignarla a la propiedad del View controlador.

En primer lugar, necesitamos un controlador, así que cree una nueva clase vacía denominada CircleController .

En CircleController agregue el código siguiente para establecer en un View (no debe llamar a la implementación CircleView en la base invalidación):

using UIKit;

namespace CodeOnlyDemo
{
    class CircleController : UIViewController
    {
        CircleView view;

        public override void LoadView()
        {
            view = new CircleView();
            View = view;
        }
    }
}

Por último, es necesario presentar el controlador en tiempo de ejecución. Para ello, agreguemos un controlador de eventos en el botón enviar que agregamos anteriormente, como se muestra a continuación:

submitButton.TouchUpInside += delegate
{
    Console.WriteLine("Submit button clicked");

    //circleController is declared as class variable
    circleController = new CircleController();
    PresentViewController(circleController, true, null);
};

Ahora, cuando se ejecuta la aplicación y se pulsa el botón enviar, se muestra la nueva vista con un círculo:

Se muestra la nueva vista con un círculo

Creación de una pantalla de inicio

Se muestra una pantalla de inicio cuando la aplicación se inicia como una manera de mostrar a los usuarios que responde. Dado que se muestra una pantalla de inicio cuando se carga la aplicación, no se puede crear en el código, ya que la aplicación se sigue cargando en la memoria.

Al crear un Project iOS en Visual Studio, se proporciona una pantalla de inicio en forma de archivo .xib, que se puede encontrar en la carpeta Recursos del proyecto.

Para editarlo, haga doble clic en él y lo abra en la ventana Xcode Interface Builder.

Apple recomienda que se use un archivo .xib o Storyboard para aplicaciones destinadas a iOS 8 o posterior. Al iniciar cualquiera de los archivos en el Interface Builder de Xcode, puede usar clases de tamaño y diseño automático para adaptar el diseño para que se vea bien y se muestre correctamente para todos los tamaños de dispositivo. Se puede usar una imagen de inicio estática además de un archivo .xib o Storyboard para permitir la compatibilidad con aplicaciones destinadas a versiones anteriores.

Para obtener más información sobre cómo crear una pantalla de inicio, consulte los documentos siguientes:

Importante

A partir de iOS 9, Apple recomienda usar guiones gráficos como método principal para crear una pantalla de inicio.

Creación de una imagen de inicio para aplicaciones previas a iOS 8

Se puede usar una imagen estática además de una pantalla de inicio .xib o Storyboard si la aplicación tiene como destino versiones anteriores a iOS 8.

Esta imagen estática se puede establecer en el archivo Info.plist o como un catálogo de recursos (para iOS 7) en la aplicación. Deberá proporcionar imágenes independientes para cada tamaño de dispositivo (320 x 480, 640 x 960, 640 x 1136) en las que se pueda ejecutar la aplicación. Para más información sobre los tamaños de pantalla de inicio, consulte la guía Launch Screen Images (Iniciar imágenes de pantalla).

Importante

Si la aplicación no tiene ninguna pantalla de inicio, es posible que observe que no se ajusta completamente a la pantalla. Si este es el caso, debe asegurarse de incluir, al menos, una imagen de 640 x 1136 denominada a Default-568@2x.png info.plist.

Resumen

En este artículo se describe cómo desarrollar aplicaciones iOS mediante programación en Visual Studio. Hemos visto cómo compilar un proyecto a partir de una plantilla de proyecto vacía y hemos analizado cómo crear y agregar un controlador de vista raíz a la ventana. A continuación, mostramos cómo usar controles de UIKit para crear una jerarquía de vistas dentro de un controlador para desarrollar una pantalla de aplicación. A continuación, examinamos cómo hacer que las vistas se esclasifiquen correctamente en distintas orientaciones y vimos cómo crear una vista personalizada mediante subclases , así como cómo cargar la vista dentro de un UIView controlador. Por último, hemos explorado cómo agregar una pantalla de inicio a una aplicación.