English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Préambule
Récemment, j'ai eu du temps libre, j'ai organisé les projets que j'ai réalisés récemment. Cet article présente principalement le contenu concernant les transitions d'animation personnalisées de contrôleur iOS push, et je le partage pour que chacun puisse l'étudier et l'utiliser. Je ne vais pas en dire plus, regardons ensemble la présentation détaillée.
Illustration :
iOS7 Apple a lancé l'API de transition personnalisée. Depuis lors, toute animation pouvant être réalisée avec CoreAnimation peut apparaître lors du basculement entre deux ViewController. De plus, la méthode d'implémentation est fortement découplée, ce qui signifie que pour remplacer d'autres schémas d'animation tout en garantissant la propreté du code, il suffit de modifier simplement un nom de classe, ce qui permet vraiment de ressentir le plaisir apporté par le code à haute valeur ajoutée.
En réalité, il y a beaucoup de tutoriels en ligne sur l'animation de transition personnalisée, mais j'espère que les étudiants pourront les comprendre et les utiliser facilement.
Il existe deux types de transition de phase : Push et Modal, donc l'animation de transition personnalisée est également divisée en deux types. Aujourd'hui, nous allons parler de Push
animation de transition personnalisée Push
Tout d'abord, construire l'interface et ajouter4des boutons :
- (void)addButton{ self.buttonArr = [NSMutableArray array]; CGFloat margin=50; CGFloat width=(self.view.frame.size.width-margin*3)/2; CGFloat height = width; CGFloat x = 0; CGFloat y = 0; //列 NSInteger col = 2; for (NSInteger i = 0; i < 4; i ++) { x = margin + (i%col)*(margin+width); 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]; } }
Ajouter l'animation :
- (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 = YES; positionAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; positionAnimation.duration = (idx == self.buttonArr.count - 1);63; 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, @1.1,@1.0]; scaleXAniamtion.keyTimes = @[@0.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 structure de l'interface est prête :
Pour implémenter une animation de transition personnalisée lors d'un Push, il faut respecter un protocole : UINavigationControllerDelegate
Apple a fourni plusieurs méthodes de protocole dans UINavigationControllerDelegate, où le type de retour peut clairement indiquer l'effet spécifique de chacun.
//utilisé pour personnaliser l'animation de transition - (nullable id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);
//Ajouter l'interaction utilisateur pour cette animation - (nullable id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id) animationController NS_AVAILABLE_IOS(7_0);
Dans la première méthode, il suffit de retourner un objet respectant l'accord UIViewControllerInteractiveTransitioning et d'y implémenter l'animation.
//Retourner le temps d'animation - (NSTimeInterval)transitionDuration:(nullable id)transitionContext; //Écrivez le code d'animation à l'intérieur - (void)animateTransition:(id)transitionContext;
Tout d'abord, j'ai personnalisé une classe nommée LRTransitionPushController qui hérite de NSObject et obéit à l'accord de UIViewControllerAnimatedTransitioning
- (void)animateTransition:(id)transitionContext{ self.transitionContext = transitionContext; //Obtenir le contrôleur source, attention à ne pas écrire UITransitionContextFromViewKey LRTransitionPushController *fromVc = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; //Obtenir le contrôleur cible, attention à ne pas écrire UITransitionContextToViewKey LRTransitionPopController *toVc = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; //Obtenir la vue de conteneur UIView *containView = [transitionContext containerView]; // Tous les deux sont ajoutés au container. Notez l'ordre : la vue du contrôleur cible doit être ajoutée en dernier [containView addSubview:fromVc.view]; [containView addSubview:toVc.view]; UIButton *button = fromVc.button; //dessiner un cercle UIBezierPath *startPath = [UIBezierPath bezierPathWithOvalInRect:button.frame]; //Créer deux instances de UIBezierPath circulaires ; l'une pour la taille du bouton, l'autre avec un rayon suffisant pour couvrir l'écran. L'animation finale se déroule entre ces deux chemins de Bézier. //point du coin le plus éloigné de l'écran par rapport au centre du bouton CGPoint finalPoint; //décider dans quel quadrant le point déclencheur se trouve if(button.frame.origin.x > (toVc.view.bounds.size.width / 2)) { if (button.frame.origin.y < (toVc.view.bounds.size.height / 2)) { //premier quadrant finalPoint = CGPointMake(0, CGRectGetMaxY(toVc.view.frame)); }else{ //quatrième quadrant finalPoint = CGPointMake(0, 0); } }else{ if (button.frame.origin.y < (toVc.view.bounds.size.height / 2)) { //deuxième quadrant finalPoint = CGPointMake(CGRectGetMaxX(toVc.view.frame), CGRectGetMaxY(toVc.view.frame)); }else{ //troisième quadrant finalPoint = CGPointMake(CGRectGetMaxX(toVc.view.frame), 0); } } CGPoint startPoint = CGPointMake(button.center.x, button.center.y); //Calculer le rayon de diffusion vers l'extérieur = la distance entre le centre du bouton et le coin le plus éloigné de l'écran - rayon du bouton 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)]; //affecter la valeur de mask au layer de la vue toVc 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"]; }
retourner la méthode utilisée pour personnaliser l'animation de transition en fonction du contrôleur
- (id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{ if (operation == UINavigationControllerOperationPush) { return [LRTranstionAnimationPush new]; }else{ return nil; } }
Jusqu'à présent, l'animation de transition personnalisée est terminée
L'animation de pop ne fait que faire l'inverse de l'animation de push, je ne vais pas entrer dans les détails ici, ceux qui ont des questions peuvent consulter le code
Ajouter le geste de retour glissant
Comme mentionné précédemment, cette méthode ajoute l'interaction utilisateur pour cette animation, donc nous devons réaliser le retour glissant lors du pop
La manière la plus simple devrait être d'utiliser la classe UIPercentDrivenInteractiveTransition fournie par UIKit, cette classe a déjà implémenté l'accord UIPercentDrivenInteractiveTransition, les étudiants peuvent utiliser l'objet de cette classe pour spécifier le pourcentage de fin de l'animation de transition.
//Ajouter l'interaction utilisateur pour cette animation - (nullable id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id) animationController NS_AVAILABLE_IOS(7_0);
Première étape : ajouter le geste
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; [self.view addGestureRecognizer:gestureRecognizer];
Deuxième étape : déterminer la proportion de l'animation à exécuter en fonction des changements de glissement de l'utilisateur
- (void)handlePan:(UIPanGestureRecognizer *)gestureRecognizer { /*Appeler la méthode updateInteractiveTransition: de UIPercentDrivenInteractiveTransition permet de contrôler jusqu'où l'animation de transition se déroule, Lorsque le geste de défilement du utilisateur est terminé, appeler finishInteractiveTransition ou cancelInteractiveTransition, UIKit exécutera automatiquement la moitié restante de l'animation, ou revenir à l'état initial de l'animation.*/ si ([gestureRecognizer translationInView:self.view].x>=0) { //比例 de glissement de geste CGFloat per = [gestureRecognizer translationInView:self.view].x / (self.view.bounds.size.width); per = MIN(1.0, (MAX(0.0, per))); if (gestureRecognizer.state == UIGestureRecognizerStateBegan) { self.interactiveTransition = [UIPercentDrivenInteractiveTransition new]; [self.navigationController popViewControllerAnimated:YES]; } else if (gestureRecognizer.state == UIGestureRecognizerStateChanged){ if([gestureRecognizer translationInView:self.view].x ==0){ [self.interactiveTransition updateInteractiveTransition:0.01]; }else{ [self.interactiveTransition updateInteractiveTransition:per]; } } else if (gestureRecognizer.state == UIGestureRecognizerStateEnded || gestureRecognizer.state == UIGestureRecognizerStateCancelled){ if([gestureRecognizer translationInView:self.view].x == 0){ [self.interactiveTransition cancelInteractiveTransition]; self.interactiveTransition = nil; }else if (per > 0.5) { [ self.interactiveTransition finishInteractiveTransition]; }else{ [ self.interactiveTransition cancelInteractiveTransition]; } self.interactiveTransition = nil; } } else if (gestureRecognizer.state == UIGestureRecognizerStateChanged){ [self.interactiveTransition updateInteractiveTransition:0.01]; [self.interactiveTransition cancelInteractiveTransition]; } else if ((gestureRecognizer.state == UIGestureRecognizerStateEnded || gestureRecognizer.state == UIGestureRecognizerStateCancelled)){ self.interactiveTransition = nil; } }
Étape 3 : Retournez l'instance de UIPercentDrivenInteractiveTransition dans la méthode d'agent utilisateur ajoutée pour l'interaction avec l'animation
- (id)navigationController:(UINavigationController *navigationController interactionControllerForAnimationController:(id) animationController { return self.interactiveTransition; }
Si vous trouvez cet article utile, cliquez sur "J'aime", merci beaucoup
Le code est placé dansGitHubVous pouvez télécharger ici, bien sûr, vous pouvez également passer parTéléchargement local
Résumé
Voici la totalité du contenu de cet article, j'espère que le contenu de cet article a une certaine valeur de référence pour votre apprentissage ou travail. Si vous avez des doutes, vous pouvez laisser des commentaires pour échanger, merci de votre soutien au tutoriel d'alarme.
Déclaration : le contenu de cet article est issu du réseau, propriété de l'auteur original, contribué et téléversé par les utilisateurs d'Internet, ce site ne détient pas de propriété, n'a pas été traité par l'édition humaine et n'assume pas de responsabilité juridique connexe. Si vous trouvez du contenu suspect de violation de droits d'auteur, veuillez envoyer un e-mail à : notice#oldtoolbag.com (veuillez remplacer # par @ lors de l'envoi d'un e-mail pour signaler une violation, et fournir des preuves pertinentes. Une fois vérifié, ce site supprimera immédiatement le contenu suspect de violation de droits d'auteur.)