Unter iOS interagieren Benutzer normalerweise mit Ihren Apps über den Touchscreen des Geräts. Bei tvOS wird die Benutzerinteraktion jedoch durch Verschieben des Stroms behandelt Fokus zwischen Ansichten auf dem Bildschirm.
Glücklicherweise bewältigen die tvOS-Implementierungen der UIKit-APIs den Fokuswechsel zwischen Ansichten automatisch. Während dieses eingebaute System für bestimmte Ansichtslayouts und / oder Zwecke sehr gut funktioniert, kann es erforderlich sein, die Fokussierungsmaschine manchmal manuell zu steuern.
In diesem Tutorial werfen wir einen detaillierten Einblick in die tvOS-Fokus-Engine. Sie lernen, wie es funktioniert und wie Sie es steuern können, wie Sie möchten.
Für dieses Lernprogramm müssen Sie Xcode 7.3 oder höher mit dem neuesten tvOS 9.2 SDK ausführen. Wenn Sie mitverfolgen möchten, müssen Sie auch das Starterprojekt von GitHub herunterladen.
Der Zweck der Fokus-Engine von tvOS ist es, Entwicklern zu helfen, sich auf den einzigartigen Inhalt ihrer eigenen App zu konzentrieren, anstatt grundlegende Navigationsverhalten neu zu implementieren. Das heißt, während viele Benutzer die Siri-Fernbedienung von Apple TV verwenden, unterstützt die Fokus-Engine automatisch alle aktuellen und zukünftigen Apple TV-Eingabegeräte.
Dies bedeutet, dass Sie sich als Entwickler keine Gedanken darüber machen müssen, wie ein Benutzer mit Ihrer App interagiert. Ein weiteres wichtiges Ziel der Fokus-Engine ist es, eine konsistente Benutzererfahrung zwischen Anwendungen zu schaffen. Aus diesem Grund gibt es keine API, mit der eine Anwendung den Fokus verschieben kann.
Wenn der Benutzer mit der Fernbedienung des Apple TV-Geräts interagiert, indem er in einer bestimmten Richtung auf die Glas-Touch-Oberfläche wischt, sucht die Fokus-Engine nach einer möglichen fokussierbaren Ansicht in dieser Richtung und verschiebt, falls gefunden, den Fokus auf diese Ansicht. Wenn keine fokussierbare Ansicht gefunden wird, bleibt der Fokus dort, wo er sich gerade befindet.
Neben dem Verschieben des Fokus in eine bestimmte Richtung behandelt die Fokus-Engine auch einige andere, fortgeschrittenere Verhaltensweisen, z.
Bei der Bestimmung, wohin sich der Fokus in einer App bewegen soll, macht die Focus Engine ein internes Bild der aktuellen Benutzeroberfläche Ihrer App und hebt alle sichtbaren Elemente hervor, die fokussierbar sind. Dies bedeutet, dass ausgeblendete Ansichten, einschließlich Ansichten mit einem Alphawert von 0, nicht fokussiert werden können. Dies bedeutet auch, dass für jede Ansicht, die von einer anderen Ansicht ausgeblendet wird, nur der sichtbare Teil von der Fokus-Engine berücksichtigt wird.
Wenn das Fokusmodul eine Ansicht findet, zu der es den Fokus verschieben kann, benachrichtigt es die Objekte, die dem entsprechen UIFocusEnvironment
Protokoll, das an der Änderung beteiligt ist. Die UIKit-Klassen, die dem entsprechen UIFocusEnvironment
Protokoll sind UIWindow
, UIViewController
, UIView
, und UIPresentationController
. Die Fokusmaschine ruft die shouldUpdateFocusInContext (_ :)
Methode aller Fokusumgebungsobjekte, die entweder die aktuell fokussierte Ansicht oder die Ansicht enthalten, in die der Fokus verschoben wird. Wenn eine dieser Methodenaufrufe zurückgegeben wird falsch
, Der Fokus wird nicht geändert.
Das UIFocusEnvironment
Protokoll repräsentiert ein Objekt, das als a bezeichnet wird fokus umwelt. Das Protokoll definiert a preferredFocusView
Eine Eigenschaft, die angibt, wohin sich der Fokus bewegen soll, wenn die aktuelle Umgebung selbst scharfgestellt wird.
Zum Beispiel a UIViewController
Objektvorgabe preferredFocusView
ist seine Wurzelansicht. Wie jeder UIView
object kann auch eine eigene bevorzugte Fokusansicht angeben, a bevorzugte Fokuskette kann erstellt werden. Die tvOS-Fokus-Engine folgt dieser Kette, bis ein bestimmtes Objekt zurückgegeben wird selbst
oder Null
von seinem preferredFocusView
Eigentum. Mithilfe dieser Eigenschaften können Sie den Fokus über die Benutzeroberfläche umleiten und angeben, welche Ansicht zuerst angezeigt werden soll, wenn ein View-Controller auf dem Bildschirm angezeigt wird.
Es ist wichtig zu beachten, dass, wenn Sie keine der Einstellungen ändern preferredFocusView
Wenn Sie die Eigenschaften Ihrer Ansichten und Ansichts-Controller festlegen, fokussiert das Standardmodul standardmäßig die Ansicht, die der linken oberen Ecke des Bildschirms am nächsten liegt.
Eine Fokusaktualisierung findet statt, wenn eines von drei Ereignissen stattfindet:
Bei jeder Aktualisierung folgen die folgenden Ereignisse:
UIScreen
Objekt ist fokussierte Ansicht
Die Eigenschaft wird in die Ansicht geändert, in die der Fokus verschoben wird.didUpdateFocusInContext (_: withAnimationCoordinator :)
von jedem Fokusumgebungsobjekt, das an der Fokusaktualisierung beteiligt ist. Dies sind die gleichen Objekte, die die Fokus-Engine durch Aufruf der Objekte überprüft shouldUpdateFocusInContext (_ :)
Methode vor dem Aktualisieren des Fokus. An dieser Stelle können Sie benutzerdefinierte Animationen hinzufügen, die zusammen mit den fokusbezogenen Animationen des Systems ausgeführt werden.Um den Fokus in der Benutzeroberfläche manuell zu aktualisieren, können Sie das aufrufen setNeedsFocusUpdate ()
Methode eines Fokusumgebungsobjekts. Dies setzt den Fokus zurück und verschiebt ihn zurück in die Umgebung preferredFocusView
.
Das System kann auch in mehreren Situationen eine automatische Fokusaktualisierung auslösen, z. B. wenn eine fokussierte Ansicht aus der Ansichtshierarchie entfernt wird, eine Tabellen- oder Sammlungsansicht ihre Daten neu lädt oder wenn ein neuer Ansichtscontroller angezeigt oder verworfen wird.
Während die tvOS-Fokus-Engine recht komplex ist und viele bewegliche Teile enthält, ist die Verwendung dieses Systems durch die UIKit-APIs sehr einfach und macht es so, wie Sie es wünschen.
Um die Fokus-Engine zu erweitern, werden wir ein Wrap-around-Verhalten implementieren. Unsere aktuelle App verfügt über ein Raster mit sechs Schaltflächen, wie im Screenshot unten gezeigt.
Was wir tun werden, ist, dem Benutzer zu ermöglichen, den Fokus von den Knöpfen 3 und 6 nach rechts zu verschieben und den Fokus wieder auf die Knöpfe 1 und 4 zu verschieben. Da die Fokus-Engine alle unsichtbaren Ansichten ignoriert, kann dies nicht durch Einfügen eines Unsichtbaren erfolgen UIView
(einschließlich einer Ansicht mit einer Breite und Höhe von 0) und deren Änderung preferredFocusedView
Eigentum.
Stattdessen können wir dies mit der UIFocusGuide
Klasse. Diese Klasse ist eine Unterklasse von UILayoutGuide
und stellt einen rechteckigen fokussierbaren Bereich auf dem Bildschirm dar, während er vollständig unsichtbar ist und nicht mit der Ansichtshierarchie interagiert. Über allem UILayoutGuide
Eigenschaften und Methoden, die UIFocusGuide
Klasse fügt die folgenden Eigenschaften hinzu:
preferredFocusedView
: Diese Eigenschaft funktioniert wie zuvor beschrieben. Sie können sich dies als die Ansicht vorstellen, zu der der Fokus-Leitfaden weiterleiten soll.aktiviert
: Mit dieser Eigenschaft können Sie die Fokushilfe aktivieren oder deaktivieren.Öffnen Sie in Ihrem Projekt ViewController.swift und implementieren die viewDidAppear (_ :)
Methode der ViewController
Klasse wie unten gezeigt:
func viewDidAppear überschreiben (animiert: Bool) super.viewDidAppear (animiert) let rightButtonIds = [3, 6] für buttonId in rightButtonIds wenn let button = buttonWithTag (buttonId) let focusGuide = UIFocusGuide () view.addLayoutGuide ( .widthAnchor.constraintEqualToAnchor (button.widthAnchor) .active = true focusGuide.heightAnchor.constraintEqualToAnchor (button.heightAnchor) .active = true focusGuide.leadingAnchor.constraintEqualToAnchor (button.trailingAnchor, Konstante: 60.0) (button.centerYAnchor) .active = true focusGuide.preferredFocusedView = buttonWithTag (buttonId-2) Lassen Sie leftButtonIds = [1, 4] für buttonId in leftButtonIds wenn let button = buttonWithTag (buttonId) anzeigen lassen) .addLayoutGuide (focusGuide) focusGuide.widthAnchor.constraintEqualToAnchor (button.widthAnchor) .active = true focusGuide.heightAnchor.constraintEqualToAnchor (button.heightAnchor) .active = true focusGuide.tr ailingAnchor.constraintEqualToAnchor (button.leadingAnchor, Konstante: -60.0) .active = true focusGuide.centerYAnchor.constraintEqualToAnchor (button.centerYAnchor) .active = true focusGuide.preferredfocusedView = buttonWithTag (buttonId + 2)
Im viewDidAppear (_ :)
, Wir erstellen Fokushilfslinien rechts von den Tasten 3 und 6 und links von Tasten 1und 4. Da diese Fokushilfslinien einen fokussierbaren Bereich in der Benutzeroberfläche darstellen, müssen sie eine festgelegte Höhe und Breite haben. Mit diesem Code werden die Regionen so groß wie die anderen Schaltflächen, sodass sich die impulsbasierte Logik der Fokus-Engine mit den sichtbaren Schaltflächen konsistent anfühlt.
Um zu zeigen, wie koordinierte Animationen funktionieren, aktualisieren wir die Alpha
Eigenschaft der Schaltflächen, wenn sich der Fokus ändert. Im ViewController.swift, implementiere das didUpdateFocusInContext (_: withAnimationCoordinator :)
Methode in der ViewController
Klasse:
func didUpdateFocusInContext überschreiben (Kontext: UIFocusUpdateContext, withAnimationCoordinator Coordinator: UIFocusAnimationCoordinator) super.didUpdateFocusInContext (Context, withAnimationCoordinator: Coordinator), wenn fokussiertesButton = context.previouslyFocusedView as? UIButton wobei buttons.contains (fokussiertesButton) Coordinator.addCoordinatedAnimations (fokussiertesButton.alpha = 0,5, Abschluss: // Ausführen der abgeschlossenen Animation)
Das Kontext
Parameter von didUpdateFocusInContext (_: withAnimationCoordinator :)
ist ein UIFocusUpdateContext
Objekt mit den folgenden Eigenschaften:
beforeFocusedView
: Verweist auf die Ansicht, aus der der Fokus verschoben wirdnextFocusedView
: Verweist auf die Ansicht, in die der Fokus verschoben wirdfocusHeading
: ein UIFocusHeading
Aufzählungswert, der die Richtung angibt, in die sich der Fokus bewegtMit der Umsetzung von didUpdateFocusInContext (_: withAnimationCoordinator :)
, Wir fügen eine koordinierte Animation hinzu, um den Alpha-Wert der zuvor fokussierten Schaltfläche auf 0,5 und den der aktuell fokussierten Schaltfläche auf 1,0 zu ändern.
Führen Sie die App im Simulator aus und verschieben Sie den Fokus zwischen den Schaltflächen der Benutzeroberfläche. Sie sehen, dass die aktuell fokussierte Schaltfläche ein Alpha von 1,0 hat, während die zuvor fokussierte Schaltfläche ein Alpha von 0,5 hat.
Die erste Schließung der addCoordinatedAnimations (_: Vollendung :)
Methode funktioniert ähnlich wie eine reguläre UIView
Animation Schließung. Der Unterschied besteht darin, dass er seine Dauer und Zeitfunktion von der Fokusmaschine erbt.
Wenn Sie eine Animation mit einer benutzerdefinierten Dauer ausführen möchten, können Sie eine beliebige hinzufügen UIView
Animation innerhalb dieser Schließung mit der OverrideInheritedDuration
Animationsoption. Der folgende Code ist ein Beispiel für die Implementierung einer benutzerdefinierten Animation, die zur Hälfte der Fokusanimationen ausgeführt wird:
// Benutzerdefinierte zeitgesteuerte Animation ausführen lassen duration = UIView.inheritedAnimationDuration () UIView.animateWithDuration (Dauer / 2.0, Verzögerung: 0.0, Optionen: .OverrideInheritedDuration, Animationen: // Animationen, Abschluss: (abgeschlossen: Bool) in // Vervollständigungsblock)
Mit der UIFocusGuide
Klasse und durch die Verwendung von benutzerdefinierten Animationen können Sie das Standardverhalten der tvOS focus Engine an Ihre Bedürfnisse anpassen.
Wie bereits erwähnt, ruft die Fokus - Engine bei der Entscheidung, ob der Fokus von einer Ansicht in eine andere verschoben werden soll oder nicht, die shouldUpdateFocusInContext (_ :)
Methode für jede Fokusumgebung. Wenn eine dieser Methodenaufrufe zurückgegeben wird falsch
, Der Fokus wird nicht geändert.
In unserer App überschreiben wir diese Methode in der ViewController
Klasse, so dass der Fokus nicht nach unten verschoben werden kann, wenn die aktuell fokussierte Schaltfläche 2 oder 3 ist. Implementieren Sie dies shouldUpdateFocusInContext (_ :)
in dem ViewController
Klasse wie unten gezeigt:
Überschreiben Sie func shouldUpdateFocusInContext (context: UIFocusUpdateContext) -> Bool let fokussierteButton = context.previouslyFocusedView as? UIButton, wenn fokussierte Schaltfläche == buttonWithTag (2) || focusButton == buttonWithTag (3) if context.focusHeading == .Down return false Rückgabe super.shouldUpdateFocusInContext (Kontext)
Im shouldUpdateFocusInContext (_ :)
, Zuerst prüfen wir, ob die zuvor fokussierte Ansicht die Schaltflächen 2 oder 3 ist. Wir prüfen dann die Fokusüberschrift. Wenn die Überschrift gleich ist Nieder
, wir kehren zurück falsch
damit sich der aktuelle Fokus nicht ändert.
Führen Sie Ihre App ein letztes Mal aus. Sie können den Fokus nicht von den Tasten 2 und 3 auf die Tasten 5 und 6 verschieben.
Sie sollten sich nun mit der Fokus-Engine von tvOS wohlfühlen und arbeiten können. Sie wissen jetzt, wie die Fokus-Engine funktioniert und wie Sie sie an Ihre eigenen Apple TV-Anwendungen anpassen können.
Wie immer sollten Sie Ihre Kommentare und Rückmeldungen in den nachstehenden Kommentaren hinterlassen.