Kontrolle über die tvOS Focus Engine

Einführung

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.

Voraussetzungen

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.

1. Focus Engine Überblick

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.

Fokusbewegung

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.

  • Bewegen des Fokus über bestimmte Ansichten, wenn der Benutzer beispielsweise schnell auf der Touch-Oberfläche der Apple TV-Fernbedienung wischt
  • Laufende Animationen mit Geschwindigkeiten basierend auf der Geschwindigkeit der Fokusänderung
  • Das Abspielen von Navigationsgeräuschen, wenn sich der Fokus ändert
  • Animieren der Verschiebungsansicht automatisch, wenn der Fokus zu einer aktuellen Ansicht außerhalb des Bildschirms verschoben werden muss

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, UIViewControllerUIView, 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.

Anfangsfokus

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.

Fokus aktualisieren

Eine Fokusaktualisierung findet statt, wenn eines von drei Ereignissen stattfindet:

  • der Benutzer verursacht eine Fokusbewegung
  • Die App fordert ausdrücklich ein Fokus-Update an
  • das System löst aus und automatische Aktualisierung

Bei jeder Aktualisierung folgen die folgenden Ereignisse:

  • Die jetzige UIScreen Objekt ist fokussierte Ansicht Die Eigenschaft wird in die Ansicht geändert, in die der Fokus verschoben wird.
  • Die Fokusmaschine ruft die 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.
  • Alle koordinierten Animationen, sowohl System- als auch benutzerdefinierte Animationen, werden gleichzeitig ausgeführt.
  • Wenn die Ansicht, in die sich der Fokus bewegt, derzeit nicht auf dem Bildschirm angezeigt wird, und in einer Bildlaufansicht, scrollt das System die Ansicht auf dem Bildschirm, so dass die Ansicht für den Benutzer sichtbar wird.

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.

2. Steuern der Focus Engine

Fokus-Anleitungen

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.

Koordinierte Animationen

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 wird
  • nextFocusedView: Verweist auf die Ansicht, in die der Fokus verschoben wird
  • focusHeading: ein UIFocusHeading Aufzählungswert, der die Richtung angibt, in die sich der Fokus bewegt

Mit 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.

Begrenzung der Fokus-Engine

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.

Fazit

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.