Tworzenie interfejsów użytkownika systemu iOS w kodzie na platformie Xamarin.iOS

Interfejs użytkownika aplikacji dla systemu iOS jest jak witryna sklepu — aplikacja zazwyczaj pobiera jedno okno, ale może wypełnić okno tak wieloma obiektami, jak to wymaga, a obiekty i ustalenia można zmienić w zależności od tego, co aplikacja chce wyświetlić. Obiekty w tym scenariuszu — elementy widoczne przez użytkownika — są nazywane widokami. Aby utworzyć pojedynczy ekran w aplikacji, widoki są ułożone na siebie nawzajem w hierarchii widoków zawartości, a hierarchia jest zarządzana przez pojedynczy kontroler widoku. Aplikacje z wieloma ekranami mają wiele hierarchii widoków zawartości, z których każdy ma własny kontroler widoków, a aplikacja umieszcza widoki w oknie, aby utworzyć inną hierarchię widoku zawartości na podstawie ekranu, na podstawie którego znajduje się użytkownik.

Na poniższym diagramie przedstawiono relacje między oknami, widokami, widokami podrzędnymi i kontrolerem widoku, które łączą interfejs użytkownika z ekranem urządzenia:

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

Te hierarchie widoków można konstruować przy użyciu konstruktora interfejsu Xcode, jednak dobrze jest mieć podstawową wiedzę na temat sposobu pracy w całości w kodzie. W tym artykule przedstawiono niektóre podstawowe kwestie, które umożliwiają rozpoczęcie pracy przy użyciu interfejsu użytkownika tylko do kodu.

Tworzenie projektu tylko do kodu

Pusty szablon projektu dla systemu iOS

Najpierw utwórz projekt systemu iOS w programie Visual Studio przy użyciu projektu File > New Project > Visual C# > i Telefon & iPad iOS > App (Xamarin), jak pokazano poniżej:

New Project Dialog

Następnie wybierz szablon projektu Pusta aplikacja :

Select a Template Dialog

Szablon Empty Project (Pusty projekt) dodaje do projektu 4 pliki:

Project Files

  1. AppDelegate.cs — zawiera podklasę UIApplicationDelegate , AppDelegate która służy do obsługi zdarzeń aplikacji z systemu iOS. Okno aplikacji jest tworzone w metodzie AppDelegateFinishedLaunching .
  2. Main.cs — zawiera punkt wejścia dla aplikacji, który określa klasę dla klasy AppDelegate .
  3. Info.plist — plik listy właściwości zawierający informacje o konfiguracji aplikacji.
  4. Entitlements.plist — plik listy właściwości zawierający informacje o możliwościach i uprawnieniach aplikacji.

Aplikacje systemu iOS są tworzone przy użyciu wzorca MVC. Pierwszy ekran wyświetlany przez aplikację jest tworzony na podstawie głównego kontrolera widoku okna. Aby uzyskać więcej informacji na temat samego wzorca MVC, zobacz przewodnik Hello, iOS Multiscreen.

Implementacja dodawana AppDelegate przez szablon tworzy okno aplikacji, z którego jest dostępna tylko jedna dla każdej aplikacji systemu iOS i powoduje, że jest ona widoczna za pomocą następującego kodu:

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

Jeśli chcesz teraz uruchomić tę aplikację, prawdopodobnie zostanie zgłoszony wyjątek z informacją o tym, że Application windows are expected to have a root view controller at the end of application launch. Dodajmy kontroler i ustawmy go jako kontroler widoku głównego aplikacji.

Dodawanie kontrolera

Aplikacja może zawierać wiele kontrolerów widoku, ale musi mieć jeden kontroler widoku głównego, aby kontrolować wszystkie kontrolery widoku. Dodaj kontroler do okna, tworząc UIViewController wystąpienie i ustawiając je na Window.RootViewController właściwość :

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

Każdy kontroler ma skojarzony widok, który jest dostępny z właściwości.View Powyższy kod zmienia właściwość widoku BackgroundColor na UIColor.LightGray tak, aby była widoczna, jak pokazano poniżej:

The View's background is a visible light gray

Możemy również ustawić dowolną UIViewController podklasę RootViewController w ten sposób, w tym kontrolery z zestawu UIKit, a także te, które piszemy. Na przykład następujący kod dodaje element UINavigationController jako :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;
    }
}

Spowoduje to utworzenie kontrolera zagnieżdżonego w kontrolerze nawigacji, jak pokazano poniżej:

The controller nested within the navigation controller

Tworzenie kontrolera widoku

Teraz, gdy zobaczyliśmy, jak dodać kontroler jako RootViewController okno, zobaczmy, jak utworzyć niestandardowy kontroler widoku w kodzie.

