Hallo Habr! Ich präsentiere Ihnen die Übersetzung des Artikels
Programmgesteuertes Erstellen von UIViews-Einschränkungen mithilfe von PureLayout von Aly Yaka.

Heute werde ich Sie durch die Erstellung einer einfachen Benutzeroberfläche für mobile Anwendungen mit Code führen, ohne Storyboards oder NIBs zu verwenden. Ich werde nicht auf Diskussionen darüber eingehen, was besser ist, da alles seine Vor- und Nachteile hat. Ich werde also nur
einen Link hinterlassen, der auf diese Angelegenheit eingeht .
Im zweiten Teil dieses Handbuchs werden einige der am häufigsten verwendeten Elemente der Benutzeroberfläche für mobile Anwendungen mit Code erstellt, darunter eine Navigationsleiste, eine Tabellenansicht und Zellen mit dynamischer Größe.
Rückblick
Dieses Tutorial wurde mit Xcode 9 und Swift 4 geschrieben. Ich gehe auch davon aus, dass Sie mit Xcode, Swift und CocoaPods vertraut sind.
Beginnen wir ohne weitere Verzögerung mit der Erstellung unseres Projekts: einer einfachen Kontaktkartenanwendung. In diesem Artikel erfahren Sie, wie Sie die Benutzeroberfläche Ihrer Anwendung in Code erstellen. Daher enthält sie keine Logik bezüglich der Funktionalität der Anwendung, es sei denn, dies ist für die Zwecke dieses Handbuchs erforderlich.
Programmgesteuertes Erstellen von Einschränkungen mit PureLayout
Projekteinrichtung
Starten Sie zunächst Xcode -> "Neues Xcode-Projekt erstellen". Wählen Sie "Single View App" und klicken Sie auf "Weiter".

Benennen Sie das Projekt so, wie Sie möchten. Ich habe beschlossen, es ContactCard zu nennen. Deaktivieren Sie alle drei Optionen unten und wählen Sie Swift als Programmiersprache aus. Klicken Sie dann auf Weiter.

Wählen Sie einen Speicherort auf Ihrem Computer aus, um das Projekt zu speichern. Deaktivieren Sie "Git-Repository auf meinem Mac erstellen".
Da wir in diesem Projekt keine Storyboards oder NIBs verwenden, löschen Sie das "Main.storyboard", das sich im Projektnavigator befindet:

Klicken Sie anschließend im Projektnavigator und auf der Registerkarte „Allgemein“ auf das Projekt, suchen Sie den Abschnitt mit den Bereitstellungsinformationen und löschen Sie alles, was in der „Hauptschnittstelle“ geschrieben ist. Dies teilt Xcode mit, welche Storyboard-Datei beim Starten der Anwendung geladen werden soll. Da wir jedoch gerade "Main.storyboard" gelöscht haben, findet Xcode diese Datei nicht, was zum Absturz der Anwendung führt.

ViewController erstellen
Wenn Sie die Anwendung jetzt ausführen, wird ein schwarzer Bildschirm angezeigt, da die Anwendung jetzt keine Quelle für die Benutzeroberfläche hat. Im nächsten Teil werden wir sie erstellen. Öffnen Sie "AppDelegate.swift" und fügen Sie in der
application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?)
Dieses Codefragment ein:
self.window = UIWindow(frame: UIScreen.main.bounds) let viewController = ViewController() self.window?.rootViewController = viewController self.window?.makeKeyAndVisible()
Dieser Code bietet ein Fenster für die Benutzerinteraktion mit der Anwendung, das normalerweise in "ViewController.swift" zu finden ist. Um schnell zu überprüfen, ob alles funktioniert, gehen Sie zu "ViewController.swift" und
viewDidLoad()
in der
viewDidLoad()
-Methode die folgende Zeile ein:
self.view.backgroundColor = .blue
Führen Sie nun die Anwendung aus.
Um zwischen Dateien in Xcode zu navigieren, verwenden Sie die Hotkeys „⇧⌘O“ und geben Sie den Dateinamen oder sogar das gesuchte Codefragment ein. Auf dem Bildschirm wird eine Liste der Dateien angezeigt, aus denen Sie auswählen können.
Nach dem Starten der Anwendung sollte dies das Ergebnis auf dem Bildschirm Ihres Simulators sein:

