På IOS, brukerne normalt interaksjon med appene dine via enhetens berøringsskjerm. På tvOS håndteres imidlertid brukerinteraksjonen ved å flytte strømmen fokus mellom visninger på skjermen.
Heldigvis håndterer tvOS-implementeringene av UIKit API-ene endring av fokus mellom visninger automatisk. Selv om dette innebygde systemet fungerer veldig bra, for bestemte visningslogger og / eller formål, kan det være nødvendig å noen ganger manuelt kontrollere fokusmotor.
I denne opplæringen tar vi en grundig titt på tvOS fokusmotor. Du lærer hvordan det fungerer og hvordan du kontrollerer det, men du vil.
Denne opplæringen krever at du kjører Xcode 7.3 eller høyere med den nyeste TVOS 9.2 SDK. Hvis du vil følge med, må du også laste ned startprosjektet fra GitHub.
Formålet med fokusmotoren til tvOS er å hjelpe utviklere med å konsentrere seg om sin egen apps unike innhold, i stedet for å reimplementere grunnleggende navigeringsoppføringer. Dette betyr at, mens mange brukere vil bruke Apple TVs Siri Remote, støtter fokusmotor automatisk alle nåværende og fremtidige Apple TV-inngangsenheter.
Dette betyr at du som utvikler ikke trenger å bekymre deg for hvordan en bruker samhandler med appen din. Et annet viktig mål med fokusmotor er å skape en konsistent brukeropplevelse mellom applikasjoner. På grunn av dette er det ingen API som lar et program flytte fokuset.
Når brukeren samhandler med fjernkontrollen til Apple TV ved å sveipe på glasset. Berøringsflaten i en bestemt retning, ser fokusmotorene etter en mulig fokuserbar visning i den retningen og, hvis funnet, flytter fokuset til den visningen. Hvis ingen fokuserbar visning er funnet, forblir fokuset der det er for øyeblikket.
I tillegg til å flytte fokuset i en bestemt retning, håndterer fokusmotoren også flere andre, mer avanserte atferd, som for eksempel:
Når du bestemmer hvor fokus skal flyttes til i en app, tar fokusmotoren et internt bilde av appens nåværende grensesnitt og fremhever alle de synlige elementene som kan fokuseres. Dette betyr at eventuelle skjulte visninger, inkludert visninger med en alfa-verdi på 0, ikke kan fokuseres. Dette betyr også at for enhver visning som er skjult av en annen visning, anses kun den synlige delen av fokusmotoren.
Hvis fokusmotoren finner en visning, kan den flytte fokuset til, det underretter objektene som samsvarer med UIFocusEnvironment
protokoll som er involvert i endringen. UIKit klassene som samsvarer med UIFocusEnvironment
protokollen er UIWindow
, UIViewController
, UIView
, og UIPresentationController
. Fokusmotoren kaller shouldUpdateFocusInContext (_ :)
metode for alle fokusmiljøobjekter som inneholder enten den nåværende fokuserte visningen eller visningen fokuset beveger seg til. Hvis noen av disse metodene ringer tilbake falsk
, fokuset er ikke endret.
De UIFocusEnvironment
protokollen representerer et objekt som er kjent som en fokus miljø. Protokollen definerer a preferredFocusView
Egenskap som spesifiserer hvor fokus skal flyttes til hvis det nåværende miljøet fokuserer seg selv.
For eksempel a UIViewController
objektets standard preferredFocusView
er roten sin. Som hver UIView
objekt kan også spesifisere sin egen foretrukne fokusvisning, a foretrukket fokuskjede kan opprettes. TvOS fokusmotor følger denne kjeden til en bestemt gjenstand returnerer heller selv-
eller nil
fra sin preferredFocusView
eiendom. Ved å bruke disse egenskapene kan du omdirigere fokus gjennom brukergrensesnittet og også spesifisere hvilken visning som skal fokuseres først når en visningsstyring vises på skjermen.
Det er viktig å merke seg at hvis du ikke endrer noen av preferredFocusView
egenskapene til visningene dine og visning av kontroller, fokuserer fokuset som standard motoren visningen nærmest øverst til venstre på skjermen.
En fokusoppdatering oppstår når en av tre hendelser finner sted:
Når en oppdatering finner sted, følger følgende hendelser:
UIScreen
objektets focusedView
Eiendommen er endret til utsikten at fokuset beveger seg til.didUpdateFocusInContext (_: withAnimationCoordinator :)
av alle fokusmiljøobjekter involvert i fokusoppdateringen. Dette er det samme settet med objekter som fokusmotoren kontrollerer ved å ringe til hvert objekt shouldUpdateFocusInContext (_ :)
metode før oppdatering av fokus. Det er på dette tidspunktet at du kan legge til egendefinerte animasjoner for å kjøre sammen med de fokusrelaterte animasjonene som systemet gir.For å manuelt oppdatere fokuset i brukergrensesnittet, kan du påkalle setNeedsFocusUpdate ()
metode for hvilken som helst fokusmiljøobjekt. Dette nullstiller fokuset og flytter det tilbake til miljøet preferredFocusView
.
Systemet kan også utløse en automatisk fokusoppdatering i flere situasjoner, inkludert når en fokusert visning fjernes fra visningshierarkiet, oppdateres en tabell eller samlingsvisning dataene sine, eller når en ny visningscontroller blir presentert eller avvist.
Mens tvOS-fokusmotor er ganske kompleks og har mange bevegelige deler, gir UIKit API-ene til deg det svært enkelt å bruke dette systemet og gjør det til å fungere slik du vil.
For å utvide fokusmotor, skal vi implementere en omviklingsadferd. Vår nåværende app har et rutenett på seks knapper som vist på bildet nedenfor.
Det vi skal gjøre er å la brukeren flytte fokuset til høyre, fra knappene 3 og 6, og la fokuset vikle tilbake til henholdsvis knappene 1 og 4. Som fokusmotor ignorerer noen usynlige visninger, kan dette ikke gjøres ved å sette inn en usynlig UIView
(inkludert en visning med bredde og høyde på 0) og endre dens preferredFocusedView
eiendom.
I stedet kan vi oppnå dette ved hjelp av UIFocusGuide
klasse. Denne klassen er en underklasse av UILayoutGuide
og representerer en rektangulær fokusbar region på skjermen mens den er helt usynlig og ikke interagerer med visningshierarkiet. På toppen av alle UILayoutGuide
egenskaper og metoder, UIFocusGuide
Klassen legger til følgende egenskaper:
preferredFocusedView
: Denne egenskapen fungerer som beskrevet tidligere. Du kan tenke på dette som visningen om at du vil at fokusveiledningen skal viderekobles til.aktivert
: Denne egenskapen lar deg aktivere eller deaktivere fokusveiledningen.I prosjektet ditt, åpne ViewController.swift og implementere viewDidAppear (_ :)
metode av ViewController
klassen som vist nedenfor:
overstyr func viewDidAppear (animert: Bool) super.viewDidAppear (animert) la rightButtonIds = [3, 6] for buttonId i rightButtonIds hvis la knappen = knappWithTag (buttonId) la focusGuide = UIFocusGuide () view.addLayoutGuide (focusGuide) focusGuide .widthAnchor.constraintEqualToAnchor (button.widthAnchor) .active = true focusGuide.heightAnchor.constraintEqualToAnchor (button.heightAnchor) .active = true focusGuide.leadingAnchor.constraintEqualToAnchor (button.trailingAnchor, constant: 60.0) .active = true focusGuide.centerYAnchor.constraintEqualToAnchor (button.centerYAnchor) .active = true focusGuide.preferredFocusedView = buttonWithTag (buttonId-2) la leftButtonIds = [1, 4] for buttonId i leftButtonIds hvis la knapp = buttonWithTag (buttonId) la focusGuide = UIFocusGuide .addLayoutGuide (focusGuide) focusGuide.widthAnchor.constraintEqualToAnchor (button.widthAnchor) .active = true focusGuide.heightAnchor.constraintEqualToAnchor (button.heightAnchor) .active = true focusGuide.tr ailingAnchor.constraintEqualToAnchor (button.leadingAnchor, constant: -60.0) .active = true focusGuide.centerYAnchor.constraintEqualToAnchor (button.centerYAnchor) .active = true focusGuide.preferredFocusedView = buttonWithTag (buttonId + 2)
I viewDidAppear (_ :)
, Vi lager fokusguider til høyre for knappene 3 og 6, og til venstre for knappene 1og 4. Da disse fokusguider representerer en fokuserbar region i brukergrensesnittet, må de ha en sett høyde og bredde. Med denne koden, gjør vi regionene i samme størrelse som de andre knappene, slik at den momentumbaserte logikken til fokusmotor føles i samsvar med de synlige knappene.
For å illustrere hvordan samordnede animasjoner fungerer, oppdaterer vi alfa
Egenskapen til knappene når fokuset endres. I ViewController.swift, implementere didUpdateFocusInContext (_: withAnimationCoordinator :)
metode i ViewController
klasse:
overstyr func didUpdateFocusInContext (kontekst: UIFocusUpdateContext, medAnimationCoordinator koordinator: UIFocusAnimationCoordinator) super.didUpdateFocusInContext (kontekst, medAnimationCoordinator: koordinator) hvis la focusedButton = context.previouslyFocusedView som? UIButton hvor buttons.contains (focusedButton) coordinator.addCoordinatedAnimations (focusedButton.alpha = 0.5, ferdigstillelse: // Kjør fullført animasjon)
De kontekst
parameter av didUpdateFocusInContext (_: withAnimationCoordinator :)
er en UIFocusUpdateContext
objekt som har følgende egenskaper:
previouslyFocusedView
: refererer til visningen fokuset beveger seg franextFocusedView
: refererer til visningen fokuset beveger seg påfocusHeading
: a UIFocusHeading
tallverdi som representerer retningen fokuset beveger seg inn iMed implementeringen av didUpdateFocusInContext (_: withAnimationCoordinator :)
, vi legger til en koordinert animasjon for å endre alfaverdien til den tidligere fokuserte knappen til 0,5 og den aktuelle fokuserte knappen til 1.0.
Kjør appen i simulatoren og flytt fokus mellom knappene i brukergrensesnittet. Du kan se at den nåværende fokuserte knappen har en alfa på 1,0 mens den tidligere fokuserte knappen har en alfa på 0,5.
Den første nedleggelsen av addCoordinatedAnimations (_: fullføring :)
Metoden fungerer på samme måte som en vanlig UIView
animasjonstenging. Forskjellen er at den arver sin varighet og timingfunksjon fra fokusmotor.
Hvis du vil kjøre en animasjon med en tilpasset varighet, kan du legge til noen UIView
animasjon innen denne lukkingen med OverrideInheritedDuration
animasjonsalternativ. Følgende kode er et eksempel på hvordan du implementerer en egendefinert animasjon som går i løpet av halvparten av fokusanimasjonene:
// Kjør tilpasset tidsbegrenset animasjon la duration = UIView.inheritedAnimationDuration () UIView.animateWithDuration (varighet / 2,0, forsinkelse: 0.0, alternativer: .OverrideInheritedDuration, animasjoner: // Animasjoner, fullføring: (ferdig: Bool) i // Fullføringsblokk)
Ved å bruke UIFocusGuide
klassen og ved å bruke tilpassede animasjoner, kan du utvide standardoppførelsen til tvOS fokusmotor som passer dine behov.
Som jeg nevnte tidligere, når jeg bestemmer hvorvidt fokuset skal flyttes fra et synspunkt til et annet, ringer fokusmotoren på shouldUpdateFocusInContext (_ :)
metode for hvert fokus miljø involvert. Hvis noen av disse metodene ringer tilbake falsk
, fokuset er ikke endret.
I vår app skal vi overstyre denne metoden i ViewController
klassen slik at fokuset ikke kan flyttes ned hvis den nåværende fokuserte knappen er 2 eller 3. For å gjøre det, implementer shouldUpdateFocusInContext (_ :)
i ViewController
klassen som vist nedenfor:
overstyr func shouldUpdateFocusInContext (kontekst: UIFocusUpdateContext) -> Bool la focusedButton = context.previouslyFocusedView som? UIButton hvis fokusertButton == buttonWithTag (2) || focusButton == buttonWithTag (3) hvis context.focusHeading == .Down return false returnere super.shouldUpdateFocusInContext (kontekst)
I shouldUpdateFocusInContext (_ :)
, Vi kontrollerer først om den tidligere fokuserte visningen er knapp 2 eller 3. Vi kontrollerer deretter fokusoverskriften. Hvis overskriften er lik Ned
, vi returnerer falsk
slik at dagens fokus ikke endres.
Kjør appen din forrige gang. Du kan ikke flytte fokuset ned fra knappene 2 og 3 til knappene 5 og 6.
Du bør nå være komfortabel å kontrollere og jobbe med fokusmotoren til tvOS. Du vet nå hvordan fokusmotoren fungerer, og hvordan du kan manipulere den for å passe uansett behov du har for dine egne Apple TV-apper.
Som alltid, vær sikker på å legge igjen dine kommentarer og tilbakemeldinger i kommentarene nedenfor.