Dodaj nową klasę o nazwie, CustomViewController jak pokazano poniżej:

Klasa powinna dziedziczyć z UIViewControllerklasy , która znajduje się w UIKit przestrzeni nazw, jak pokazano poniżej:

using System;
using UIKit;

namespace CodeOnlyDemo
{
    class CustomViewController : UIViewController
    {
    }
}

Inicjowanie widoku

UIViewController zawiera metodę o nazwie , która jest wywoływana ViewDidLoad , gdy kontroler widoku jest po raz pierwszy załadowany do pamięci. Jest to odpowiednie miejsce do inicjowania widoku, takiego jak ustawienie jego właściwości.

Na przykład poniższy kod dodaje przycisk i procedurę obsługi zdarzeń, aby wypchnąć nowy kontroler widoku do stosu nawigacji po naciśnięciu przycisku:

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

        }
    }
}

Aby załadować ten kontroler w aplikacji i zademonstrować prostą nawigację, utwórz nowe wystąpienie klasy CustomViewController. Utwórz nowy kontroler nawigacji, przekaż wystąpienie kontrolera widoku i ustaw nowy kontroler nawigacji na okno RootViewController w AppDelegate następujący sposób:

var cvc = new CustomViewController ();

var navController = new UINavigationController (cvc);

Window.RootViewController = navController;

Teraz, gdy aplikacja zostanie załadowana, CustomViewController element zostanie załadowany wewnątrz kontrolera nawigacji:

The CustomViewController is loaded inside a navigation controller

Kliknięcie przycisku spowoduje wypchnięcie nowego kontrolera widoku do stosu nawigacji:

A new View Controller pushed onto the navigation stack

Kompilowanie hierarchii widoków

W powyższym przykładzie zaczęliśmy tworzyć interfejs użytkownika w kodzie, dodając przycisk do kontrolera widoku.

Interfejsy użytkownika systemu iOS składają się z hierarchii widoków. Dodatkowe widoki, takie jak etykiety, przyciski, suwaki itp., są dodawane jako widoki podrzędne niektórych widoków nadrzędnych.

Na przykład zmodyfikujmy CustomViewController element , aby utworzyć ekran logowania, na którym użytkownik może wprowadzić nazwę użytkownika i hasło. Ekran będzie składać się z dwóch pól tekstowych i przycisku.

Dodawanie pól tekstowych

Najpierw usuń przycisk i procedurę obsługi zdarzeń, która została dodana w sekcji Inicjowanie widoku .

Dodaj kontrolkę dla nazwy użytkownika, tworząc i inicjując element UITextField , a następnie dodając ją do hierarchii widoków, jak pokazano poniżej:

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

Podczas tworzenia UITextFieldobiektu ustawiamy Frame właściwość , aby zdefiniować jej lokalizację i rozmiar. W systemie iOS współrzędna 0,0 znajduje się w lewym górnym rogu z +x w prawo i +y w dół. Po ustawieniu parametru Frame wraz z kilkoma innymi właściwościami wywołujemy metodę View.AddSubview , aby dodać UITextField element do hierarchii widoków. Dzięki usernameField temu widok podrzędny UIView wystąpienia, do którego View odwołuje się właściwość. Widok podrzędny jest dodawany z kolejnością z większą niż jej widok nadrzędny, więc pojawia się przed widokiem nadrzędnym na ekranie.

Aplikacja z dołączonym elementem UITextField jest pokazana poniżej:

The application with the UITextField included

Możemy dodać UITextField element dla hasła w podobny sposób, tym razem ustawimy SecureTextEntry właściwość na true, jak pokazano poniżej:

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

Ustawienie SecureTextEntry = true ukrywa tekst wprowadzony przez UITextField użytkownika, jak pokazano poniżej:

Setting SecureTextEntry true hides the text entered by the user

Dodawanie przycisku

Następnie dodamy przycisk, aby użytkownik mógł przesłać nazwę użytkownika i hasło. Przycisk jest dodawany do hierarchii widoków, podobnie jak każda inna kontrolka, przekazując go jako argument do metody widoku nadrzędnego AddSubview .

Poniższy kod dodaje przycisk i rejestruje procedurę obsługi zdarzeń dla TouchUpInside zdarzenia:

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

W tym miejscu zostanie wyświetlony ekran logowania, jak pokazano poniżej:

The login screen

W przeciwieństwie do poprzednich wersji systemu iOS domyślne tło przycisku jest przezroczyste. Zmiana właściwości przycisku BackgroundColor powoduje zmianę następujących zmian:

submitButton.BackgroundColor = UIColor.White;

Spowoduje to naciśnięcie przycisku kwadratowego, a nie typowego zaokrąglonego przycisku krawędzi. Aby uzyskać zaokrąglone krawędzie, użyj następującego fragmentu kodu:

