Blog

Parallaxes Scrollen von Bildern mit Storyboards

Lammert Westerhoff

Aktualisiert Oktober 22, 2025
10 Minuten

Das parallaxe Scrollen von Bildern ist ein beliebtes Konzept, das heutzutage von vielen Apps übernommen wird. Es sind die kleinen Details wie dieses, die eine App wirklich großartig machen können. Der parallaxe Bildlauf vermittelt Ihnen die Illusion von Tiefe, indem er Objekte im Hintergrund langsamer scrollen lässt als Objekte im Vordergrund. Es wurde in der Vergangenheit von vielen 2D-Spielen verwendet, um ihnen einen 3D-Effekt zu verleihen. Echtes Parallaxen-Scrolling kann ziemlich komplex werden, aber es ist nicht sehr schwer, selbst einen einfachen Parallaxen-Scrolling-Effekt auf iOS zu erzeugen. In diesem Beitrag zeigen wir Ihnen, wie Sie ihn mithilfe von Storyboards zu einer Tabellenansicht hinzufügen können.

HINWEIS: Den gesamten in diesem Beitrag verwendeten Quellcode finden Sie auf GitHub ParallaxImageScrolling. Die Idee ist, eine UITableView mit einer Bildüberschrift zu erstellen, die einen Parallax-Scrolling-Effekt hat. Wenn wir in der Tabellenansicht nach unten scrollen (d.h. nach oben wischen), sollte das Bild mit der halben Geschwindigkeit der Tabelle scrollen. Und wenn wir nach oben scrollen (d.h. nach unten wischen), sollte das Bild größer werden, so dass es den Eindruck macht, dass es sich beim Scrollen ausdehnt. Letzteres ist kein wirklicher Parallaxen-Scroll-Effekt, wird aber häufig in Kombination mit ihm verwendet. Die folgende Animation zeigt diese Effekte:

imageedit_9_7419205352

Was aber, wenn wir einen "Nach-unten-ziehen-um-zu-aktualisieren"-Effekt wünschen und ein UIRefreshControl hinzufügen müssen? Nun, dann lassen wir den Stretch-Effekt einfach weg, wenn wir nach oben scrollen:

imageedit_7_3493339154

Und wie Sie vielleicht erwarten, ist die Variante mit Pull to Refresh tatsächlich viel einfacher zu bewerkstelligen als die Variante ohne.

Parallax Scrolling Bibliotheken

Sie finden zwar mehrere Objective-C- oder Swift-Bibliotheken, die einen ähnlichen Parallaxen-Scroller wie die hier vorgestellten bieten, aber Sie werden feststellen, dass es gar nicht so schwer ist, diese selbst zu erstellen. Wenn Sie es selbst machen, haben Sie den Vorteil, dass Sie es genau so anpassen können, wie Sie es wollen, und natürlich wird es Ihre Erfahrung bereichern. Außerdem benötigen Sie weniger Code als bei der Integration in eine solche Bibliothek. Wenn Sie jedoch genau das benötigen, was eine solche Bibliothek bietet, dann ist die Verwendung einer solchen Bibliothek vielleicht besser für Sie.

Die Grundlagen

HINWEIS: Den gesamten Code dieses Abschnitts finden Sie im Zweig no-parallax-scrolling. Beginnen wir mit einem einfachen Beispiel, das noch keine Parallax-Scrolling-Effekte hat.

imageedit_5_3840368192

Hier haben wir einen standardmäßigen UITableViewController mit einer Zelle, die oben unser Bild enthält, und einer weiteren Zelle darunter mit etwas Text. Hier ist der Code: [code language="obj-c"] class ImageTableViewController: UITableViewController { override func numberOfSectionsInTableView(tableView: UITableView) -> Int { Rückkehr 2 } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { Rückgabe 1 } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { var cellIdentifier = "" switch indexPath.section { Fall 0: cellIdentifier = "ImageCell" case 1: cellIdentifier = "TextCell" default: () } let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! UITableViewCell Zelle zurückgeben } override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { switch indexPath.section { Fall 0: return UITableViewAutomaticDimension Standard: () Rückgabe 50 } } override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { switch indexPath.section { Fall 0: Rückkehr 200 Standard: () Rückgabe 50 } } } [/code] Das einzig Bemerkenswerte hier ist, dass wir UITableViewAutomaticDimension für automatische Zellenhöhen verwenden, die durch Einschränkungen in der Zelle bestimmt werden: Wir haben eine UIImageView mit Einschränkungen, um die volle Breite und Höhe der Zelle und ein festes Seitenverhältnis von 2:1 zu verwenden. Aufgrund dieses Seitenverhältnisses ist die Höhe des Bildes (und damit der Zelle) immer halb so groß wie die Breite. Im Querformat sieht das so aus: iOS Simulator Bildschirmfoto 20 Jul 2015 17.27.38 Wir werden später sehen, warum das wichtig ist.

