English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Introduzione
Negli ultimi tempi ho avuto un po' di tempo libero, ho organizzato i progetti che ho fatto di recente. Questo articolo introduce principalmente il contenuto di iOS personalizzazione del controller di transizione animazione push, lo condivido per riferimento e studio. Non c'è molto da dire, vediamo insieme la descrizione dettagliata.
Esempio di effetto:
A partire da iOS7, Apple ha introdotto l'API di transizione personalizzata. Da allora, qualsiasi animazione che può essere realizzata con CoreAnimation può apparire nella transizione tra due ViewController. E il modo di implementazione è altamente decoupled, il che significa che per mantenere il codice pulito e voler sostituire altri piani di animazione è sufficiente cambiare semplicemente un nome di classe, avendo veramente provato la gioia di un codice ad alta qualità.
In realtà ci sono molti tutorial su Internet sull'animazione di transizione personalizzata, qui spero che i miei compagni possano capirla facilmente e iniziare facilmente.
Le transizioni di transizione sono di due tipi, Push e Modal, quindi l'animazione di transizione personalizzata è anche di due tipi. Oggi parleremo di Push
Animazione di transizione personalizzata Push
Prima di tutto, costruiamo l'interfaccia e aggiungiamo 4 pulsanti:
- (void)aggiungiPulsante{ self.buttonArr = [NSMutableArray array]; CGFloat margine = 50; CGFloat larghezza = (self.view.frame.size.width-margine*3)/2; CGFloat altezza = larghezza; CGFloat x = 0; CGFloat y = 0; // colonne NSInteger col = 2; per (NSInteger i = 0; i < 4; i++) { x = margine + (i%col)*(margine+larghezza); y = margin + (i/col)*(margin+height) + 150; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = CGRectMake(x, y, width, height); button.layer.cornerRadius = width * 0.5; [button addTarget:self action:@selector(btnclick:) forControlEvents:UIControlEventTouchUpInside]; button.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:1.0]; button.tag = i+1; [self.view addSubview:button]; [self.buttonArr addObject:button]; } }
Aggiungi animazione:
- (void)setupButtonAnimation{ [self.buttonArr enumerateObjectsUsingBlock:^(UIButton * _Nonnull button, NSUInteger idx, BOOL * _Nonnull stop) { // positionAnimation CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; positionAnimation.calculationMode = kCAAnimationPaced; positionAnimation.fillMode = kCAFillModeForwards; positionAnimation.repeatCount = MAXFLOAT; positionAnimation.autoreverses = SI; positionAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; positionAnimation.duration = (idx == self.buttonArr.count - 1) ? 4 : 5+idx; UIBezierPath *positionPath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(button.frame, button.frame.size.width/2-5, button.frame.size.height/2-5)]; positionAnimation.path = positionPath.CGPath; [button.layer addAnimation:positionAnimation forKey:nil]; // scaleXAniamtion CAKeyframeAnimation *scaleXAniamtion = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale.x"]; scaleXAniamtion.values = @[@1.0,@1.1,@1.0]; scaleXAniamtion.keyTimes = @[@0.0,@0.5,@1.0]; scaleXAniamtion.repeatCount = MAXFLOAT; scaleXAniamtion.autoreverses = YES; scaleXAniamtion.duration = 4+idx; [button.layer addAnimation:scaleXAniamtion forKey:nil]; // scaleYAniamtion CAKeyframeAnimation *scaleYAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale.y"]; scaleYAnimation.values = @[@1,@1.1,@1.0]; scaleYAnimation.keyTimes = @[@0.0,@0.5,@1.0]; scaleYAnimation.autoreverses = YES; scaleYAnimation.repeatCount = YES; scaleYAnimation.duration = 4+idx; [button.layer addAnimation:scaleYAnimation forKey:nil]; }; }
La costruzione dell'interfaccia è stata completata:
Poi, per implementare un'animazione di transizione personalizzata durante il Push, è necessario seguire un accordo UINavigationControllerDelegate
Apple ha fornito alcuni metodi di accordo in UINavigationControllerDelegate, che possono essere identificati chiaramente attraverso il tipo di restituzione.
// utilizzato per personalizzare l'animazione di transizione - (nullable id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);
//Aggiungere l'interazione utente per questa animazione - (nullable id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id) animationController NS_AVAILABLE_IOS(7_0);
Nel primo metodo, ritorna un oggetto che rispetta l'accordo UIViewControllerInteractiveTransitioning e implementa l'animazione al suo interno.
// restituisce il tempo dell'animazione - (NSTimeInterval)transitionDuration:(nullable id)transitionContext; //Scrivi il codice dell'animazione all'interno di esso - (void)animateTransition:(id)transitionContext;
Prima di tutto, ho creato una classe chiamata LRTransitionPushController che eredita da NSObject e aderisce al protocollo UCLAyoutAnimatedTransitioning
- (void)animateTransition:(id)transitionContext{ self.transitionContext = transitionContext; //Ottengo il controller di origine Attenzione a non scriverlo come UITransitionContextFromViewKey LRTransitionPushController *fromVc = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; //Ottengo il controller di destinazione Attenzione a non scriverlo come UITransitionContextToViewKey LRTransitionPopController *toVc = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; //Ottengo la vista del container UIView *containView = [transitionContext containerView]; //Aggiungono entrambi al container. Attenzione all'ordine: la view del controller di destinazione deve essere aggiunta dopo. [containView addSubview:fromVc.view]; [containView addSubview:toVc.view]; UIButton *button = fromVc.button; //Disegno un cerchio UIBezierPath *startPath = [UIBezierPath bezierPathWithOvalInRect:button.frame]; //Creo due istanze di UIBezierPath; una con la dimensione del button e un'altra con un raggio sufficiente per coprire lo schermo. L'animazione finale si svolge tra questi due percorsi bezier. //Punto dell'angolo più lontano dal centro del pulsante rispetto allo schermo CGPoint finalPoint; //Determina in quale quadrante si trova il punto di attivazione if(button.frame.origin.x > (toVc.view.bounds.size.width / 2)){ if (button.frame.origin.y < (toVc.view.bounds.size.height / 2)) { //Primo quadrante finalPoint = CGPointMake(0, CGRectGetMaxY(toVc.view.frame)); altrimenti { //Quarto quadrante finalPoint = CGPointMake(0, 0); } altrimenti { if (button.frame.origin.y < (toVc.view.bounds.size.height / 2)) { //Secondo quadrante finalPoint = CGPointMake(CGRectGetMaxX(toVc.view.frame), CGRectGetMaxY(toVc.view.frame)); altrimenti { //Terzo quadrante finalPoint = CGPointMake(CGRectGetMaxX(toVc.view.frame), 0); } } CGPoint startPoint = CGPointMake(button.center.x, button.center.y); //Calcola il raggio di espansione esterna = distanza dal centro del pulsante al lato più lontano dello schermo - raggio del pulsante CGFloat radius = sqrt((finalPoint.x-startPoint.x) * (finalPoint.x-startPoint.x) + (finalPoint.y-startPoint.y) * (finalPoint.y-startPoint.y)) - sqrt(button.frame.size.width/2 * button.frame.size.width/2 + button.frame.size.height/2 * button.frame.size.height/2); UIBezierPath *endPath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(button.frame, -radius, -radius)]; //Assign to the mask of the toVc view layer CAShapeLayer *maskLayer = [CAShapeLayer layer]; maskLayer.path = endPath.CGPath; toVc.view.layer.mask = maskLayer; CABasicAnimation *maskAnimation =[CABasicAnimation animationWithKeyPath:@"path"]; maskAnimation.fromValue = (__bridge id)startPath.CGPath; maskAnimation.toValue = (__bridge id)endPath.CGPath; maskAnimation.duration = [self transitionDuration:transitionContext]; maskAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; maskAnimation.delegate = self; [maskLayer addAnimation:maskAnimation forKey:@"path"]; }
In the method used to customize the transition animation within the controller, return the custom animation class just now.
- (id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{ if (operation == UINavigationControllerOperationPush) { return [LRTranstionAnimationPush new]; altrimenti { return nil; } }
Fino a questo punto, l'animazione di transizione personalizzata è completata
L'animazione di pop è solo il contrario dell'animazione di push, non verrà spiegato in dettaglio qui, chi ha domande può guardare il codice
Aggiungere lo swipe di ritorno
Come detto prima, questo metodo aggiunge l'interazione utente per questa animazione quindi dobbiamo implementare il ritorno dello swipe durante il pop
Il modo più semplice dovrebbe essere utilizzare la classe UIPercentDrivenInteractiveTransition fornita da UIKit, questa classe ha già implementato l'protocollo UIViewControllerInteractiveTransitioning, gli studenti possono utilizzare l'oggetto di questa classe per specificare la percentuale di completamento della transizione di scena.
//Aggiungere l'interazione utente per questa animazione - (nullable id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id) animationController NS_AVAILABLE_IOS(7_0);
Primo passo: aggiungere il gesto
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; [self.view addGestureRecognizer:gestureRecognizer];
Secondo passo: determinare la proporzione dell'animazione in esecuzione attraverso le variazioni dello swipe dell'utente
- (void)handlePan:(UIPanGestureRecognizer *)gestureRecognizer { /*Chiamare il metodo updateInteractiveTransition: dell'UIPercentDrivenInteractiveTransition può controllare fino a dove l'animazione di transizione è in corso, Quando il gesto di scorrimento dell'utente è completato, chiamare finishInteractiveTransition o cancelInteractiveTransition, UIKit eseguirà automaticamente la metà rimanente dell'animazione, o tornare l'animazione all'inizio.*/ if ([gestureRecognizer translationInView:self.view].x>=0) { //La proporzioni dello swipe CGFloat per = [gestureRecognizer translationInView:self.view].x / (self.view.bounds.size.width) per = MIN(1.0, (MAX(0.0, per))); se (gestureRecognizer.state == UIGestureRecognizerStateBegan) { self.interactiveTransition = [UIPercentDrivenInteractiveTransition new]; [self.navigationController popViewControllerAnimated:YES]; altrimenti se (gestureRecognizer.state == UIGestureRecognizerStateChanged) { se ([gestureRecognizer translationInView:self.view].x == 0) { [self.interactiveTransition updateInteractiveTransition:0.01]; altrimenti { [self.interactiveTransition updateInteractiveTransition:per]; } altrimenti se (gestureRecognizer.state == UIGestureRecognizerStateEnded || gestureRecognizer.state == UIGestureRecognizerStateCancelled) { se ([gestureRecognizer translationInView:self.view].x == 0) { [self.interactiveTransition cancelInteractiveTransition]; self.interactiveTransition = nil; altrimenti se (per > 0.5) { [ self.interactiveTransition finishInteractiveTransition]; altrimenti { [ self.interactiveTransition cancelInteractiveTransition]; } self.interactiveTransition = nil; } altrimenti se (gestureRecognizer.state == UIGestureRecognizerStateChanged) { [self.interactiveTransition updateInteractiveTransition:0.01]; [self.interactiveTransition cancelInteractiveTransition]; } else if ((gestureRecognizer.state == UIGestureRecognizerStateEnded || gestureRecognizer.state == UIGestureRecognizerStateCancelled)){ self.interactiveTransition = nil; } }
Passo terzo: nel metodo dell'agente dell'interazione utente per l'animazione, restituisci un'istanza di UIPercentDrivenInteractiveTransition
- (id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id) animationController { return self.interactiveTransition; }
Se senti che questo articolo ti è stato utile, premi il pulsante Mi piace, grazie!
Il codice è stato messo inGitHubSul sito web è possibile scaricare, naturalmente, è possibile passare attraversoDownload locale
Sommario
Questo è tutto il contenuto dell'articolo, spero che il contenuto di questo articolo abbia un valore di riferimento per lo studio o il lavoro di tutti, se avete domande, potete lasciare un messaggio di commento, grazie per il supporto del Corso di urla.
Dichiarazione: il contenuto di questo articolo è stato tratto da Internet, il copyright spetta agli autori, il contenuto è stato contribuito volontariamente dagli utenti di Internet e caricato autonomamente, questo sito non detiene i diritti di proprietà, non è stato editato manualmente e non assume alcuna responsabilità legale correlata. Se trovi contenuti sospetti di copyright, invia un'e-mail a: notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare, fornendo prove pertinenti. Una volta verificata, questo sito eliminerà immediatamente il contenuto sospetto di violazione del copyright.