submitButton.Layer.CornerRadius = 5f;

Po wprowadzeniu tych zmian widok będzie wyglądać następująco:

An example run of the view

Dodawanie wielu widoków do hierarchii widoków

System iOS udostępnia funkcję dodawania wielu widoków do hierarchii widoków przy użyciu polecenia AddSubviews.

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

Dodawanie funkcji przycisku

Po kliknięciu przycisku użytkownicy będą oczekiwać, że coś się stanie. Na przykład wyświetlany jest alert lub nawigacja jest wykonywana na innym ekranie.

Dodajmy kod, aby wypchnąć drugi kontroler widoku do stosu nawigacji.

Najpierw utwórz drugi kontroler widoku:

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

Następnie dodaj funkcję do TouchUpInside zdarzenia:

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

Nawigacja jest pokazana poniżej:

The navigation is illustrated in this chart

Zauważ, że domyślnie w przypadku korzystania z kontrolera nawigacji system iOS udostępnia aplikacji pasek nawigacyjny i przycisk wstecz, aby umożliwić powrót przez stos.

Iterowanie za pośrednictwem hierarchii widoków

Istnieje możliwość iterowania przez hierarchię widoku podrzędnego i wybranie dowolnego określonego widoku. Aby na przykład znaleźć każdy UIButton z nich i nadać mu inny BackgroundColorprzycisk, można użyć następującego fragmentu kodu

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

Nie będzie to jednak działać, jeśli widok jest iterated dla elementu , UIView ponieważ wszystkie widoki zostaną przywrócone jako UIView obiekty dodane do widoku nadrzędnego dziedziczą UIViewwartość .

Obsługa rotacji

Jeśli użytkownik obraca urządzenie w poziomie, kontrolki nie zmieniają odpowiedniego rozmiaru, jak pokazano na poniższym zrzucie ekranu:

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

Jednym ze sposobów rozwiązania tego problemu AutoresizingMask jest ustawienie właściwości w każdym widoku. W tym przypadku chcemy, aby kontrolki rozciągały się w poziomie, więc ustawilibyśmy każdy AutoresizingMaskelement . Poniższy przykład dotyczy usernameFieldelementu , ale ten sam element należy zastosować do każdego gadżetu w hierarchii widoków.

usernameField.AutoresizingMask = UIViewAutoresizing.FlexibleWidth;

Teraz, gdy obracamy urządzenie lub symulator, wszystko rozciąga się, aby wypełnić dodatkowe miejsce, jak pokazano poniżej:

All the controls stretch to fill the additional space

Tworzenie widoków niestandardowych

Oprócz używania kontrolek będących częścią zestawu UIKit można również używać widoków niestandardowych. Widok niestandardowy można utworzyć, dziedzicząc z UIView i przesłaniając Drawelement . Utwórzmy widok niestandardowy i dodajmy go do hierarchii widoków w celu zademonstrowania.

Dziedziczenie z widoku interfejsu użytkownika

Pierwszą rzeczą, którą musimy zrobić, jest utworzenie klasy dla widoku niestandardowego. Zrobimy to przy użyciu szablonu Klasa w programie Visual Studio, aby dodać pustą klasę o nazwie CircleView. Klasa bazowa powinna być ustawiona na UIView, którą przypominamy w UIKit przestrzeni nazw. Będziemy również potrzebować System.Drawing przestrzeni nazw. Inne różne System.* przestrzenie nazw nie będą używane w tym przykładzie, więc możesz je usunąć.

Klasa powinna wyglądać następująco:

using System;

namespace CodeOnlyDemo
{
    class CircleView : UIView
    {
    }
}

Rysowanie w widoku interfejsu użytkownika

Każda UIView z nich ma metodę wywoływaną Draw przez system, gdy musi zostać narysowana. Draw nigdy nie należy wywoływać bezpośrednio. Jest on wywoływany przez system podczas przetwarzania pętli przebiegu. Po pierwszym przejściu przez pętlę uruchamiania po dodaniu widoku do hierarchii widoków wywoływana jest jej Draw metoda. Kolejne wywołania są Draw wykonywane, gdy widok jest oznaczony jako wymagający rysowania przez wywołanie SetNeedsDisplay elementu lub SetNeedsDisplayInRect w widoku.

Możemy dodać kod rysunku do naszego widoku, dodając taki kod wewnątrz metody przesłoniętej Draw , jak pokazano poniżej:

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

Ponieważ CircleView element to UIView, możemy również ustawić UIView właściwości. Na przykład możemy ustawić BackgroundColor element w konstruktorze:

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