Natürlich werden wir dieses ekelhafte Blau nicht verwenden, also ändern Sie einfach den Hintergrund in Weiß, indem Sie
.blue
durch
.white
in
viewDidLoad ()
.
UI-Entwicklung
Um unsere Benutzeroberfläche zu erstellen, werden wir eine
Bibliothek verwenden , die unser Leben viel einfacher macht. Um PureLayout zu installieren, müssen Sie zuerst Ihr Terminal öffnen und cd und dann ein Leerzeichen eingeben, Ihren Projektordner in das Terminal ziehen und die Eingabetaste drücken. Führen Sie nun die folgenden Befehle im Terminal aus:
Dies sollte die Ausgabe Ihres Terminals nach dem zweiten Befehl sein:

Schließen Sie danach Xcode, öffnen Sie den Ordner im Finder und Sie sollten "<Ihr Projektname> .xcworkspace" finden. Dies wird geöffnet, um auf unsere Anwendung zuzugreifen, falls wir jemals CocoaPods verwenden müssen. Suchen Sie nun die Datei mit dem Namen "PodFile" und schreiben Sie die folgende Zeile unter den Ausdruck "use_frameworks"
use_frameworks!
pod “PureLayout”
Führen Sie die
pod install
erneut in Ihrem Terminal aus und erstellen Sie dann Ihr Projekt, indem Sie „Befehl + B“ drücken.
Kaffeepause
Nachdem alles eingerichtet ist, beginnen wir mit der eigentlichen Arbeit. Gehen Sie zu "ViewController.swift" und trinken Sie eine Tasse Kaffee, denn so wird das Endergebnis aussehen:

Erstellen Sie ImageView
Fügen Sie die
import PureLayout
Zeile unter
import UIKit
damit Sie die Bibliothek in dieser Datei verwenden können. Anschließend erstellen wir unter der Klassendeklaration und außerhalb einer Funktion zunächst die faule (faule)
Avatar ImageView
Variable wie folgt:
lazy var avatar: UIImageView = { let imageView = UIImageView(image: UIImage(named: "avatar.jpg")) imageView.autoSetDimensions(to: CGSize(width: 128.0, height: 128.0)) imageView.layer.borderWidth = 3.0 imageView.layer.borderColor = UIColor.lightGray.cgColor imageView.layer.cornerRadius = 64.0 imageView.clipsToBounds = true return imageView }()
Speichern Sie das Bild auf dem Desktop, das Sie als Avatar verwenden möchten, und ziehen Sie es in Xcode im Ordner <Ihr Projektname>, in meinem Fall "ContactCard". Aktivieren Sie das Kontrollkästchen "Elemente bei Bedarf kopieren" .