Parallaxes Scrollen mit Pull to Refresh

HINWEIS: Den gesamten Code dieses Abschnitts finden Sie in der pull-to-refresh-Verzweigung. Wie bereits erwähnt, ist es am einfachsten, den Parallaxen-Scroll-Effekt zu erstellen, wenn er sich nicht dehnen muss. Das wollen Sie in der Regel nur, wenn Sie einen Pull-to-Refresh-Effekt haben. Das Hinzufügen des UIRefreshControl erfolgt auf die übliche Weise, so dass ich darauf nicht näher eingehen werde. Container-Ansicht Der Rest ist ebenfalls recht einfach. Mit den Grundlagen von unten als Ausgangspunkt müssen wir zunächst eine UIView um unsere UIImageView hinzufügen, die als Container fungiert. Da unser Bild beim Scrollen seine Position ändert, können wir es nicht mehr verwenden, um die Höhe der Zelle zu berechnen. Die Container-Ansicht hat genau die gleichen Einschränkungen wie unsere Bildansicht: Sie nutzt die volle Breite und Höhe der Zelle und hat ein Seitenverhältnis von 2:1. Aktivieren Sie außerdem die Option Unteransichten ausschneiden in der Container-Ansicht, um sicherzustellen, dass die Bildansicht durch sie beschnitten wird. Y-Beschränkung ausrichten Die Bildansicht, die sich jetzt innerhalb der Containeransicht befindet, behält ihr Seitenverhältnis bei und nutzt die volle Breite der Containeransicht. Für die y-Position fügen wir eine Beschränkung Align Center Y hinzu, um das Bild innerhalb des Containers vertikal zu zentrieren. Das Ganze sieht in etwa so aus: Bildschirmfoto 2015-07-20 um 17.46.25 Parallaxes Scrollen mit Constraint Wenn wir diesen Code jetzt ausführen, verhält er sich noch genauso wie vorher. Wir müssen nur dafür sorgen, dass die Bildansicht beim Scrollen nach unten mit der halben Geschwindigkeit der Tabellenansicht scrollt. Das können wir erreichen, indem wir die Konstante der soeben erstellten Einschränkung Align Center Y ändern. Zunächst müssen wir sie mit einem Ausgang einer benutzerdefinierten UITableViewCell-Unterklasse verbinden: [code language="obj-c"] class ImageCell: UITableViewCell { @IBOutlet weak var imageCenterYConstraint: NSLayoutConstraint! } [/code] Wenn die Tabellenansicht nach unten scrollt, müssen wir die Y-Position des Bildes um die Hälfte des gescrollten Betrags verringern. Dazu können wir scrollViewDidScroll und den Inhaltsoffset der Tabellenansicht verwenden. Da sich unser UITableViewController bereits an das UIScrollViewDelegate hält, genügt es, diese Methode zu überschreiben: [code language="obj-c"] override func scrollViewDidScroll(scrollView: UIScrollView) { imageCenterYConstraint?.constant = min(0, -scrollView.contentOffset.y / 2.0) // nur beim Scrollen nach unten, so dass der Wert nie höher als 0 sein darf } [/code] Wir haben noch ein kleines Problem. Das imageCenterYConstraint ist mit der ImageCell verbunden, die wir erstellt haben, und die Methode scrollViewDidScroll befindet sich im View Controller. Es bleibt also nichts anderes übrig, als ein imageCenterYConstraint im View-Controller zu erstellen und es zuzuweisen, wenn die Zelle erstellt wird: [code language="obj-c"] weak var imageCenterYConstraint: NSLayoutConstraint? override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { var cellIdentifier = "" switch indexPath.section { case 0: cellIdentifier = "ImageCell" case 1: cellIdentifier = "TextCell" default: () } // der neue Teil des Codes: let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! UITableViewCell if let imageCell = cell as? ImageCell { imageCenterYConstraint = imageCell.imageCenterYConstraint } return cell } [/code] Das ist alles, was wir für unsere erste Variante des parallaxen Bildlaufs tun müssen. Lassen Sie uns mit etwas Komplizierterem weitermachen.

Parallaxes Scrollen mit Pull to Refresh

HINWEIS: Den gesamten Code dieses Abschnitts finden Sie im Zweig no-pull-to-refresh. Wenn wir von den Grundlagen ausgehen, müssen wir wieder eine Container-Ansicht hinzufügen, wie wir es im Abschnitt Container-Ansicht im vorherigen Abschnitt getan haben. Die Bildansicht benötigt jedoch einige andere Beschränkungen. Fügen Sie der Bildansicht die folgenden Beschränkungen hinzu:

  • Behalten Sie das Seitenverhältnis 2:1 bei.
  • Fügen Sie der Superview (unserer Container-Ansicht) einen Leading Space und Trailing Space von 0 hinzu und setzen Sie die Priorität auf 900. Beim Strecken des Bildes werden diese Einschränkungen aufgehoben, da das Bild breiter wird als die Container-Ansicht. Wir benötigen sie aber dennoch, um die bevorzugte Breite zu bestimmen.
  • Zentrum X an der Aufsicht ausrichten. Wir brauchen diese Option, um das Bild in der Mitte zu halten, wenn wir die Beschränkungen für den vorderen und hinteren Abstand aufheben.
  • Fügen Sie der Superview einen Bottom Space und einen Top Space von 0 hinzu. Erstellen Sie zwei Ausgänge für die Zellklasse ImageCell, so wie wir es im vorigen Abschnitt für die mittlere Y-Beschränkung getan haben. Wir nennen sie bottomSpaceConstraint und topSpaceConstraint. Weisen Sie auch diese von der Zelle aus dem View Controller zu, wie wir es zuvor getan haben, damit wir in unserer scrollViewDidScroll-Methode darauf zugreifen können.

Das Ergebnis: Bildschirmfoto 2015-07-20 um 21.30.52 Wir haben jetzt alle Einschränkungen, die wir für die Effekte zum Hoch- und Runterscrollen benötigen. Nach unten scrollen Wenn wir nach unten scrollen (nach oben streichen), wollen wir den gleichen Effekt wie im vorherigen Abschnitt. Anstatt eine 'Align Center Y'-Beschränkung zu haben, die wir ändern können, müssen wir jetzt Folgendes tun:

  • Stellen Sie den unteren Abstand auf minus die Hälfte des Inhaltsversatzes ein, so dass er unter die Containeransicht fällt.
  • Legen Sie den oberen Abstand auf plus die Hälfte des Inhaltsversatzes fest, so dass er unterhalb des oberen Randes der Containeransicht liegt.

Mit diesen beiden Berechnungen verzögern wir die Bildlaufgeschwindigkeit der Bildansicht effektiv um die Hälfte der Bildlaufgeschwindigkeit der Tabellenansicht. [code language="obj-c"] bottomSpaceConstraint?.constant = -scrollView.contentOffset.y / 2 topSpaceConstraint?.constant = scrollView.contentOffset.y / 2 [/code] Nach oben scrollen Wenn die Tabellenansicht nach oben scrollt (nach unten wischen), wird die Containeransicht nach unten verschoben. Was wir hier wollen, ist, dass die Bildansicht am oberen Rand des Bildschirms verbleibt und nicht mit nach unten wandert. Dazu müssen wir die Konstante des topSpaceConstraint auf den Offset des Inhalts setzen. Das bedeutet, dass die Höhe des Bildes zunimmt. Aufgrund unseres Seitenverhältnisses von 2:1 wird auch die Breite des Bildes größer. Aus diesem Grund mussten wir die Priorität des Leading- und Trailing-Constraints herabsetzen, da das Bild nicht mehr in den Container passt und diese Constraints verletzt. [code language="obj-c"] topSpaceConstraint?.constant = scrollView.contentOffset.y [/code] Jetzt haben wir noch ein Problem. Wenn das Bild oben bleibt, während die Container-Ansicht nach unten geht, bedeutet dies, dass das Bild außerhalb der Container-Ansicht fällt. Und da wir Clip Subviews für das Scrollen nach unten aktivieren mussten, erhalten wir jetzt etwas wie dieses: iOS Simulator Bildschirmfoto 20 Jul 2015 21.45.44 Wir können den oberen Teil des Bildes nicht sehen, da er sich außerhalb der Containeransicht befindet. Was wir also brauchen, ist ein Ausschnitt beim Scrollen nach unten und kein Ausschnitt beim Scrollen nach oben. Das geht nur im Code, also müssen wir die Container-Ansicht mit einem Ausgang verbinden, so wie wir es mit den Beschränkungen gemacht haben. Dann wird der endgültige Code in scrollViewDidScroll zu: [code language="obj-c"] func scrollViewDidScroll(scrollView: UIScrollView) { if scrollView.contentOffset.y >= 0 { // Abwärts scrollen containerView.clipsToBounds = true bottomSpaceConstraint?.constant = -scrollView.contentOffset.y / 2 topSpaceConstraint?.constant = scrollView.contentOffset.y / 2 } else { // nach oben scrollen topSpaceConstraint?.constant = scrollView.contentOffset.y containerView.clipsToBounds = false } } [/code]

Fazit

Da haben Sie es also. Zwei Variationen des Parallaxen-Scrollings ohne allzu viel Aufwand. Wie bereits erwähnt, verwenden Sie eine spezielle Bibliothek, wenn Sie müssen, aber haben Sie keine Angst, dass es zu kompliziert ist, es selbst zu machen.

Zusätzliche Hinweise

Wenn Sie den Quellcode auf GitHub gesehen haben, sind Ihnen vielleicht ein paar zusätzliche Dinge aufgefallen. Ich wollte sie nicht im Hauptteil dieses Beitrags erwähnen, um Ablenkungen zu vermeiden, aber es ist wichtig, sie trotzdem zu erwähnen.

  • Die Beschränkungen für das Seitenverhältnis müssen eine niedrigere Priorität als 1000 haben. Setzen Sie sie auf 999 oder 950 oder so (stellen Sie sicher, dass sie höher sind als die Einschränkungen für den führenden und den nachlaufenden Abstand, die wir im letzten Abschnitt auf 900 gesetzt haben). Der Grund dafür ist ein Problem im Zusammenhang mit Zellen mit dynamischer Höhe (unter Verwendung von UITableViewAutomaticDimension) und Rotation. Wenn der Benutzer das Gerät dreht, erhält die Zelle ihre neue Breite, während sie noch die vorherige Höhe hat. Die Berechnung der neuen Höhe wird zu Beginn der Rotationsanimation noch nicht durchgeführt. Zu diesem Zeitpunkt kann das Seitenverhältnis 2:1 noch nicht existieren, weshalb wir es auch nicht auf 1000 (erforderlich) setzen können. Unmittelbar nach der Berechnung der neuen Höhe wird die Einschränkung des Seitenverhältnisses wieder aktiv. Es scheint, dass der Zustand, in dem die Seitenverhältnisbeschränkung nicht existiert, nicht einmal sichtbar ist, also machen Sie sich keine Sorgen, dass Ihre Zelle seltsam aussieht. Wenn Sie den Wert auf 1000 belassen, scheint nur eine Fehlermeldung über die Beschränkung zu erscheinen, nach der es wie erwartet weitergeht.
  • Anstatt die Ausgänge der ImageCell neuen Variablen im View Controller zuzuweisen, können Sie auch einen scrollViewDidScroll in der Zelle erstellen, der dann vom scrollViewDidScroll Ihres View Controllers aufgerufen wird. Sie können die Zelle mit cellForRowAtIndexPath abrufen. Sehen Sie sich den Code auf GitHub an, um dies zu sehen.

Verfasst von

Lammert Westerhoff

Contact

Let’s discuss how we can support your journey.