UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Wir bauen eine Detailansicht

Bisher haben wir in unsere App eine Liste von Bildern/Bildnamen aus denen wir auswählen können, aber obwohl wir einen Namen antippen passiert nichts. Unser nächstes Ziel wird sein eine neue Anzeige zu entwerfen, die erscheint sobald man eine Zeile auswählt/antippt. Es soll das gewählte Bild vollflächig anzeigen und von der Seite hereinkommen.

Dieses können wir in zwei überschaubare Aufgaben teilen: Erstens bauen wir den Code, der sich um diese Anzeige kümmert. Zweitens entwerfen wir die dafür nötige Benutzeroberfläche im Interface Builder.

Fangen wir mit dem Leichteren an, dem Code. Öffne im Menübalken oben das Menpü File und dort New > File – und es erscheint ein dialog voller Auswahlmöglichkeiten. Wähle davon iOS > Cocoa Touch Class und klicke danach auf Next.

Du wirst nach dem Namen für die neue Anzeige gefragt und stellst auch ein, auf welcher Basisklasse die Anzeige basieren soll. Gib dort als Name “DetailViewController” an und “UIViewController” bei “Subclass Of”. Deaktiviere “Also create XIB file” und klicke Next und Create zum Anlegen der neuen Datei, in die der Start-Code für unsere Detailansicht geschrieben wird.

Nun müssen wir schon etwas mehr nachdenken. Kehre zurück zu Main.storyboard, wo Du Deine beiden existierenden View Controller vorfindest: Links der Navigation View Controller und rechts daneben der Table View Controller. Nun legen wir einen Dritten an – unsere Detailansicht.

Öffne die Objekt Bibliothek, finde dort den Eintrag "View Controller" und ziehe ihn mit gedrückter Maustaste rechts neben unseren bisherigen View Controller. Eigentlich ist es egal wohin, aber es empfiehlt sich eine Reihenfolge (nach der Bedienlogik) von Links nach Rechts beizubehalten.

In der Dokumentübersicht erscheint ein zweiter Eintrag als “View Controller scene”. Der erste war für die Tabelle und der neue ist für die Detailansicht. Wenn Du dir dabei nicht sicher bist, klicke einfach auf die neu erzeugte Fläche im Zeichnungsbereich und beobachte, welcher der beiden in der Übersicht ausgewählt wird.

Als wir vorhin unsere Tabellen-Zelle angelegt hatten, gaben wir ihr einen Indentifier über den wir sie per Code laden konnten. Das Selbe müssen wir nun auch für unsere Detailanzeige machen. Als Du es eben ausgewählt hattest, sollte "View" in der Übersicht hervorgeboben worden sein. Darüber sollte “View Controller” mit einem gelben Icon daneben sein – klicke das um den gesamten View Controller auszuwählen.

Um den View Controller einen Namen zu geben, öffne den Identity Inspector mit Cmd+Alt+3 oder über das Menü. Gib nun unter “Storyboard ID” den Namen “Detail” ein. Das war's. Ab jetzt können wir per Code auf diesen View Controller unter dem ID “Detail” zugreifen. Um es auch mit der richtigen Klasse im Code zu verknüpfen, klicke auf den Pfeil neben "Class" und wähle dort “DetailViewController” aus.

Nun wird es interessant: Wir wollen das vom Anwender gewählte Bild gross und schön präsentieren. Dazu verwendet man am besten eine Ableitung der Klasse UIImageView. Wie der Name (“UI…”) schon andeutet, ist es Teil des UIKit und zuständig für die Anzeige von Bildern - perfekt!

Halte in der Objekt-Bibliothek Ausschau nach “Image View”; am schnellsten findest Du es wohl wieder über den Namensfilter. Ziehe ihn über den View Controller der Detailansicht und lass die Maustaste los. Vergrössere die Seiten auf die gesamte Fläche der Ansicht.

Vergrössere die Seiten auf die gesamte Fläche der Ansicht – bis unter das Batterieladesymbol.

Derzeit zeigt die neue Ansicht nichts ausser einem bläulichen Hintergrund und dem Wort UIImageView. Was angezeigt werden soll, bestimmen wir nicht hier, sondern während der Laufzeit, über Programmcode. Aber wir sollten hier angeben wie die Bildgrösse sein soll, je nachdem ob die App auf einem iPhone oder iPad läuft.

“Aber wir haben doch eben die Ränder erweitert auf die der Detailansicht – reicht das nicht?” Nicht ganz! Bedenke die Vielzahl an Bildschirmgrössen, Orientierungen und Multi-App-Layouts die es bei iOS geben kann. Wie soll sich die Bildanzeige verhalten?

