Creazione di interfacce utente iOS nel codice in Xamarin.iOS

L'interfaccia utente di un'app iOS è simile a una vetrina: l'applicazione in genere ottiene una finestra, ma può riempire la finestra con il numero di oggetti necessari e gli oggetti e le disposizioni possono essere modificati a seconda di ciò che l'app vuole visualizzare. Gli oggetti di questo scenario, ovvero gli elementi visibili per l'utente, sono chiamati visualizzazioni. In un'applicazione con un'unica finestra, le visualizzazioni vengono disposte una sopra l'altra in una gerarchia di visualizzazione del contenuto gestita da un unico controller di visualizzazione. Le applicazioni con più schermate hanno più gerarchie di visualizzazione del contenuto, ognuna con un proprio controller di visualizzazione, e l'applicazione inserisce visualizzazioni nella finestra per creare gerarchie di visualizzazione del contenuto diverse in base alla schermata visualizzata dall'utente.

Il diagramma seguente illustra le relazioni tra la finestra, le visualizzazioni, le visualizzazioni secondarie e il controller di visualizzazione che visualizzano l'interfaccia utente sullo schermo del dispositivo:

This diagram illustrates the relationships between the Window, Views, Subviews, and View Controller

Queste gerarchie di visualizzazione possono essere costruite usando Interface Builder di Xcode, ma è bene avere una conoscenza fondamentale del funzionamento del tutto nel codice. Questo articolo illustra alcuni punti di base per iniziare a funzionare con lo sviluppo dell'interfaccia utente di sola codice.

Creazione di un progetto solo codice

Modello di progetto iOS vuoto

Prima di tutto, creare un progetto iOS in Visual Studio usando il progetto File > Nuovo progetto > Visual C# > i Telefono & iPad > iOS App (Xamarin), illustrato di seguito:

New Project Dialog

Selezionare quindi il modello di progetto App vuota:

Select a Template Dialog

Il modello Progetto vuoto aggiunge 4 file al progetto:

Project Files

  1. AppDelegate.cs: contiene una UIApplicationDelegate sottoclasse, AppDelegate , che viene usata per gestire gli eventi dell'applicazione da iOS. La finestra dell'applicazione viene creata nel AppDelegatemetodo del FinishedLaunching .
  2. Main.cs : contiene il punto di ingresso per l'applicazione, che specifica la classe per .AppDelegate
  3. Info.plist - File di elenco delle proprietà che contiene le informazioni di configurazione dell'applicazione.
  4. Entitlements.plist : file di elenco delle proprietà che contiene informazioni sulle funzionalità e sulle autorizzazioni dell'applicazione.

Le applicazioni iOS vengono compilate usando il modello MVC. La prima schermata visualizzata da un'applicazione viene creata dal controller di visualizzazione radice della finestra. Per altri dettagli sul modello MVC stesso, vedere la guida a più schermi Hello, iOS.

L'implementazione per l'aggiunta AppDelegate dal modello crea la finestra dell'applicazione, di cui è presente una sola per ogni applicazione iOS e la rende visibile con il codice seguente:

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;
    }
}

Se si eseguisse ora questa applicazione, è probabile che venga generata un'eccezione che indica che Application windows are expected to have a root view controller at the end of application launch. Aggiungere un controller e impostarlo come controller di visualizzazione radice dell'app.

Aggiunta di un controller

L'app può contenere molti controller di visualizzazione, ma deve avere un controller di visualizzazione radice per controllare tutti i controller di visualizzazione. Aggiungere un controller alla finestra creando un'istanza UIViewController e impostandola sulla Window.RootViewController proprietà :

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;
    }
}

Ogni controller ha una visualizzazione associata, accessibile dalla View proprietà . Il codice precedente modifica la proprietà della BackgroundColor visualizzazione in UIColor.LightGray in modo che sia visibile, come illustrato di seguito:

The View's background is a visible light gray

Potremmo impostare qualsiasi UIViewController sottoclasse come RootViewController in questo modo, inclusi i controller di UIKit e quelli che scriviamo noi stessi. Ad esempio, il codice seguente aggiunge un oggetto UINavigationController come 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;
    }
}

Questo produce il controller annidato all'interno del controller di spostamento, come illustrato di seguito:

The controller nested within the navigation controller

Creazione di un controller di visualizzazione

Ora che è stato illustrato come aggiungere un controller come finestra RootViewController , verrà illustrato come creare un controller di visualizzazione personalizzato nel codice.

