În iOS, utilizatorii interacționează în mod normal cu aplicațiile dvs. prin intermediul ecranului tactil al dispozitivului. Pe tvOS, cu toate acestea, interacțiunea cu utilizatorul este manipulată prin mutarea curentului concentra între vizualizările de pe ecran.
Din fericire, implementările tvOS ale API-urilor UIKit se ocupă de schimbarea focalizării între vizualizări în mod automat. În timp ce acest sistem încorporat funcționează foarte bine, pentru aspecte și / sau scopuri specifice de vizualizare, poate fi necesar să controlați uneori manual motorul de focalizare.
În acest tutorial, analizăm în profunzime motorul de focalizare tvOS. Învățați cum funcționează și cum să o controlați oricum doriți.
Acest tutorial necesită să executați Xcode 7.3 sau o versiune ulterioară cu cea mai recentă SDOS 9.2 SDK. Dacă doriți să continuați, trebuie să descărcați proiectul de pornire de la GitHub.
Scopul motorului de focalizare al tvOS este de a ajuta dezvoltatorii să se concentreze asupra conținutului unic al aplicației proprii, în loc să reimplementeze comportamentele de navigație de bază. Acest lucru înseamnă că, în timp ce mulți utilizatori vor folosi Siri Remote Apple TV, motorul de focalizare acceptă automat toate dispozitivele de intrare Apple TV actuale și viitoare.
Aceasta înseamnă că, în calitate de dezvoltator, nu trebuie să vă faceți griji cu privire la modul în care un utilizator interacționează cu aplicația dvs. Un alt obiectiv important al motorului de focalizare este de a crea o experiență constantă între utilizatori. Din acest motiv, nu există niciun API care să permită unei aplicații să deplaseze focalizarea.
Atunci când utilizatorul interacționează cu telecomanda Apple TV prin deplasarea pe geam atingeți suprafața într-o anumită direcție, motorul de focalizare caută o vizibilă posibilă în această direcție și, dacă se găsește, mișcă focalizarea spre acea vizualizare. Dacă nu se găsește o vizualizare focalizată, focalizarea rămâne acolo unde este în prezent.
În plus față de mutarea focalizării într-o anumită direcție, motorul de focalizare se ocupă și de alte comportamente mai avansate, cum ar fi:
Când determinați unde trebuie să treacă concentrarea într-o aplicație, motorul de focalizare are o imagine internă a interfeței curente a aplicației dvs. și evidențiază toate elementele vizibile care pot fi focalizate. Aceasta înseamnă că orice vizualizări ascunse, inclusiv vederi cu o valoare alfa de 0, nu pot fi focalizate. Aceasta înseamnă că, pentru orice vizualizare ascunsă de o altă imagine, numai partea vizibilă este considerată de motorul de focalizare.
Dacă motorul de focalizare găsește o vizualizare pe care o poate deplasa, acesta notifică obiectele conforme cu UIFocusEnvironment
care sunt implicate în schimbarea. Clasele UIKit care sunt conforme cu UIFocusEnvironment
protocol sunt UIWindow
, UIViewController
, UIView
, și UIPresentationController
. Motorul de focalizare sună shouldUpdateFocusInContext (_ :)
metoda tuturor obiectelor de mediu de focalizare care conțin fie viziunea curentă concentrată, fie viziunea pe care se îndreaptă focalizarea. Dacă oricare dintre aceste apeluri de metodă revine fals
, focalizarea nu se schimbă.
UIFocusEnvironment
protocol reprezintă un obiect cunoscut sub numele de a mediu de focalizare. Protocolul definește a preferredFocusView
proprietate care specifică unde trebuie să se deplaseze focalizarea în cazul în care mediul actual se focalizează în sine.
De exemplu, a UIViewController
obiect implicit preferredFocusView
este punctul său de vedere. Ca fiecare UIView
Obiectul poate specifica și propria sa viziune de focalizare preferată, a lanțul de focalizare preferat pot fi create. Motorul de focalizare tvOS urmează acest lanț până când un anumit obiect nu se întoarce de sine
sau zero
de la ei preferredFocusView
proprietate. Prin utilizarea acestor proprietăți, puteți redirecționa focalizarea pe întreaga interfață a utilizatorului și, de asemenea, să specificați ce vizualizare trebuie să fie focalizată mai întâi când un controler de vizualizare apare pe ecran.
Este important să rețineți că, dacă nu schimbați nimic preferredFocusView
proprietățile vizualizărilor și controlorilor de vizualizare, focalizarea motorului implicit focalizează vizualizarea cea mai apropiată de colțul din stânga sus al ecranului.
O actualizare a focalizării are loc atunci când are loc unul din cele trei evenimente:
Ori de câte ori are loc o actualizare, urmează următoarele evenimente:
UIScreen
obiecte focusedView
proprietatea este schimbată în viziunea la care se îndreaptă atenția.didUpdateFocusInContext (_: withAnimationCoordinator :)
din fiecare obiect de mediu de focalizare implicat în actualizarea focalizării. Acestea sunt aceleași seturi de obiecte pe care motorul de focalizare le verifică prin apelarea fiecărui obiect shouldUpdateFocusInContext (_ :)
înainte de a actualiza focalizarea. În acest moment, puteți adăuga animații personalizate pentru a rula împreună cu animațiile legate de focalizare pe care le oferă sistemul.Pentru a actualiza manual focalizarea în interfața cu utilizatorul, puteți invoca funcția setNeedsFocusUpdate ()
metoda oricărui obiect de mediu de focalizare. Aceasta restabilește focalizarea și o mută înapoi în mediul înconjurător preferredFocusView
.
De asemenea, sistemul poate declanșa o actualizare automată a focalizării în mai multe situații, inclusiv în cazul în care o vizualizare focalizată este eliminată din ierarhia de vizualizare, o vizualizare a tabelei sau a colecției își reîncarcă datele sau când este prezentat sau respins un nou controler de vizualizare.
În timp ce motorul de focalizare tvOS este destul de complex și are o mulțime de piese în mișcare, API-urile UIKit oferite vă fac foarte ușor să utilizați acest sistem și să îl faceți să funcționeze așa cum doriți.
Pentru a extinde motorul de focalizare, vom implementa un comportament înfășurat. Aplicația noastră curentă are o grilă de șase butoane, după cum se arată în ecranul de mai jos.
Ceea ce vom face este să permiteți utilizatorului să deplaseze focalizarea spre dreapta, de la butoanele 3 și 6 și să înfășoare focalizarea înapoi spre butoanele 1 și respectiv 4. Pe măsură ce motorul de focalizare ignoră orice vizualizare invizibilă, acest lucru nu se poate face prin introducerea unui invizibil UIView
(inclusiv o vedere cu o lățime și înălțime de 0) și schimbarea lui preferredFocusedView
proprietate.
În schimb, putem realiza acest lucru folosind UIFocusGuide
clasă. Această clasă este o subclasă de UILayoutGuide
și reprezintă o regiune rectangulară focalizabilă pe ecran în timp ce este complet invizibilă și nu interacționează cu ierarhia vizuală. Pe partea de sus a tuturor UILayoutGuide
proprietăți și metode, UIFocusGuide
clasa adaugă următoarele proprietăți:
preferredFocusedView
: Această proprietate funcționează așa cum am descris mai devreme. Vă puteți gândi la acest lucru ca la punctul în care doriți să se redirecționeze ghidul de focalizare.activat
: Această proprietate vă permite să activați sau să dezactivați ghidul de focalizare.În proiectul dvs., deschis ViewController.swift și să pună în aplicare viewDidAppear (_ :)
metodă a ViewController
clasa după cum se arată mai jos:
override functie viewDidAppear (animat: Bool) super.viewDidAppear (animat) lasati rightButtonIds = [3, 6] pentru butonulIndicator in dreaptaButtonIds daca butonul da = butonulWithTag (butonulId) focusGuide = UIFocusGuide (focusGuide) focusGuide .widthAnchor.constraintEqualToAnchor (buton.widthAnchor) .active = true focusGuide.heightAnchor.constraintEqualToAnchor (buton.heightAnchor) .active = true focusGuide.leadingAnchor.constraintEqualToAnchor (buton.trailingAnchor, constant: 60.0) .active = true focusGuide.centerYAnchor.constraintEqualToAnchor (button.centerYAnchor) .activ = adevărat focusGuide.preferredFocusedView = butonulWithTag (buttonId-2) leftButtonIds = [1, 4] pentru buttonId în leftButtonIds if let = buttonWithTag (buttonId) let focusGuide = UIFocusGuide .addLayoutGuide (focusGuide) focusGuide.widthAnchor.constraintEqualToAnchor (buton.widthAnchor) .active = true focusGuide.heightAnchor.constraintEqualToAnchor (buton.heightAnchor) .active = true focusGuide.tr ailingAnchor.constraintEqualToAnchor (buton.leadingAnchor, constant: -60.0) .activ = adevărat focusGuide.centerYAnchor.constraintEqualToAnchor (buton.centerYAnchor) .activ = adevărat focusGuide.preferredFocusedView = butonWithTag (buttonId + 2)
În viewDidAppear (_ :)
, vom crea ghiduri de focalizare în partea dreaptă a butoanelor 3 și 6 și în partea stângă a butoanelor 1și 4. Deoarece aceste ghiduri de focus reprezintă o regiune focalizabilă în interfața cu utilizatorul, ele trebuie să aibă o înălțime și o lățime stabilite. Cu acest cod, facem ca regiunile să aibă aceeași dimensiune ca celelalte butoane, astfel încât logica bazată pe impulsuri a motorului de focalizare să se simtă conformă cu butoanele vizibile.
Pentru a ilustra modul în care funcționează animațiile coordonate, actualizăm alfa
proprietățile butoanelor atunci când se schimbă focalizarea. În ViewController.swift, pune în aplicare didUpdateFocusInContext (_: withAnimationCoordinator :)
metodă în ViewController
clasă:
override funcția didUpdateFocusInContext (context: UIFocusUpdateContext, cuAnimationCoordinator coordinator: UIFocusAnimationCoordinator) super.didUpdateFocusInContext (context, cuAnimationCoordinator: coordinator) dacă permiteți focusButton = context.previouslyFocusedView as? UIButton unde buttons.contains (focusedButton) coordinator.addCoordinatedAnimations (focusedButton.alpha = 0.5, finalizarea: // Run animation completed)
context
parametru de didUpdateFocusInContext (_: withAnimationCoordinator :)
este a UIFocusUpdateContext
obiect care are următoarele proprietăți:
previouslyFocusedView
: se referă la viziunea la care se mișcă focalizareanextFocusedView
: se referă la viziunea la care se îndreaptă atențiafocusHeading
: A UIFocusHeading
valoarea de numărare reprezentând direcția în care se mișcă focalizareaOdată cu punerea în aplicare a didUpdateFocusInContext (_: withAnimationCoordinator :)
, adăugăm o animație coordonată pentru a schimba valoarea alfa a butonului focalizat anterior la valoarea 0.5 și cea a butonului focalizat în prezent la 1.0.
Rulați aplicația în simulator și mutați focalizarea între butoanele din interfața cu utilizatorul. Puteți vedea că butonul focalizat în prezent are un alfa de 1,0 în timp ce butonul focalizat anterior are un alfa de 0,5.
Prima închidere a addCoordinatedAnimations (_: finalizare :)
metoda funcționează similar cu cea obișnuită UIView
închiderea animației. Diferența este că îi moștenează durata și funcția de temporizare de la motorul de focalizare.
Dacă doriți să rulați o animație cu o durată personalizată, puteți adăuga orice UIView
animație în cadrul acestei închideri cu OverrideInheritedDuration
opțiune de animație. Următorul cod este un exemplu de implementare a unei animații personalizate care rulează în jumătate din timpul animațiilor de focalizare:
// Running custom animation timed let = UIView.inheritedAnimationDuration () UIView.animateWithDuration (durata / 2.0, întârziere: 0.0, opțiuni: .OverrideInheritedDuration, animații: // Animations, completare: (completat: Bool) în // Bloc de completare)
Prin utilizarea funcției UIFocusGuide
clasa și prin utilizarea de animații personalizate, puteți extinde comportamentul standard al motorului de focalizare tvOS pentru a se potrivi nevoilor dvs..
Așa cum am menționat mai devreme, atunci când se decide dacă focalizarea ar trebui să fie mutată dintr-o vedere în alta, motorul de focalizare îl sună shouldUpdateFocusInContext (_ :)
pe fiecare mediu de interes implicat. Dacă oricare dintre aceste apeluri de metodă revine fals
, focalizarea nu se schimbă.
În aplicația noastră, vom trece peste această metodă în ViewController
astfel încât focalizarea să nu poată fi mutată în jos dacă butonul focalizat în prezent este 2 sau 3. Pentru a face acest lucru, implementați shouldUpdateFocusInContext (_ :)
în ViewController
clasa după cum se arată mai jos:
override func shouldUpdateFocusInContext (context: UIFocusUpdateContext) -> Bool lasa focusButton = context.previouslyFocusedView as? UIButton dacă focusButton == butonulWithTag (2) || focusButton == butonulWithTag (3) if context.focusHeading == .Down return false retur super.shouldUpdateFocusInContext (context)
În shouldUpdateFocusInContext (_ :)
, mai întâi verificăm dacă vizualizarea focalizată anterior este butonul 2 sau 3. Atunci verificăm poziția focalizării. Dacă poziția este egală cu Jos
, ne intoarcem fals
astfel încât focalizarea actuală să nu se schimbe.
Rulați aplicația ultima oară. Nu puteți mișca focalizarea în jos de la butoanele 2 și 3 în butoanele 5 și 6.
Ar trebui să controlați și să lucrați confortabil cu motorul de focalizare al tvOS. Acum știți cum funcționează motorul de focalizare și cum îl puteți manipula pentru a se potrivi oricăror nevoi pe care le aveți pentru propriile aplicații Apple TV.
Ca întotdeauna, asigurați-vă că părăsiți comentariile și comentariile dvs. în comentariile de mai jos.