iOS hat dafür eine Lösung und die arbeitet auf fast magische Weise. Das Zauberwort ist “Auto Layout”. Damit definierst Du Regeln, die die App später sinnvoll befolgt.

Aber – und das ist ein großes “Aber” – Auto Layout stellt selbst zwei Regeln auf, die Du befolgen mußt:

  • Deine Layout-Regeln müssen vollständig sein. Das heisst, Du kannst nicht nur eine X-Position vereinbaren, ohne auch Y zu bestimmen. Wie im Mathematikunterricht: “X” steht für die horizontale Position (ausgehend vom linken Rand) und “Y” die vertikale Position (ausgehend vom oberen Rand).
  • Deine Layout-Regeln dürfen sich auch nicht widersprechen. Wenn Du z.B. bestimmt hast, daß ein View 1000 Punkte breit sein soll und zum rechten Rand 10 Punkte Abstand, wie auch zum linken haben soll, geht das auf einem kleinen iPhone rein rechnerisch gar nicht. Auto Layout würde versuchen dieses Dilemma durch Regelbrüche zu lösen, bis es irgendwie funktioniert – aber bestimmt nicht sinnvoll.

Solche Auto Layout Regeln (auch constraints genannt) können wir nur im Interface Builder vereinbaren und der wird Dich auch vor Widersprüchen warnen und Dir Korrekturvorschläge machen – die sind oft, aber nicht immer sinnvoll – letztlich entscheidest Du!

Wir erstellen nun 4 solche Contraints: für jeden Rand eine Regel (oben, unten, links, rechts). Es gibt mehrere Wege die anzulegen, aber der allereinfachste erscheint mir, den Image View auszuwählen und im Menü Editor > Resolve Auto Layout Issues > Reset to Suggested Contraints zu klicken.

Hast Du bemerkt, daß es diese Option zweimal im Menü gibt – mit einem kleinen Unterschied. In unserem Fall können wir beide verwenden. Wenn DU lieber Tastaurkürzel verwendest: das selbe erreichen wir über Shift+Alt+Cmd+=.

Auf den ersten Blick scheint sich nichts verändert zu haben. Achte bitte auf subtile Unterschiede:

  • Um den UIImageView auf der Detailansicht ist eine dünne blaue Linie. Damit zeigt uns der IB an, daß hier eine widerspruchsfreie Auto Layout Regel angewandt wird.
  • In der Dokumentübersicht erschien ein neuer Eintrag mit der Überschrift “Constraints” unter dem Image View. Darunter verbergen sich alle 4 Regeln, die Du anklicken sichtbar machst.

Nach dem Anlegen der Regeln gibt es nur noch eine Sache im Interface Builder zu erledigen. Wir verbinden diesen Image View mit unserem Code. Es reicht nicht, einen View im IB zu erzeugen. Um ihn im Code ansprechen zu können, brauchen wir dort eine Property, der wir diese IB-Elemente zuweisen.

Diese Property ist also wie das Array pictures von vorhin, aber es bedarf einer für uns neuen Swift-Syntax sie anzulegen. Und die Art und Weise, wie das Folgende im Interface Builder gelöst wird, wird Leuten mit Erfahrung an anderen IDEs (Integrated Development Environments) sehr bizarr vorkommen.

Aber lass uns anfangen und ich erkläre es währenddessen. Xcode hat eine Bildschirmanordnung, die “Assistant Editor” genannt wird. Dabei teilt es sich: Oben siehtst Du die grafische Darstellen wie bisher, unten erscheint ein Zusatz-Editor für mehrere Zwecke. In unserem Fall erscheint dort der Source-Code unserer Klasse der Detailansicht (detail view controller).

Xcode wählt das unten Anzuzeigende anhand des jeweils oben Ausgewählten aus. Stelle also sicher, daß der DetailViewController oben angewählt ist und wähle im Menü View > Assistant Editor > Show Assistant Editor. Oder drücke Alt+Cmd+Return.

Ich persönlich finde ja die Oben/Unten-Darstellung gut, aber falls Du magst, kannst Du über View > Assistant Editor > Assistant Editors On Right auch beides nebeneinander darstellen lassen. Xcode weis, daß er unten den Source Code in DetailViewController.swift anzeigen soll, weil wir den View vorhin der Klasse “DetailViewController” zugeordnet hatten.

