Una dintre cele mai populare caracteristici noi introduse în iOS 8 este capacitatea de a crea mai multe tipuri de extensii. În acest tutorial, vă voi îndruma prin procesul de creare a unui widget personalizat pentru Astăzi secțiune a centrului de notificare. Dar, mai întâi, să revedem pe scurt câteva subiecte despre extensii și să înțelegem conceptele importante care folosesc widget-uri.
O extensie este un scop binar special. Nu este o aplicație completă, are nevoie de o care conține aplicație pentru a fi distribuite. Aceasta ar putea fi aplicația dvs. existentă, care poate include una sau mai multe extensii sau una nouă. Deși extensia nu este distribuită separat, ea are un container propriu.
O extensie este lansată și controlată prin intermediul acesteia gazdă aplicație. Ar putea fi Safari, de exemplu, dacă creați o extensie de partajare sau aplicația de sistem Today care are grijă de centrul de notificare și alte widget-uri. Fiecare zonă de sistem care acceptă extinderea este numită a punct de prelungire.
Pentru a crea o extensie, trebuie să adăugați o țintă proiectului proiectului care conține. Șabloanele furnizate de Xcode includ deja cadrele corespunzătoare pentru fiecare punct de extensie, permițând aplicației să interacționeze cu și să respecte politicile corecte ale aplicației gazdă.
Extensiile create pentru punctul de extensie de astăzi, așa-numitele widget-uri, sunt menite să ofere acces simplu și rapid la informații. Widgeturile se leagă de cadrul Centrului de notificare. Este important să vă proiectați widgetul cu o interfață de utilizator simplă și concentrată, deoarece prea multă interacțiune poate fi o problemă. Rețineți, de asemenea, că nu aveți acces la o tastatură.
Este de așteptat ca widget-urile să funcționeze bine și să le actualizeze conținutul. Performanța este un punct important de luat în considerare. Widgetul dvs. trebuie să fie gata rapid și să folosească resurse cu înțelepciune. Acest lucru va evita încetinirea întregii experiențe în jos. Sistemul termină widget-urile care folosesc prea multă memorie, de exemplu. Widget-urile trebuie să fie simple și concentrate pe conținutul pe care îl afișează.
Asta e destulă teorie pentru acum. Să începem să creăm un widget personalizat astăzi. Widgetul pe care urmează să-l creăm va afișa informații despre utilizarea discului, inclusiv o bara de progres pentru a oferi o referință vizuală rapidă pentru utilizator. Pe parcurs, vom aborda și alte concepte importante despre extensiile iOS 8.
Dacă doriți să construiți acest widget ca extensie la o aplicație existentă, continuați și deschideți proiectul Xcode și treceți la al doilea pas. Dacă începeți de la zero ca și mine, atunci mai întâi trebuie să creați o aplicație care să conțină.
Deschideți Xcode și în Fişier selectați meniul Nou> Proiect ... . Vom folosi Obiectiv-C ca limbaj de programare și Vizualizare individuală șablon pentru a începe cu.
Deschide Fişier meniu și alegeți Nou> Țintă ... . În Extensie de aplicație categorie, selectați Astăzi Extensie șablon.
Veți observa că Proiect la care se va adăuga obiectivul este proiectul în care lucrăm în prezent și extensia va fi încorporată în aplicația care conține. De asemenea, rețineți că extensia are un identificator distinct de pachet bazat pe cel al aplicației care conține, com.tutsplus.Today.Used-Space.
Clic Următor →, dați widget-ul dvs. un nume, de exemplu, Spațiu folosit, și faceți clic pe finalizarea pentru a crea noua țintă. Xcode a creat o nouă schemă pentru dvs. și vă va cere să o activați pentru dvs. Clic Activati a continua.
Xcode a creat un nou grup pentru numele widget-ului Spațiul folosit și a adăugat un număr de fișiere la el, a UIViewController
subclasa și un scenariu. Așa-i, un widget nu este altceva decât un controler de vizualizare și un tablou de bord. Dacă deschideți antetul controlerului de vizualizare în editorul de coduri, veți observa că acesta este într-adevăr o subclasare UIViewController
.
Dacă selectați ținta de extensie din lista de ținte, deschideți Construiți faze filă și extindeți Link binar cu biblioteci , veți vedea că noua țintă este legată de Centru de notificari cadru.
Acum vom construi o interfață de bază pentru widget-ul nostru. Stabilirea dimensiunii widget-ului este importantă și există două modalități de a spune sistemului cantitatea de spațiu de care avem nevoie. Unul utilizează funcția Auto Layout și celălalt utilizează funcția preferredContentSize
proprietatea controlorului de vizualizare.
Conceptul de machete adaptive este de asemenea aplicabil widget-urilor. Nu numai că acum avem iPhone-uri cu diferite lățimi (și iPad-uri și dispozitive viitoare), dar, de asemenea, amintiți-vă că widget-ul ar putea avea nevoie să-și afișeze conținutul în orientare peisaj. Dacă interfața cu utilizatorul poate fi descrisă cu constrângeri Auto Layout, atunci acesta este un avantaj clar pentru dezvoltator. Înălțimea poate fi ajustată ulterior cu setPreferredContentSize:
dacă e nevoie.
Deschis MainInterface.storyboard în editorul Xcode. Veți observa că o etichetă care afișează "Hello World" este deja prezentă în vizualizarea controlerului de vizualizare. Selectați-l și ștergeți-l din vizualizare, deoarece nu îl vom folosi. Adăugați o nouă etichetă în vizualizare și aliniați-o la marginea dreaptă, după cum se arată mai jos.
În Atribuții Inspector, setați culoarea textului în alb, alinierea textului la dreapta și textul etichetării la 50.0%.
Selectați Dimensiune pentru potrivirea conținutului din Xcode Editor pentru a redimensiona eticheta corect dacă este prea mică pentru a se potrivi cu conținutul acesteia.
Apoi, adăugați o UIProgressView
în partea stângă a etichetei și poziționați-o după cum se arată mai jos.
În ecranul de progres selectat, schimbați Progresul nuanțat atribut în Atribuții Inspector la alb și la Urmăriți nuanța culoare până la gri închis. Acest lucru va face mai vizibil. Acest lucru arată bine până acum. E timpul să aplicăm anumite constrângeri.
Selectați eticheta procentuală și adăugați o constrângere de sus, de jos și trailing, după cum se arată mai jos. Asigurați-vă că ați debifat Constrângeți la marje Caseta de bifat.
Selectați vizualizarea progresului și adăugați o constrângere de vârf, de conducere și de urmărire. Utilizați această ocazie pentru a schimba spațiul de conducere la 3 și nu uitați să debifați Constrângeți la marje.
Deoarece am schimbat valoarea constrângerii principale a vederii progresului, avem o mică problemă pe care trebuie să o rezolvăm. Cadrul vizualizării progresului nu reflectă constrângerile din perspectiva progresului. În ecranul de progres selectat, faceți clic pe Rezolvați problemele privind aspectul automat butonul din partea de jos și alegeți Actualizați rame de la Vizualizări selectate secțiune. Aceasta va actualiza cadrul afișării progresului pe baza constrângerilor pe care le-am stabilit mai devreme.
E timpul să vedem widget-ul în acțiune. Cu Spațiu folosit selectați, selectați Alerga de la Produs meniu sau lovitură Command-R. Afișați centrul de notificare prin deplasarea din partea de sus a ecranului spre partea inferioară și atingând Editați | × din partea de jos a centrului de notificare. Widget-ul dvs. ar trebui să fie disponibil pentru a adăuga secțiunea Astăzi. Adăugați-o în secțiunea Astăzi apăsând butonul de adăugare din partea stângă.
Asa ar trebui sa arate extensia noastra.
Asta arată bine, dar de ce există mult spațiu sub viziunea progresului și a etichetei? De asemenea, de ce sistemul de operare nu respecta constrângerile majore ale vizualizării progresului?
Ambele aspecte sunt marjele standard stabilite de sistemul de operare. Vom schimba acest lucru în pasul următor. Rețineți, totuși, că marja stângă este de dorit, deoarece aliniază vizualizarea progresului cu numele widgetului.
Dacă rotiți dispozitivul sau rulați aplicația pe un alt dispozitiv, veți observa că widget-ul ajustează dimensiunea corectă. Asta este datorită funcției Auto Layout.
Deschis TodayViewController.m în editorul Xcode. Veți observa că controlerul de vizualizare este în conformitate cu NCWidgetProviding
protocol. Aceasta înseamnă că trebuie să implementăm widgetMarginInsetsForProposedMarginInsets:
și returnați o marjă personalizată prin returnarea unei UIEdgeInsets
structura. Actualizați implementarea metodei după cum se arată mai jos.
- (UIEdgeInsets) widgetMarginInsetsForProposedImagini de margine: (UIEdgeInsets) marginile margins.bottom = 10.0; marjele de returnare;
Rulați aplicația din nou pentru a vedea rezultatul. Widget-ul ar trebui să fie mai mic, cu o marjă mai mică în partea de jos. Puteți personaliza aceste margini pentru a obține rezultatul urmărit.
Înainte de a trece mai departe, să terminăm interfața cu utilizatorul adăugând două ieșiri. Cu fișierul storyboard deschis, treceți la editorul asistent și asigurați-vă că acesta este afișat TodayViewController.m.
ține Control și trageți de la etichetă la interfața controlerului de vizualizare pentru a crea o priză pentru etichetă. Denumiți priza percentLabel
. Repetați acest pas și creați o priză denumită barView
pentru UIProgressView
instanță.
Vom folosi NSFileManager
pentru a calcula spațiul disponibil al dispozitivului. Dar cum actualizăm widgetul cu datele respective?
Aici este o altă metodă din NCWidgetProviding
protocolul intră în joc. Sistemul de operare invocă widgetPerformUpdateWithCompletionHandler:
atunci când widgetul este încărcat și poate fi apelat și în fundal. În ultimul caz, chiar dacă widget-ul nu este vizibil, sistemul îl poate lansa și cere actualizări pentru a salva un instantaneu. Acest instantaneu va fi afișat data viitoare când widgetul apare, de obicei pentru o perioadă scurtă de timp până când widget-ul este afișat.
Argumentul transmis în această metodă este un handler de completare care trebuie apelat atunci când conținutul sau datele sunt actualizate. Blocul are un parametru de tip NCUpdateResult
pentru a descrie dacă avem conținut nou de afișat. Dacă nu, sistemul de operare va ști că nu este nevoie să salvați un instantaneu nou.
Mai întâi trebuie să creați câteva proprietăți care să dețină dimensiunile libere, utilizate și totale. De asemenea, vom adăuga o proprietate pentru a ține spațiul utilizat pe dispozitiv. Acest lucru ne permite o mai mare flexibilitate mai târziu. Adăugați aceste proprietăți la extensia de clasă din TodayViewController.m.
@property (nonatomic, atribuiți) nesemnate lungi longSystemSize; @property (nonatomic, atribuiți) unsigned long long freeSize; @property (nonatomic, atribuire) unsigned long long usedSize; @property (nonatomic, atribuiți) double usedRate;
updateSizes
Apoi, creați și implementați o metodă de ajutor, updateSizes
, pentru a prelua datele necesare și pentru a calcula spațiul utilizat de dispozitiv.
- (void) updateSizes // Returnați atributele din NSFileManager NSDictionary * dict = [[NSFileManager defaultManager] attributesOfFileSystemForPath: eroare NSHomeDirectory (): nil]; // Setați valorile self.fileSystemSize = [[dict valueForKey: NSFileSystemSize] unsignedLongLongValue]; self.freeSize = [[valoare dictForKey: NSFileSystemFreeSize] unsignedLongLongValue]; self.usedSize = self.fileSystemSize - auto.freeSize;
Putem profita de asta NSUserDefaults
pentru a salva spațiul utilizat calculat între lansări. Ciclul de viață al unui widget este scurt, deci, dacă stocăm această valoare în memoria cache, putem configura interfața cu o valoare inițială și apoi calculam valoarea reală.
Acest lucru este, de asemenea, util pentru a determina dacă trebuie să actualizăm instantaneu widget-ul sau nu. Să creați două metode de convenție pentru a accesa baza de date implicită a utilizatorilor.
// @implementation - (dublu) usedRate return [[[NSUserDefaults standardUserDefaults] valueForKey: RATE_KEY] doubleValue]; - (void) setUsedRate: (dublu) folositRate NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; [implicit setValue: [NSNumber numberWithDouble: usedRate] pentruKey: RATE_KEY]; [implicit sincronizați];
Rețineți că folosim o macrocomandă RATE_KEY
asa ca nu uitati sa adaugati aceasta in partea de sus TodayViewController.m.
// Macro pentru cheia NSUserDefaults #define RATE_KEY @ "kUDRateUsed"
Deoarece widgetul nostru este un controler de vizualizare, viewDidLoad
metoda este un loc bun pentru a actualiza interfața cu utilizatorul. Folosim o metodă de ajutor, updateInterface
să facă acest lucru.
- (void) updateInterface rate dublu = auto.usedRate; // recupera valoarea cached self.percentLabel.text = [NSString stringWithFormat: @ "%. 1f %%", (rata * 100)]; self.barView.progress = rate; - (void) viewDidLoad [vizualizare superDidLoad]; [self updateInterface];
Numărul de octeți liberi tinde să se schimbe destul de frecvent. Pentru a verifica dacă într-adevăr trebuie să actualizăm widgetul, verificăm spațiul utilizat și aplicăm un prag de 0,01% în loc de numărul exact de octeți liberi. Modificați implementarea widgetPerformUpdateWithCompletionHandler:
așa cum se arată mai jos.
- (void) widgetPerformUpdateWithCompletionHandler: (void (^) (NCUpdateResult)) completareHandler [self updateSizes]; dublu newRate = (dublu) self.usedSize / (dublu) self.fileSystemSize; dacă (newRate - self.usedRate < 0.0001) completionHandler(NCUpdateResultNoData); else [self setUsedRate:newRate]; [self updateInterface]; completionHandler(NCUpdateResultNewData);
Recalculează spațiul utilizat și, dacă este semnificativ diferit de valoarea precedentă, salvați valoarea și actualizați interfața. Apoi spunem sistemului de operare că ceva sa schimbat. Dacă nu, atunci nu este nevoie de un instantaneu nou. În timp ce nu o folosim în acest exemplu, există și a NCUpdateResultFailed
valoare pentru a indica faptul că a apărut o eroare.
Rulați încă o dată aplicația. Ar trebui să afișeze acum valoarea corectă a spațiului utilizat de dispozitiv.
Să examinăm ciclul de viață al noului dvs. widget. Când deschideți Astăzi , sistemul poate afișa un instantaneu anterior până când este gata. Vizualizarea este încărcată și widgetul dvs. va prelua o valoare stocată în memoria cache NSUserDefaults
și să-l folosească pentru a actualiza interfața cu utilizatorul.
Următor →, widgetPerformUpdateWithCompletionHandler:
este apelat și va recalcula valoarea reală. Dacă valoarea cache și noua nu sunt semnificativ diferite, atunci nu facem nimic. Dacă noua valoare este substanțial diferită, o stocăm în cache și actualizăm interfața de utilizator în consecință.
În timp ce în fundal, widgetul poate fi lansat de sistemul de operare și același proces este repetat. Dacă NCUpdateResultNewData
este returnat, este creat un nou instantaneu pentru afișarea pentru următoarea apariție.
Deși arată deja spațiul utilizat, ar fi interesant să aveți un număr precis. Pentru a evita aglomerarea interfeței cu utilizatorul, vom face widgetul nostru mai interactiv. Dacă utilizatorul fixează eticheta procentuală, widgetul se extinde, afișând o nouă etichetă cu numere absolute. Aceasta este, de asemenea, o mare oportunitate de a învăța cum să folosești animația în widget-uri.
Deschis MainInterface.storyboard și selectați eticheta procentuală. În Atribuții Inspector, sub Vedere secțiune, găsiți Interacțiunea cu utilizatorul activată și să o activați.
Apoi, trebuie să eliminăm constrângerea de jos a etichetei. Distanța etichetei la partea inferioară a vederii se va schimba programabil, ceea ce înseamnă că restricția ar deveni nevalidă.
Selectați eticheta, deschideți mărimea zonă în Inspector de mărime, selectați constrângerea spațiului inferior și apăsați ștergeți. De asemenea, puteți selecta manual ghidul de constrângeri din vizualizare și îl puteți șterge. Eticheta are acum doar o constrângere superioară și limitată, după cum se arată mai jos.
Selectați controlerul de vizualizare făcând clic pe prima dintre cele trei pictograme din partea de sus a scenei. În mărimea zona Inspector de mărime, setați înălțimea la 106.
Adăugați o nouă etichetă în vizualizare și, așa cum am făcut înainte, setați culoarea albă în Atribuții Inspector. În plus, setați numărul de linii la 3, înălțimea la 61, și lățimea 200. Acest lucru ar trebui să fie suficient pentru a acoperi trei linii de informații. De asemenea, doriți ca aceasta să fie aliniată la marginea inferioară și la stânga.
Ultimul pas este să deschideți editorul asistent și să creați o priză pentru eticheta numită detailsLabel
.
Widgetul va fi extins doar pentru un moment scurt. Am putea salva un boolean NSUserDefaults
și încărcați-o amintindu-vă starea anterioară, dar, pentru a păstra simplu, de fiecare dată când widgetul este încărcat, acesta va fi închis. Când atingeți eticheta procentuală, apar informații suplimentare.
Să definim mai întâi două macrocomenzi în partea de sus a paginii TodayViewController.m pentru a ajuta la dimensiuni.
#define kWClosedHeight 37.0 #define kWExpandedHeight 106.0
În viewDidLoad
, adăugați două linii de cod pentru a seta înălțimea inițială a widgetului și pentru a face eticheta cu detalii să fie transparentă. Vom estompa în eticheta detaliilor atunci când este atinsă eticheta procentuală.
- (vid) viewDidLoad [super viewDidLoad]; [self updateInterface]; // noi [auto setPreferredContentSize: CGSizeMake (0.0, kWClosedHeight)]; [auto.detailsLabel setAlpha: 0.0];
Rețineți că am setat lățimea widgetului la 0.0, deoarece lățimea va fi setată de sistemul de operare.
În eticheta detaliată, vom arăta valorile pentru spațiul liber, utilizat și total disponibil cu ajutorul lui NSByteCountFormatter
. Adăugați următoarea implementare la controlerul de vizualizare.
-(void) actualizareDetaliiLabel NSByteCountFormatter * formatter = [[NSByteCountFormatter alloc] init]; [formatter setCountStyle: NSByteCountFormatterCountStyleFile]; auto.detaliiLabel.text = [NSString stringWithFormat: @ "Folosit: \ t% @ \ nFree: \ t% @ \ nTotal: \ t% @", [formatter stringFromByteCount: self.usedSize], [formatter stringFromByteCount: self.freeSize ], [formatorul șirFromByteCount: self.fileSystemSize]];
Pentru a detecta atingeri, suprascriem touchesBegan: withEvent:
metodă. Ideea este simplă, ori de câte ori este detectată o atingere, widgetul este extins și eticheta detaliilor este actualizată. Rețineți că dimensiunea widget-ului este actualizată prin apelare setPreferredContentSize:
pe controlerul de vizualizare.
-(void) atingeBegan: (NSSet *) atinge cu EventEvent: (UIEvent *) eveniment [self updateDetailsLabel]; [auto setPreferredContentSize: CGSizeMake (0.0, kWExpandedHeight)];
Chiar dacă widgetul funcționează ca amenzi, putem îmbunătăți experiența utilizatorului prin eliminarea etichetei de detalii în timp ce widgetul se extinde. Acest lucru este posibil dacă implementăm viewWillTransitionToSize: withTransitionCoordinator:
. Această metodă se numește când se modifică înălțimea widgetului. Deoarece un obiect al coordonatorului de tranziție este transmis, putem include animații suplimentare.
După cum puteți vedea, vom schimba valoarea alfa a etichetei de detalii, dar puteți adăuga orice tip de animat pe care credeți că îl îmbunătățește experiența utilizatorului.
-(void) viewWillTransitionToSize: Dimensiunea (CGSize) cuTransitionCoordinator: (id) coordonator [coordonator animateAlongsideTransition: ^ (id context) [auto.detailsLabel setAlpha: 1.0]; completare: nil];
Suntem gata să rulați aplicația încă o dată. Faceți o încercare și atingeți eticheta procentuală pentru a dezvălui detaliile noi.
Deși toată această logică poate părea prea complexă pentru o sarcină atât de simplă, acum veți fi familiarizați cu procesul complet pentru a crea o extensie de astăzi. Țineți cont de aceste principii atunci când proiectați și construiți widget-ul. Amintiți-vă să o păstrați simplu și direct și nu uitați performanța.
Cachingul aici nu ar fi deloc necesar cu aceste operațiuni rapide, dar este deosebit de important dacă aveți procesare costisitoare. Folosiți-vă cunoștințele despre controlorii de vizualizare și verificați dacă funcționează pentru diferite dimensiuni ale ecranului. De asemenea, este recomandat să evitați vizualizările de defilare sau recunoașterea complexă a atingerii.
Deși extensia va avea un container separat, după cum am văzut mai devreme, este posibil să activați partajarea datelor între extensie și aplicația care conține. Puteți utiliza, de asemenea NSExtensionContext
„s openURL: completionHandler:
cu o schemă de adrese URL personalizată pentru a lansa aplicația dvs. din widget. Și dacă codul este ceea ce trebuie să partajați cu extensia dvs., continuați și creați un cadru de utilizat în aplicația și extensia dvs..
Sper ca cunoștințele prezentate aici să fie utile atunci când vă construiți widget-ul dvs. de astăzi.