Aggiungere una nuova classe denominata CustomViewController come illustrato di seguito:

La classe deve ereditare da UIViewController, che si trova nello spazio dei UIKit nomi , come illustrato di seguito:

using System;
using UIKit;

namespace CodeOnlyDemo
{
    class CustomViewController : UIViewController
    {
    }
}

Inizializzazione della visualizzazione

UIViewController contiene un metodo chiamato che viene chiamato ViewDidLoad quando il controller View viene caricato per la prima volta in memoria. Si tratta di una posizione appropriata per l'inizializzazione della visualizzazione, ad esempio l'impostazione delle proprietà.

Ad esempio, il codice seguente aggiunge un pulsante e un gestore eventi per eseguire il push di un nuovo controller di visualizzazione nello stack di navigazione quando viene premuto il pulsante:

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);

        }
    }
}

Per caricare questo controller nell'applicazione e illustrare la navigazione semplice, creare una nuova istanza di CustomViewController. Creare un nuovo controller di spostamento, passare l'istanza del controller di visualizzazione e impostare il nuovo controller di RootViewController spostamento sulla finestra come AppDelegate prima:

var cvc = new CustomViewController ();

var navController = new UINavigationController (cvc);

Window.RootViewController = navController;

A questo punto, CustomViewController quando l'applicazione viene caricata all'interno di un controller di spostamento:

The CustomViewController is loaded inside a navigation controller

Facendo clic sul pulsante, si eseguirà il push di un nuovo controller di visualizzazione nello stack di spostamento:

A new View Controller pushed onto the navigation stack

Compilazione della gerarchia di viste

Nell'esempio precedente è stata avviata la creazione di un'interfaccia utente nel codice aggiungendo un pulsante al controller di visualizzazione.

Le interfacce utente iOS sono costituite da una gerarchia di visualizzazioni. Le visualizzazioni aggiuntive, ad esempio etichette, pulsanti, dispositivi di scorrimento e così via, vengono aggiunte come visualizzazioni secondarie di alcune visualizzazioni padre.

Ad esempio, modificare per CustomViewController creare una schermata di accesso in cui l'utente può immettere un nome utente e una password. La schermata sarà costituita da due campi di testo e un pulsante.

Aggiunta dei campi di testo

Rimuovere prima di tutto il pulsante e il gestore eventi aggiunti nella sezione Inizializzazione della vista .

Aggiungere un controllo per il nome utente creando e inizializzando e UITextField quindi aggiungendolo alla gerarchia di visualizzazione, come illustrato di seguito:

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);
    }
}

Quando si crea UITextField, si imposta la proprietà per definirne la Frame posizione e le dimensioni. In iOS la coordinata 0,0 si trova in alto a sinistra con +x a destra e +y verso il basso. Dopo aver impostato insieme Frame un paio di altre proprietà, viene chiamato View.AddSubview per aggiungere l'oggetto UITextField alla gerarchia di visualizzazione. In questo modo viene usernameField creata una visualizzazione secondaria dell'istanza UIView a cui fa riferimento la View proprietà. Viene aggiunta una visualizzazione secondaria con un ordine z superiore a quello padre, quindi viene visualizzato davanti alla visualizzazione padre sullo schermo.

L'applicazione con l'oggetto UITextField incluso è illustrata di seguito:

The application with the UITextField included

È possibile aggiungere un UITextField oggetto per la password in modo simile, solo questa volta la proprietà viene impostata SecureTextEntry su true, come illustrato di seguito:

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);
   }
}

L'impostazione SecureTextEntry = true nasconde il testo immesso nell'oggetto UITextField dall'utente, come illustrato di seguito:

Setting SecureTextEntry true hides the text entered by the user

Aggiunta del pulsante

Verrà quindi aggiunto un pulsante in modo che l'utente possa inviare il nome utente e la password. Il pulsante viene aggiunto alla gerarchia di visualizzazione come qualsiasi altro controllo, passandolo di nuovo come argomento al metodo della AddSubview visualizzazione padre.

Il codice seguente aggiunge il pulsante e registra un gestore eventi per l'evento TouchUpInside :

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 questo aspetto, la schermata di accesso viene ora visualizzata come illustrato di seguito:

The login screen

A differenza delle versioni precedenti di iOS, lo sfondo del pulsante predefinito è trasparente. La modifica della proprietà del BackgroundColor pulsante cambia:

submitButton.BackgroundColor = UIColor.White;