Nun nutzen wir eine Besonderheit des Interface Builders – befolge bitte genau meine Beschreibung:

  1. Stelle sicher, daß der Image View ausgewählt ist.
  2. Drücke die Taste control/Ctrl und halte sie gedrückt.
  3. Drücke die Maustaste über dem Image View und halte auch sie weiterhin gedrückt.
  4. Mit Beidem gedrückt, schiebe die Maus hinunter in den Assistant Editor.
  5. Während der Bewegung spannt IB eine blaue Linie zwischem dem View oben und einer wechselnden Stelle im Sourece Code unten. Schiede diese Stelle in die Lücke zwischen class DetailViewController: UIViewController { und override func viewDidLoad() {.
  6. Dort sollte eine horizontale blaue Linie erscheinen mit einer Hinweisblase “Insert Outlet Or Outlet Connection”. Dann lasse Maustaste und Ctrl-Taste los – egal welche zuerst.

Wenn das alles so geklappt hat, erscheint ein Dialog mit fünf Feldern: Connection, Object, Name, Type, und Storage.

Wenn Du vom IB per Ctrl-Drag in Deinen Code verlinkst, erscheint ein Dialog um ein sog. *outlet* anzulegen.

Folgende Standardwerte sollten hier erscheinen: “Outlet” bei Connection, “Detail View Controller” bei Object, kein Name, “UIImageView” bei Type und “Strong” bei Storage. Falls dort doch “Weak” vorgeschlagen wird, ändere es auf “Strong”. Xcode merkt sich das.

Alle o.g. Standards sind in Ordnung, nur in den Namen schreibe bitte “imageView” und beende mit dem Connect Knopf. Xcode ergänzt nun Deinen Code um eine Zeile und es erscheint:

class DetailViewController: UIViewController {
    @IBOutlet var imageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()

Und links neben der neuen Zeile erscheint neben den Zeilennummern ein grauer, umgekreister Punkt. Damit zeigt uns Xcode an, daß es eine Verbindung zum Storyboard gibt. Wenn Du mit der Maus darüber fährst, wird kurz der Image View im Storyboard hervorgehoben.

In der Zeile steckt Neues, das ich nun erklären will:

  • @IBOutlet: Dieses Attribut teilt Xcode mit, daß im IB eine Verbindung zum Storyboard hergestellt werden soll. Dasmit wird es zum “outlet”.
  • var: Macht das folgende zu einer änderbaren/variablen Property.
  • imageView: Diesen Namen haben wir vergeben für unseren UIImageView. Beachte bitte die Verwendung von Klein- und Großbuchstaben. Diese Schreibweise wird auch CamelCase genannt, wegen dem Auf/Nieder wie bei Kamel-Höckern. Die Worte werden zusammengeschrieben, aber jedes mit einem Großbuchstaben eingeleitet. Für Variablen und Konstanten in Swift gilt die Regel, daß der erste Buchstabe klein geschrieben wird. Beispiel: meineTolleVariable. Typen und Klassennamen fangen gross an. Beispiel: UIImageView.
  • UIImageView!: Damit deklarieren wir den Type dieses Properties als UIImageView und am Ende sehen wir wieder das Symbol ! für ein explizit entpacktes Optional. Das heisst, es handelt sich zwar um eine Optional nud kann einen Wert annehmen oder auch nicht, aber wird sind uns extrem sicher, daß es gesetzt sein wird, wenn wir es verwenden – sonst droht Absturz!

Wenn Du Dich mit diesen explizit/implizit entpackten Optionals schwer tust (Keine Sorge – ja, sie sind kompliziert!) hilft Dir vielleicht diese Erklärung:

Wenn der DetailViewController erzeugt wird, existiert der dazugehörende View noch garnicht, das Optional belegt zwar Speicher, ist aber nicht gesetzt und enthält den Wert nil.

Erst wenn die App grundlegende Arbeiten wie Speicher für alles Bereitstellen gemacht hat, lädt iOS das Storyboard und setzt alle vorher als outlets vorgemerkten Optionals auf die Elemente im Storyboard. Erst danach können wir sie ansprechen.

Also – outlet-Optionals werden mit dem Wert nil angelegt, aber bevor unser Code auf sie zugreift, setzt iOS einen sinnvollen Wert aus dem Storyboard. Daher können wir am Ende das ! statt dem ? verwenden und unser Code verwendet es wie einen non-optional-Typ. Ein Bilderbuchbeispiel für ein implizit entpacktes Optional.

Das schliesst unsere Arbeit im Interface Builder an der Detailansicht ab und wir schliessen unseren Assistent Editor wieder mit View > Standard Editor > Show Standard Editor. Es geht weiter mit Source Code.

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.