Aby użyć właśnie utworzonego CircleView obiektu, możemy dodać go jako widok podrzędny do hierarchii widoków w istniejącym kontrolerze, tak jak w przypadku elementów UILabels i UIButton wcześniejszych, lub załadować go jako widok nowego kontrolera. Zróbmy to drugie.

Ładowanie widoku

UIViewController ma metodę o nazwie LoadView , która jest wywoływana przez kontroler w celu utworzenia widoku. Jest to odpowiednie miejsce do utworzenia widoku i przypisania go do właściwości kontrolera View .

Najpierw potrzebujemy kontrolera, więc utwórz nową pustą klasę o nazwie CircleController.

W CircleController pliku dodaj następujący kod, aby ustawić View element na wartość ( CircleView implementacja base nie powinna być wywoływana w zastąpieniu):

using UIKit;

namespace CodeOnlyDemo
{
    class CircleController : UIViewController
    {
        CircleView view;

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

Na koniec musimy przedstawić kontroler w czasie wykonywania. Zróbmy to, dodając procedurę obsługi zdarzeń na dodanym wcześniej przycisku przesyłania w następujący sposób:

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

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

Teraz po uruchomieniu aplikacji i naciśnięciu przycisku przesyłania zostanie wyświetlony nowy widok z okręgiem:

The new view with a circle is displayed

Tworzenie ekranu uruchamiania

Ekran uruchamiania jest wyświetlany, gdy aplikacja zostanie uruchomiona jako sposób wyświetlania użytkownikom, że odpowiada. Ponieważ podczas ładowania aplikacji jest wyświetlany ekran uruchamiania, nie można go utworzyć w kodzie, ponieważ aplikacja jest nadal ładowana do pamięci.

Podczas tworzenia projektu systemu iOS w programie Visual Studio zostanie udostępniony ekran uruchamiania w postaci pliku .xib, który można znaleźć w folderze Resources w projekcie.

Można to edytować, klikając go dwukrotnie i otwierając go w narzędziu Xcode Interface Builder.

Firma Apple zaleca, aby plik .xib lub Storyboard był używany w aplikacjach przeznaczonych dla systemu iOS 8 lub nowszego. Po uruchomieniu pliku w narzędziu Xcode Interface Builder można użyć klas rozmiarów i automatycznego układu, aby dostosować układ tak, aby wyglądał dobrze i wyświetlał poprawnie dla wszystkich rozmiarów urządzeń. Statyczny obraz uruchamiania może być używany oprócz pliku .xib lub Storyboard, aby umożliwić obsługę aplikacji przeznaczonych dla wcześniejszych wersji.

Aby uzyskać więcej informacji na temat tworzenia ekranu uruchamiania, zapoznaj się z poniższymi dokumentami:

Ważne

Od systemu iOS 9 firma Apple zaleca, aby scenorysy były używane jako podstawowa metoda tworzenia ekranu uruchamiania.

Tworzenie obrazu uruchamiania dla aplikacji w wersji wstępnej dla systemu iOS 8

Obraz statyczny może być używany oprócz ekranu uruchamiania platformy .xib lub Storyboard, jeśli aplikacja jest przeznaczona dla wersji starszych niż iOS 8.

Ten statyczny obraz można ustawić w pliku Info.plist lub jako wykaz zasobów (dla systemu iOS 7) w aplikacji. Musisz podać oddzielne obrazy dla każdego rozmiaru urządzenia (320x480, 640x960, 640x1136), na których aplikacja może działać. Aby uzyskać więcej informacji na temat rozmiarów ekranu uruchamiania, zobacz przewodnik Launch Screen Images (Uruchamianie obrazów ekranu).

Ważne

Jeśli aplikacja nie ma ekranu uruchamiania, możesz zauważyć, że nie mieści się on w pełni na ekranie. Jeśli tak jest, pamiętaj o dołączeniu co najmniej obrazu 640x1136 o nazwie Default-568@2x.png do pliku Info.plist.

Podsumowanie

W tym artykule omówiono sposób programowego tworzenia aplikacji dla systemu iOS w programie Visual Studio. Przyjrzeliśmy się, jak utworzyć projekt z pustego szablonu projektu, omawiając sposób tworzenia i dodawania kontrolera widoku głównego do okna. Następnie pokazaliśmy, jak za pomocą kontrolek z zestawu UIKit utworzyć hierarchię widoków w kontrolerze w celu utworzenia ekranu aplikacji. Następnie sprawdziliśmy, jak ustawić widoki odpowiednio w różnych orientacjach i zobaczyliśmy, jak utworzyć widok niestandardowy przez podklasę UIView, a także jak załadować widok w obrębie kontrolera. Na koniec dowiesz się, jak dodać ekran uruchamiania do aplikacji.