In questo modo verrà generato un pulsante quadrato anziché il tipico pulsante arrotondato. Per ottenere il bordo arrotondato, usare il frammento di codice seguente:

submitButton.Layer.CornerRadius = 5f;

Con queste modifiche, la visualizzazione sarà simile alla seguente:

An example run of the view

Aggiunta di più visualizzazioni alla gerarchia di visualizzazione

iOS offre una funzionalità per aggiungere più visualizzazioni alla gerarchia di visualizzazione usando AddSubviews.

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

Aggiunta della funzionalità del pulsante

Quando si fa clic su un pulsante, gli utenti si aspettano che si verifichi un evento. Ad esempio, viene visualizzato un avviso o lo spostamento viene eseguito su un'altra schermata.

Aggiungere un codice per eseguire il push di un secondo controller di visualizzazione nello stack di navigazione.

Creare prima di tutto il secondo controller di visualizzazione:

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

Aggiungere quindi la funzionalità all'evento TouchUpInside :

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

La navigazione è illustrata di seguito:

The navigation is illustrated in this chart

Si noti che per impostazione predefinita, quando si usa un controller di spostamento, iOS fornisce all'applicazione una barra di spostamento e un pulsante Indietro per consentire di tornare indietro nello stack.

Iterazione nella gerarchia di visualizzazione

È possibile scorrere la gerarchia della visualizzazione secondaria e selezionare qualsiasi visualizzazione specifica. Ad esempio, per trovare ogni UIButton elemento e assegnare un pulsante diverso BackgroundColor, è possibile usare il frammento di codice seguente

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

Ciò, tuttavia, non funzionerà se la visualizzazione per cui viene eseguita l'iterazione è perché UIView tutte le visualizzazioni verranno restituite come oggetti UIView aggiunti alla visualizzazione padre stessi ereditano UIView.

Gestione della rotazione

Se l'utente ruota il dispositivo in orizzontale, i controlli non vengono ridimensionati in modo appropriato, come illustrato nello screenshot seguente:

If the user rotates the device to landscape, the controls do not resize appropriately

Un modo per risolvere questo problema consiste nell'impostare la AutoresizingMask proprietà in ogni visualizzazione. In questo caso si vuole che i controlli si allungino orizzontalmente, quindi si impostano ogni AutoresizingMaskoggetto . L'esempio seguente è per usernameField, ma lo stesso deve essere applicato a ogni gadget nella gerarchia di visualizzazione.

usernameField.AutoresizingMask = UIViewAutoresizing.FlexibleWidth;

Ora, quando si ruota il dispositivo o il simulatore, tutto si estende per riempire lo spazio aggiuntivo, come illustrato di seguito:

All the controls stretch to fill the additional space

Creazione di visualizzazioni personalizzate

Oltre a usare controlli che fanno parte di UIKit, è anche possibile usare visualizzazioni personalizzate. È possibile creare una vista personalizzata ereditando da UIView ed eseguendo l'override di Draw. Creare una vista personalizzata e aggiungerla alla gerarchia di visualizzazione da illustrare.

Ereditarietà da UIView

La prima cosa da fare è creare una classe per la visualizzazione personalizzata. A questo scopo si userà il modello classe in Visual Studio per aggiungere una classe vuota denominata CircleView. La classe base deve essere impostata su UIView, che viene richiamata nello spazio dei UIKit nomi . Sarà necessario anche lo System.Drawing spazio dei nomi. Gli altri System.* spazi dei nomi non verranno usati in questo esempio, quindi è possibile rimuoverli.

La classe dovrebbe risultare simile alla seguente:

using System;

namespace CodeOnlyDemo
{
    class CircleView : UIView
    {
    }
}

Disegno in un oggetto UIView

Ogni UIView oggetto ha un Draw metodo chiamato dal sistema quando deve essere disegnato. Draw non deve mai essere chiamato direttamente. Viene chiamato dal sistema durante l'elaborazione del ciclo di esecuzione. La prima volta che si esegue il ciclo di esecuzione dopo l'aggiunta di una vista alla gerarchia di visualizzazione, viene chiamato il relativo Draw metodo. Le chiamate successive da Draw eseguire quando la vista è contrassegnata come necessario per essere disegnata chiamando SetNeedsDisplay o SetNeedsDisplayInRect nella vista.

È possibile aggiungere codice di disegno alla vista aggiungendo tale codice all'interno del metodo sottoposto Draw a override, come illustrato di seguito:

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);
    }
}