Schreiben Sie danach den Namen dieser Datei zusammen mit ihrer Erweiterung in die UIImage-Deklaration anstelle von "avatar.jpg".
Für diejenigen unter Ihnen, die es nicht wissen, ähneln Lazy-Variablen normalen Variablen, außer dass sie erst initialisiert werden (oder Speicherplatz zugewiesen wird), bis sie zum ersten Mal benötigt oder aufgerufen werden . Dies bedeutet, dass verzögerte Variablen nicht initialisiert werden, wenn der View Controller initialisiert wird, sondern einen späteren Zeitpunkt erwarten, an dem sie wirklich benötigt werden, was Verarbeitungsleistung und Speicherplatz für andere Prozesse spart. Dies ist besonders nützlich, wenn Sie Komponenten der Benutzeroberfläche initialisieren.
PureLayout in Aktion
Wie Sie in der Initialisierung sehen können, ist die Zeile
imageView.autoSetDimensions (to: CGSize (width: 128.0, height: 128.0))
PureLayout in Aktion. In einer Zeile legen wir eine Grenze für die Höhe und Breite der UIImageView fest, und alle erforderlichen NSLayoutConstraints werden erstellt, ohne dass große Funktionsaufrufe erforderlich sind. Wenn Sie programmgesteuert Einschränkungen erstellen wollten, haben Sie sich höchstwahrscheinlich bereits in diese wunderbare Bibliothek verliebt.
Um dieses Bild rund zu machen, setzen wir seinen Winkelradius auf die Hälfte seiner Breite oder Höhe, was 64,0 Punkten entspricht. Setzen Sie außerdem die Eigenschaft
clipsToBounds
auf
true
, um dem Bild
clipsToBounds
, dass alles
clipsToBounds
soll, was außerhalb des gerade festgelegten Radius liegt.
Anschließend erstellen wir eine UIView, die als oberste Ansicht hinter dem grau gestrichenen Avatar dient. Deklarieren Sie die folgende Lazy-Variable für diese Ansicht:
lazy var upperView: UIView = { let view = UIView() view.autoSetDimension(.height, toSize: 128) view.backgroundColor = .gray return view }()
Unteransichten hinzufügen
Bevor wir fortfahren, erstellen wir eine
func addSubviews ()
-Funktion, die die gerade erstellten Ansichten (und alle anderen, die wir erstellen werden) als Unteransichten zum Ansichtscontroller hinzufügt:
func addSubviews() { self.view.addSubview(avatar) self.view.addSubview(upperView) }
viewDidLoad (): self.addSubviews ()
nun die folgende Zeile zu
viewDidLoad (): self.addSubviews ()
Einschränkungen festlegen
Um eine Vorstellung davon zu bekommen, wie weit wir gekommen sind, setzen wir diesen beiden Arten Grenzen. Erstellen Sie eine weitere Funktion namens
func setupConstraints()
und fügen Sie die folgenden Einschränkungen ein:
func setupConstraints() { avatar.autoAlignAxis(toSuperviewAxis: .vertical) avatar.autoPinEdge(toSuperviewEdge: .top, withInset: 64.0) upperView.autoPinEdge(toSuperviewEdge: .left) upperView.autoPinEdge(toSuperviewEdge: .right) upperView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .bottom) }
viewDidLoad()
nun in
viewDidLoad()
setupConstraints()
wie folgt auf:
self.setupConstraints()
. Fügen Sie dies hinzu,
addSubviews()
. Dies sollte die endgültige Schlussfolgerung sein:

Bringen Sie den Avatar in den Vordergrund
Leider möchte ich das nicht erhalten. Wie Sie sehen können, liegt unsere
upperView
über dem Avatar. Dies liegt an der Tatsache, dass wir vor der
upperView
subviews
einen Avatar als
subviews
upperView
haben. Da sich diese Unteransichten in irgendeiner Form auf dem Stapel befinden, erhalten wir dieses Ergebnis. Um dies zu beheben, können wir diese beiden Zeilen einfach durch andere ersetzen, aber es gibt noch einen anderen Trick, den ich Ihnen zeigen möchte:
self.view.bringSubview (toFront: avatar)
.
Diese Methode überträgt den Avatar vom unteren Rand des Stapels nach oben. Wählen Sie also die Methode aus, die Ihnen am besten gefällt. Aus Gründen der Lesbarkeit ist es natürlich besser, Unteransichten in der Reihenfolge hinzuzufügen, in der sie angezeigt werden sollen, wenn sie sich überschneiden. Beachten Sie jedoch, dass sich die ersten hinzugefügten Unteransichten am unteren Rand des Stapels befinden und daher alle anderen sich überschneidenden Ansichten darüber angezeigt werden.
Und so sollte es eigentlich aussehen:

