În primul tutorial al acestei serii scurte despre UIKit Dynamics, am învățat elementele de bază ale API prin crearea unei componente de meniu animate. În acest tutorial, vom continua să lucrăm la proiectul nostru și vom implementa o altă componentă animată, o vizualizare personalizată de alertă.
Vizualizarea implicită de alertă pe iOS este excelentă, dar nu este foarte personalizabilă în ceea ce privește aspectul și comportamentul. Dacă aveți nevoie de o vizualizare de alertă care să fie personalizabilă, atunci trebuie să vă creați propria soluție și asta vom face în acest tutorial. Acest tutorial se axează pe comportamentul vizualizării de alertă și nu pe funcționalitatea acesteia. Să vedem care este rezultatul pe care îl urmăm
Vizualizarea de alertă va fi a UIView
exemplu la care vom adăuga următoarele sub-viziuni:
UILabel
obiect pentru afișarea titlului vizualizării avertizăriiUILabel
obiect pentru afișarea mesajului vizualizării avertizăriiUIButton
instanțe pentru a permite utilizatorului să interacționeze cu vizualizarea de alertăVom folosi UISnapBehavior
clasa pentru a prezenta vizualizarea alertei. După cum indică și numele, aceasta UIDynamicBehavior
subclasa forțează un element dinamic să se apropie de un punct ca și cum ar fi fost atras de el magnetic.
UISnapBehavior
clasa definește o proprietate suplimentară, amortizare
, care definește cantitatea de oscilație atunci când elementul dinamic a atins punctul în care este atras.
Vom folosi un comportament gravitațional, în combinație cu un comportament de coliziune și împingere, pentru a respinge viziunea de alertă. Amintiți-vă că am folosit deja aceste comportamente în tutorialul anterior.
Vizualizarea de alertă va fi animată din partea de sus a ecranului. Când vizualizarea alertă este pe cale să apară, comportamentul instantaneu o va face să cadă în vedere și să se fixeze în centrul ecranului. Pentru a elimina vizualizarea de alertă, un comportament de împingere îl va împinge pe scurt în partea de jos a ecranului și un comportament gravitator îl va trage apoi în partea de sus a ecranului și îl va face animat off-screen.
Vom crea o metodă de inițializare personalizată pentru componenta de vizualizare a alertelor care acceptă titlul, mesajul, titlurile butoanelor și vizualizarea părintelui. Nu vom implementa un protocol delegat pentru vizualizarea de alertă. În schimb, vom face uz de blocuri, ceea ce înseamnă o soluție mai elegantă și mai modernă. Blocul sau manipulatorul vor accepta doi parametri, indicele și titlul butonului pe care utilizatorul l-a lovit.
De asemenea, vom afișa o vedere semi-transparentă în spatele vizualizării de avertizare, pentru a împiedica interacțiunea cu viziunea părinte a acestuia, atâta timp cât vizualizarea de alertă este vizibilă. Să începem să aruncăm o privire asupra proprietăților vizualizării alertei și a inițializatorului personalizat.
presa Command-N pe tastatură pentru a crea un fișier nou și pentru a selecta Clasa obiectiv-C din lista de iOS template-uri. Faceți-i o subclasă de NSObject și numește-o AlertComponent.
Următorul pas este să declarăm câteva proprietăți private. Deschis AlertComponent.m, adăugați o extensie de clasă în partea de sus și declarați următoarele proprietăți:
@interface AlertComponent () @property (nonatomic, puternic) UIView * alertView; @property (nonatomic, puternic) UIView * backgroundView; @property (nonatomic, puternic) UIView * targetView; @property (nonatomic, puternic) UILabel * titleLabel; @property (nonatomic, puternic) UILabel * messageLabel; @property (nonatomic, puternic) UIDynamicAnimator * animator; @property (nonatomic, strong) NSString * title; @property (nonatomic, strong) NSString * message; @property (nonatomic, puternic) NSArray * buttonTitles; @property (nonatomic) CGRect initialAlertViewFrame; @Sfârșit
Funcția fiecărei proprietăți va deveni clară pe măsură ce implementăm componenta de alertă. Este timpul să creați inițializatorul personalizat al componentei.
Așa cum am menționat deja, vom folosi un inițializator personalizat pentru a face lucrul cu componenta de alertă cât mai ușor posibil. Initializatorul acceptă patru parametri, titlul alertului, mesajul, titlurile butoanelor și vizualizarea la care va fi adăugată componenta de alertă, vizualizarea părinte. Deschis AlertComponent.h și adăugați următoarea declarație:
@interface AlertComponent: NSObject - (id) initAlertWithTitle: (NSString *) titlul și mesaj: (NSString *) mesaj șiButtonTitles: (NSArray *) butonTitle șiTargetView: (UIView *) targetView; @Sfârșit
În această parte, va fi creată vizualizarea de alertă și vor fi adăugate toate subdiviziuni. De asemenea, vor fi configurate vizualizarea de fundal, precum și animatorul dinamic.
Deschis AlertComponent.m și declarați următoarele metode private în extensia de clasă privată:
@interface AlertComponent () ... - (void) setupBackgroundView; - (void) setupAlertView; @Sfârșit
Numele de metode sunt explicite. Să începem prin implementarea setupAlertView
mai întâi, deoarece cea mai mare parte a configurației alertei are loc în această metodă.
În setupAlertView
, facem trei lucruri:
Să începem prin calcularea dimensiunii și poziției ecranului de alertă așa cum se arată în fragmentul de cod de mai jos.
- (void) setupAlertView // Setați dimensiunea ecranului de alertă. CGSize alertViewSize = CGSizeMake (250.0, 130.0 + 50.0 * auto.buttonTitles.count); // Stabiliți punctul de origine inițial în funcție de direcția vizualizării alertei. CGPoint inițialOriginPoint = CGPointMake (auto.targetView.center.x, self.targetView.frame.origin.y - alertViewSize.height);
Începem setând dimensiunea ecranului de alertă. Pentru a face dinamica vederii dinamice, adaugam 50.0
indică înălțimea sa pentru fiecare buton. De asemenea, rețineți că originea inițială a vizualizării de alertă este off-screen. Următorul pas este inițializarea și configurarea vizualizării de alertă:
auto.alertView = [[UIView alocare] initWithFrame: CGRectMake (initialOriginPoint.x, initialOriginPoint.y, alertViewSize.width, alertViewSize.height)]; // Culoare de fundal. [auto.alertView setBackgroundColor: [culoare UICcolorWithRed: 0.94 verde: 0.94 albastru: 0.94 alfa: 1.0]]; // Faceți vizualizarea alertă cu colțuri rotunjite. [auto.alertView.layer setCornerRadius: 10.0]; // Stabiliți o margine în ecranul de alertă. [auto.alertView.layer setBorderWidth: 1.0]; [auto.alertView.layer setBorderColor: [UICcolor negruColor] .CGColor]; // Atribuiți cadrul de vizualizare inițială cu proprietatea respectivă. self.initialAlertViewFrame = auto.alertView.frame;
Utilizarea alertViewSize
și initialOriginPoint
, inițializăm alertView
obiect și setați culoarea de fundal. Închidem colțurile ecranului de alertă prin setarea lui strat
„s cornerRadius
la 10.0
, este lățimea graniței
la 1.0
, si este borderColor
La negru. De asemenea, stocăm cadrul inițial al vizualizării de alertă initialAlertViewFrame
deoarece noi vom avea nevoie mai târziu.
Dacă Xcode vă spune că nu știe despre alertView
„s strat
proprietate, apoi adăugați următoarea declarație de import în partea de sus a fișierului de implementare:
#import
Este timpul să adăugați etichetele. Să începem cu eticheta titlului.
// Configurați eticheta titlului. auto.titleLabel = [[UILabel alocare] initWithFrame: CGRectMake (0.0, 10.0, self.alertView.frame.size.width, 40.0)]; [auto.titleLabel setText: auto.titul]; [auto.titleLabel setTextAlignment: NSTextAlignmentCenter]; [auto.titleLabel setFont: [UIFont fontWithName: @ "Avenir-Heavy" dimensiune: 14.0]]; // Adăugați eticheta de titlu în ecranul de alertă. [self.alertView addSubview: self.titleLabel];
Setarea etichetei mesajului este destul de similară.
// Configurați eticheta mesajului. auto.messageLabel = [[UILabel alocare] initWithFrame: CGRectMake (0.0, auto.titleLabel.frame.origin.y + auto.titleLabel.frame.size.height, self.alertView.frame.size.width, 80.0)]; [auto.messageLabel setText: self.message]; [auto.messageLabel setTextAlignment: NSTextAlignmentCenter]; [self.messageLabel setFont: [UIFont fontWithName: @ "Avenir" dimensiune: 14.0]]; [auto.messageLabel setNumberOfLines: 3]; [auto.messageLabel setLineBreakMode: NSLineBreakByWordWrapping]; // Adăugați eticheta mesajului în ecranul de alertă. [self.alertView addSubview: self.messageLabel];
Rețineți că numberOfLines
proprietatea este setată la 3
și lineBreakMode
este setat sa NSLineBreakByWordWrapping
.
Ultimul lucru pe care trebuie să-l configurați sunt butoanele vizualizării alertului. Chiar dacă numărul de butoane poate varia, configurarea și poziționarea butoanelor este destul de simplă. Separăm butoanele de 5
puncte și folosiți a pentru
pentru a le inițializa.
CGFloat lastSubviewBottomY = auto.messageLabel.frame.origin.y + auto.messageLabel.frame.size.height; pentru (int i = 0; i<[self.buttonTitles count]; i++) UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(10.0, lastSubviewBottomY + 5.0, self.alertView.frame.size.width - 20.0, 40.0)]; [button setTitle:[self.buttonTitles objectAtIndex:i] forState:UIControlStateNormal]; [button.titleLabel setFont:[UIFont fontWithName:@"Avenir" size:13.0]]; [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; [button setTitleColor:[UIColor yellowColor] forState:UIControlStateHighlighted]; [button setBackgroundColor:[UIColor colorWithRed:0.0 green:0.47 blue:0.39 alpha:1.0]]; [button addTarget:self action:@selector(handleButtonTap:) forControlEvents:UIControlEventTouchUpInside]; [button setTag:i + 1]; [self.alertView addSubview:button]; lastSubviewBottomY = button.frame.origin.y + button.frame.size.height;
Rețineți că fiecare buton invocă handleButtonTap:
atunci când este utilizată. Putem determina ce buton a fost utilizat de utilizator prin inspectarea butoanelor etichetă
proprietate.
În cele din urmă, adăugați vizualizarea de alertă la vizualizarea țintă sau părinte adăugând următoarea linie în partea de jos a metodei setupAlertView:
// Adăugați vizualizarea de alertă la vizualizarea părinte. [self.targetView addSubview: self.alertView];
A doua metodă pe care trebuie să o implementăm este setupBackgroundView
. Vederea de fundal va împiedica utilizatorul să interacționeze cu vizualizarea parentală a vizualizării de avertizare atât timp cât este afișată vizualizarea de alertă. Am stabilit-o inițial alfa
proprietate la 0.0
, ceea ce înseamnă că este transparent.
- (void) setupBackgroundView auto.backgroundView = [[UIView alocare] initWithFrame: self.targetView.frame]; [auto.backgroundView setBackgroundColor: [UICcolor griColor]]; [auto.backgroundView setAlpha: 0.0]; [self.targetView addSubview: auto.backgroundView];
Cu setupAlertView
și setupBackgroundView
gata de utilizare, să implementăm inițializatorul personalizat pe care l-am declarat anterior.
- (id) * initAlertWithTitle: (NSString *) mesajul title șiMessage: (NSString *) șiButtonTitles: (NSArray *) butonulTitle șiTargetView: (UIView *) targetView if (self = [super init] proprietăți. auto.title = titlu; self.message = mesaj; self.targetView = targetView; auto.buttonTitles = butoane; // Configurați vizualizarea de fundal. [auto setupBackgroundView]; // Configurați vizualizarea avertizării. [self setupAlertView]; // Configurați animatorul. self.animator = [[Alocare UID dynamicAnimator] initWithReferenceView: self.targetView]; întoarce-te;
Am setat titlu
, mesaj
, targetView
, și buttonTitles
proprietăți, invoca setupBackgroundView
și setupAlertView
, și inițializează animatorul dinamic, trecând self.targetView
ca vedere de referință.
Pentru a afișa vizualizarea alertei după ce a fost inițializată, trebuie să declarăm și să implementăm o metodă publică care poate fi apelată, de exemplu, de către controlerul de vizualizare care găzduiește vizualizarea de avertizare. Deschis AlertComponent.h și adăugați următoarea declarație de metodă:
- showAlertView (void);
Înapoi la AlertComponent.m a implementa showAlertView
. Așa cum am menționat mai devreme în acest tutorial, vom folosi un nou UIDynamicBehavior
subclasa pentru a afișa vizualizarea de alertă, UISnapBehavior
. Să vedem cum folosim această clasă showAlertView
.
- (void) showAlertView [self.animator removeAllBehaviors]; UISnapBehavior * snapBehavior = [[UISnapBehavior aliniere] initWithItem: self.alertView snapToPoint: self.targetView.center]; snapBehavior.damping = 0.8; [self.animator addBehavior: snapBehavior]; [UIView animateWithDuration: 0.75 animații: ^ [auto.backgroundView setAlpha: 0.5]; ];
Începem prin eliminarea oricăror comportamente dinamice existente de la animatorul dinamic pentru a ne asigura că nu apar conflicte. Amintiți-vă că unele comportamente dinamice pot fi adăugate o singură dată animatorului dinamic, cum ar fi un comportament gravitațional. De asemenea, vom adăuga și alte comportamente dinamice pentru a respinge vizualizarea de alertă.
După cum puteți vedea, folosirea unui comportament rapid nu este dificilă. Specificăm elementul dinamic al cărui comportament trebuie aplicat și setăm punctul la care ar trebui să se fixeze elementul dinamic. De asemenea, setăm comportamentul amortizare
proprietate așa cum am discutat mai devreme. De asemenea, rețineți că animăm alfa
proprietatea vederii de fundal.
Pentru a testa vizualizarea de alertă, trebuie să efectuăm câteva modificări la ViewController
clasă. Să începem prin adăugarea a UIButton
exemplu la vizualizarea controlerului de vizualizare pentru a afișa vizualizarea de avertizare. Deschis Main.storyboard și trageți a UIButton
exemplu de la Biblioteca de obiecte la vizualizarea controlerului de vizualizare. Poziționați butonul în partea de jos a ecranului și dați-i un titlu Afișați Vizualizare avertizare. Adăugați o acțiune la ViewController.h așa cum se arată mai jos.
@ interfață ViewController: UIViewController - (IBAction) showAlertView: (id) expeditor; @Sfârșit
Întoarceți-vă la storyboard și conectați acțiunea controlerului de vedere la buton. Deschis ViewController.m și importați fișierul antet al fișierului AlertComponent
clasă.
#import "AlertComponent.h"
Apoi, declarați o proprietate în extensia de clasă privată de tip AlertComponent
și numește-o alertComponent
.
@ interfață ViewController () @property (nonatomic, puternic) MenuComponent * menuComponent; @property (nonatomic, strong) AlertComponent * alertComponent; - (void) showMenu: (UIGestureRecognizer *) gestureRecognizer; @Sfârșit
Apoi, inițializăm componenta de alertă în controlerul de vizualizare viewDidLoad
metodă.
- (void) viewDidLoad ... // Initialize Alert Component auto.alertComponent = [[AlertComponent alloc] initAlertWithTitle: @ "Custom Alert" șiMessage: @ "Aveți un nou mesaj de poștă electronică, dar nu știu de la cine." șiButtonTitles: @ [@ "Arată-mă", @ "Nu-mi pasă", @ "Pentru mine, într-adevăr?"] șiTargetView: self.view];
Pentru a afișa componenta de alertă, invoca showAlertView:
în acțiunea pe care tocmai am creat-o, showAlertView:
.
- (IBAction) showAlertView: (id) expeditor [auto.alertComponent showAlertView];
Rulați aplicația și atingeți butonul pentru a afișa vizualizarea de avertizare. Rezultatul ar trebui să pară similar celui de mai jos.
După cum am văzut mai devreme, handleButtonTap:
metoda este invocată atunci când utilizatorul pune pe butonul vizualizarea de alertă. Vizualizarea de alertă ar trebui să se ascundă atunci când unul dintre butoane este apăsat. Să vedem cum funcționează acest lucru.
Revedeți AlertComponent.m și, în extensia de clasă privată, declară handleButtonTap:
metodă.
@interface AlertComponent () ... - (void) handleButtonTap: (UIButton *) expeditor; @Sfârșit
În această metodă, creăm un număr de comportamente dinamice și le adăugăm în obiectul animator dinamic. Comportamentele dinamice de care avem nevoie sunt:
După eliminarea comportamentelor existente din animatorul dinamic și inițializarea comportamentului de împingere, după cum se arată mai jos.
- (void) handleButtonTap: (UIButton *) expeditor // Elimina toate comportamentele de la animator. [self.animator removeAllBehaviors]; UIPushBehavior * pushBehavior = [[UIPushBehavior alloc] initWithItems: modul [auto.alertView]: UIPushBehaviorModeInstantaneous]; [pushBehavior setAngle: M_PI_2 magnitudine: 20,0]; [self.animator addBehavior: pushBehavior];
unghi
proprietatea comportamentului de împingere definește direcția împingerii. Prin setarea unghiului la M_PI_2
, forța comportamentului de împingere este îndreptată spre partea inferioară a ecranului.
Următorul pas este adăugarea comportamentului gravitațional. Vectorul la care trecem setGravityDirection
va duce la o forță spre partea de sus a ecranului, tragând vederea în sus.
UIGravityBehavior * gravityBehavior = [[UIGravityBehavior alocare] initWithItems: @ [auto.alertView]]; [gravitateBehavior setGravityDirection: CGVectorMake (0.0, -1.0)]; [auto.animator addBehavior: gravityBehavior];
Ceea ce interesează despre comportamentul de coliziune este acela că definim o limită care este off-screen.
UICcolisionBehavior * collisionBehavior = [[AlocareBehavior UIC] initWithItems: @ [auto.alertView]]; [collisionBehavior addBoundaryWithIdentifier: @ "alertCollisionBoundary" dinPoint: CGPointMake (auto.initialAlertViewFrame.origin.x, self.initialAlertViewFrame.origin.y - 10.0) toPoint: CGPointMake (auto.initialAlertViewFrame.origin.x + self.initialAlertViewFrame.size.width, auto.initialAlertViewFrame.origin.y - 10.0)]; [self.animator addBehavior: collisionBehavior];
De asemenea, avem nevoie de un comportament dinamic pentru a stabili elasticitatea coliziunii. Rezultatul este că vizualizarea alertă va scădea puțin atunci când se ciocnește cu limita off-screen.
UIDynamicItemBehavior * itemBehavior = [[UID dynamicItemBehavior alocat] initWithItems: @ [auto.alertView]]; itemBehavior.elasticity = 0.4; [self.animator addBehavior: itemBehavior];
De asemenea, trebuie să facem din nou viziunea de fundal transparentă. Facem acest lucru setând vizualizarea fundalului alfa
proprietate la 0.0
într-un bloc de animație.
[UIView animateWithDuration: 2.0 animații: ^ [auto.backgroundView setAlpha: 0.0]; ];
Rulați încă o dată aplicația pentru a vedea rezultatul.
Chiar dacă vizualizarea alertă răspunde la interacțiunea cu utilizatorul, în prezent nu știm ce buton a fost utilizat de utilizator. Asta ne vom concentra în această secțiune.
Așa cum am făcut și cu componenta de meniu, vom folosi blocuri pentru a rezolva această problemă. Blocurile fac pentru o soluție elegantă și pot fi adesea mai ușor de folosit decât un protocol delegat.
Începem prin actualizarea publicului showAlertView
metodă. Metoda trebuie să accepte un handler de completare pe care vizualizarea de alertă o invocă atunci când utilizatorul a atins unul dintre butoane. În AlertComponent.h, actualizați declarația showAlertView
metoda de la:
- showAlertView (void);
la:
- (void) showAlertViewWithSelectionHandler: (void (^) (butonul NSIntegerIndex, NSString * buttonTitle)) handler;
Operatorul de finalizare acceptă doi parametri, indicele de tip NSInteger
, și titlul, de tip NSString
, a butonului care a fost utilizat de utilizator. Dacă vrem să invocăm modulul handler de finalizare atunci când utilizatorul pune la dispoziție un buton din vizualizarea de alertă, trebuie să păstrăm o referință la instrumentul de completare. Aceasta înseamnă că trebuie să declarăm o proprietate pentru agentul de completare. Facem asta în extensia de clasă privată din AlertComponent.m.
@interface AlertComponent () ... @property (nonatomic, strong) void (^ selectionHandler) (NSInteger, NSString *); ... @end
Inca inauntru AlertComponent.m, actualizați descrierea metodei așa cum am făcut-o în fișierul antet cu un moment în urmă și stocați manualul de completare în selectionHandler
proprietate, pe care tocmai am declarat-o.
- (void) showAlertViewWithSelectionHandler: (void (^) (NSInteger, NSString *)) handler auto.selecțieHandler = manipulator; ...
Ultima piesă a puzzle-ului invocă instructorul de completare handleButtonTap:
, trecând în eticheta și titlul butonului.
- (void) handleButtonTap: (UIButton *) expeditor // Apelați selectorul de selecție. auto.selecțieHandler (sender.tag, sender.titleLabel.text); ...
AlertComponent este completă. Este timpul să testați totul. Înapoi la ViewController.m și actualizați acțiunea showAlertView: după cum se arată mai jos. După cum puteți vedea, noi invocăm noul showAlertViewWithSelectionHandler:
și trece într-un bloc, care va fi apelat atunci când un utilizator din ecranul de alertă este apăsat de utilizator.
- (IBAction) showAlertView: (id) expeditor [auto.alertComponent showAlertViewWithSelectionHandler: ^ (butonul NSIntegerIndex, NSString * buttonTitle) NSLog (@ "% ld,% @", butonul lungIndex, butonulTitle); ];
Asta e. Rulați încă o dată aplicația și examinați consola Xcode pentru a vedea rezultatul activității noastre.
UIKit Dynamics a fost introdus pentru prima oară în iOS 7 și vă poate ajuta să creați rapid animații realiste. Această serie scurtă a ilustrat faptul că mobilizarea UIKit Dynamics în proiectele dvs. nu este dificilă și nu trebuie să fiți un expert în matematică sau fizică.
Rețineți că UIKit Dynamics este destinat în primul rând pentru utilizarea în aplicații bazate pe vizualizare. Dacă sunteți în căutarea unei soluții similare pentru jocuri, vă recomandăm să aruncați o privire la Sprite Kit-ul Apple, care vizează dezvoltarea jocurilor.