Poiché CircleView è , UIViewè anche possibile impostare UIView le proprietà. Ad esempio, è possibile impostare nel BackgroundColor costruttore:

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

Per usare l'oggetto CircleView appena creato, è possibile aggiungerlo come visualizzazione secondaria alla gerarchia di visualizzazione in un controller esistente, come è stato fatto con UILabels e UIButton in precedenza, oppure caricarlo come visualizzazione di un nuovo controller. Facciamo quest'ultima.

Caricamento di una visualizzazione

UIViewController dispone di un metodo denominato LoadView chiamato dal controller per crearne la visualizzazione. Si tratta di una posizione appropriata per creare una vista e assegnarla alla proprietà del View controller.

Prima di tutto, è necessario un controller, quindi creare una nuova classe vuota denominata CircleController.

Aggiungere CircleController il codice seguente per impostare su View ( CircleView non è consigliabile chiamare l'implementazione nell'override base ):

using UIKit;

namespace CodeOnlyDemo
{
    class CircleController : UIViewController
    {
        CircleView view;

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

Infine, è necessario presentare il controller in fase di esecuzione. A questo scopo, aggiungere un gestore eventi sul pulsante di invio aggiunto in precedenza, come indicato di seguito:

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

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

A questo punto, quando si esegue l'applicazione e si tocca il pulsante di invio, viene visualizzata la nuova visualizzazione con un cerchio:

The new view with a circle is displayed

Creazione di una schermata di avvio

Una schermata di avvio viene visualizzata all'avvio dell'app come modo per visualizzare agli utenti che è reattiva. Poiché una schermata di avvio viene visualizzata quando l'app viene caricata, non può essere creata nel codice perché l'applicazione viene ancora caricata in memoria.

Quando si crea un progetto iOS in Visual Studio, viene fornita una schermata di avvio sotto forma di file xib, disponibile nella cartella Risorse all'interno del progetto.

Questa operazione può essere modificata facendo doppio clic su di essa e aprendola in Xcode Interface Builder.

Apple consiglia di usare un file con estensione xib o Storyboard per le applicazioni destinate a iOS 8 o versioni successive, quando si avvia uno dei file in Xcode Interface Builder, è possibile usare classi di dimensioni e layout automatico per adattare il layout in modo che risulti corretto e visualizzato correttamente per tutte le dimensioni del dispositivo. Un'immagine di avvio statica può essere usata oltre a un file con estensione xib o Storyboard per consentire il supporto per le applicazioni destinate alle versioni precedenti.

Per altre informazioni sulla creazione di una schermata di avvio, vedere i documenti seguenti:

Importante

A partire da iOS 9, Apple consiglia di usare storyboard come metodo principale per la creazione di una schermata di avvio.

Creazione di un'immagine di avvio per le applicazioni pre-iOS 8

Un'immagine statica può essere usata oltre a una schermata di avvio con estensione xib o Storyboard se l'applicazione è destinata alle versioni precedenti a iOS 8.

Questa immagine statica può essere impostata nel file Info.plist o come catalogo asset (per iOS 7) nell'applicazione. Sarà necessario fornire immagini separate per ogni dimensione del dispositivo (320x480, 640x960, 640x1136) su cui l'applicazione può essere eseguita. Per altre informazioni sulle dimensioni della schermata di avvio, vedere la guida Launch Screen Images (Immagini dello schermo di avvio).

Importante

Se la tua app non ha schermata di avvio, potresti notare che non rientra completamente nello schermo. In questo caso, è necessario assicurarsi di includere, almeno, un'immagine 640x1136 denominata Default-568@2x.png nel file Info.plist.

Riepilogo

Questo articolo ha illustrato come sviluppare applicazioni iOS a livello di codice in Visual Studio. È stato illustrato come compilare un progetto da un modello di progetto vuoto, illustrando come creare e aggiungere un controller di visualizzazione radice alla finestra. È stato quindi illustrato come usare i controlli di UIKit per creare una gerarchia di visualizzazione all'interno di un controller per sviluppare una schermata dell'applicazione. Successivamente è stato esaminato come impostare il layout delle visualizzazioni in modo appropriato in diversi orientamenti ed è stato illustrato come creare una visualizzazione personalizzata sottoclassando UIView, nonché come caricare la vista all'interno di un controller. Infine è stato illustrato come aggiungere una schermata di avvio a un'applicazione.