Segmentierte Steuerung erstellen
Als Nächstes erstellen wir ein segmentiertes Steuerelement, einen grauen Balken mit drei Abschnitten. Tatsächlich ist ein segmentiertes Steuerelement einfach zu erstellen. Gehen Sie wie folgt vor:
lazy var segmentedControl: UISegmentedControl = { let control = UISegmentedControl(items: ["Personal", "Social", "Resumè"]) control.autoSetDimension(.height, toSize: 32.0) control.selectedSegmentIndex = 0 control.layer.borderColor = UIColor.gray.cgColor control.tintColor = .gray return control }()
Ich glaube, dass alles klar ist. Der einzige Unterschied besteht darin, dass wir nach der Initialisierung eine Reihe von Zeichenfolgen bereitstellen. Jede Zeile repräsentiert die Überschrift eines unserer gewünschten Abschnitte. Wir setzen außerdem
selectedSegmentIndex
auf 0, wodurch das segmentierte Steuerelement angewiesen wird, das erste Segment während der Initialisierung auszuwählen / auszuwählen. Der Rest ist nur ein Stil zum Spielen.
Fahren wir nun fort und fügen Sie es als Unteransicht hinzu, indem Sie am Ende der Funktion
addCubviews(): self.view.addSubview(segmentedControl)
die folgende Zeile
addCubviews(): self.view.addSubview(segmentedControl)
und seine Einschränkungen lauten wie folgt:
segmentedControl.autoPinEdge(toSuperviewEdge: .left, withInset: 8.0) segmentedControl.autoPinEdge(toSuperviewEdge: .right, withInset: 8.0) segmentedControl.autoPinEdge(.top, to: .bottom, of: avatar, withOffset: 16.0)
Wir teilen dem segmentierten Steuerelement mit, dass wir es an der linken Seite der Übersicht anbringen möchten. Wir möchten jedoch das Intervall geringfügig erhöhen und nicht direkt am Bildschirmrand anbringen. Wenn Sie bemerken, verwende ich das sogenannte Acht-Punkte-Gitter, bei dem alle Abstände und Größen ein Vielfaches von acht sind. Ich mache dasselbe auf der rechten Seite des segmentierten Steuerelements. Was die letzte Einschränkung betrifft, sagt er, dass ein Scheitelpunkt mit einem Intervall von 16 Punkten an der Basis des Avatars angebracht wird.
Führen Sie den Code aus, nachdem Sie die oben genannten Einschränkungen zu
func setupConstraints()
und stellen Sie sicher, dass er folgendermaßen aussieht:

Hinzufügen eines Buttons
Nun kommen wir zum letzten Teil der Benutzeroberfläche des Lehrbuchs, der eine Schaltfläche „Bearbeiten“ ist. Fügen Sie die folgende faule Variable hinzu:
lazy var editButton: UIButton = { let button = UIButton() button.setTitle("Edit", for: .normal) button.setTitleColor(.gray, for: .normal) button.layer.cornerRadius = 4.0 button.layer.borderColor = UIColor.gray.cgColor button.layer.borderWidth = 1.0 button.tintColor = .gray button.backgroundColor = .clear button.autoSetDimension(.width, toSize: 96.0) button.autoSetDimension(.height, toSize: 32.0) return button }()
Machen Sie sich keine Sorgen darüber, wie groß die Initialisierung ist, sondern achten Sie darauf, wie ich den Titel und seine Farbe
button.setTitle
button.setTitleColor
button.setTitle
und
button.setTitleColor
. Aus bestimmten Gründen können wir den Titel einer Schaltfläche nicht festlegen, indem wir direkt auf ihr
titleLabel
zugreifen. Dies liegt daran, dass es unterschiedliche
titleLabel
für die Schaltfläche gibt und viele gerne unterschiedliche Überschriften / Farben für unterschiedliche Status haben.
Fügen Sie nun die Schaltfläche wie die übrigen Komponenten als Unteransicht hinzu und fügen Sie die folgenden Einschränkungen hinzu, damit sie dort angezeigt wird, wo sie sein sollte:
editButton.autoPinEdge(.top, to: .bottom, of: upperView, withOffset: 16.0) editButton.autoPinEdge(toSuperviewEdge: .right, withInset: 8.0)
Hier haben wir nur die rechten und oberen Grenzen für die Schaltfläche festgelegt, da wir ihr eine Größe gegeben haben, sie sich nicht erweitert und nichts anderes benötigt wird. Führen Sie nun das Projekt aus, um das Endergebnis zu sehen:

Ein paar aktuelle Notizen
Üben Sie, fügen Sie so viele Oberflächenelemente hinzu, wie Sie möchten. Erstellen Sie Ansichten aller Anwendungen, die Ihnen schwer fallen. Fangen Sie einfach an und erhöhen Sie schrittweise die Schwierigkeit. Zeichnen Sie UI-Komponenten auf ein Blatt Papier, um sich vorzustellen, wie sie zusammenpassen.
Im zweiten Teil erweitere ich dieses Handbuch, um eine Navigationsleiste, eine Tabellenansicht und Zellen mit dynamischer Größe im Code zu erstellen.