English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Einleitung
In letzter Zeit habe ich etwas Freizeit gehabt und habe meine kürzlich abgeschlossenen Projekte zusammengefasst. In diesem Artikel werde ich hauptsächlich über die benutzerdefinierten Controller-Übergangsanimationen von iOS push sprechen und sie teilen, um anderen zur Referenz und zum Lernen zur Verfügung zu stellen. Also werde ich nicht viel mehr sagen, lassen Sie uns gemeinsam einen detaillierten Überblick geben.
Detailliertes Bild:
iOS7 Apple hat die API für benutzerdefinierte Übergänge eingeführt. Seitdem können alle Animationen, die mit CoreAnimation implementiert werden können, zwischen zwei ViewController-Wechseln erscheinen. Und die Implementierung ist stark entkoppelt, was bedeutet, dass man, um andere Animationsschemata zu ersetzen, einfach einen Klassennamen ändern muss, was wirklich das Vergnügen eines hübschen Codes erfahren hat.
Es gibt viele Tutorials im Internet über eigen definierte Transitionseffekte, aber ich hoffe, dass die hier vorgestellten für alle leicht verständlich und einfach zu handhaben sind.
Es gibt zwei Arten von Transitionseffekten, Push und Modal, daher gibt es auch zwei Arten von eigen definierten Transitionseffekten. Heute sprechen wir über Push
eigen definierte Transitionseffekte Push
Zuerst das Interface aufbauen,4Tasten:
- (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; //Spalten 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]; } }
Animation hinzufügen:
- (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]; }; }
Die Benutzeroberfläche ist aufgebaut:
Um eine personalisierte Übergangsanimation beim Pushen zu implementieren, muss das Protokoll UINavigationControllerDelegate befolgt werden.
Apple hat in UINavigationControllerDelegate mehrere Protokollmethoden bereitgestellt, deren spezifische Funktionen durch die Rückgabetypen klar erkennbar sind.
//um die Übergangsanimation zu personalisieren - (nullable id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);
//Add user interaction to this animation - (nullable id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id) animationController NS_AVAILABLE_IOS(7_0);
Im ersten Ansatz muss ein Objekt, das das Protokoll UIViewControllerInteractiveTransitioning implementiert, zurückgegeben werden, und darin die Animation implementiert werden.
//Rückgabe der Animationsdauer - (NSTimeInterval)transitionDuration:(nullable id)transitionContext; //Schreiben Sie den Code der Animation darin - (void)animateTransition:(id)transitionContext;
Zunächst erstelle ich eine benutzerdefinierte Klasse namens LRTransitionPushController, die von NSObject abgeleitet ist und das Protokoll UIViewControllerAnimatedTransitioning befolgt
- (void)animateTransition:(id)transitionContext{ self.transitionContext = transitionContext; //Erhalten Sie den Quellcontroller, beachten Sie nicht, UITransitionContextFromViewKey zu schreiben LRTransitionPushController *fromVc = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; //Erhalten Sie den Zielcontroller, beachten Sie nicht, UITransitionContextToViewKey zu schreiben LRTransitionPopController *toVc = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; //Erhalten Sie die Containeransicht UIView *containView = [transitionContext containerView]; // Alle werden in den Container hinzugefügt. Beachten Sie die Reihenfolge, der View des Zielcontrollers muss nachträglich hinzugefügt werden. [containView addSubview:fromVc.view]; [containView addSubview:toVc.view]; UIButton *button = fromVc.button; //Zeichnung des Kreises UIBezierPath *startPath = [UIBezierPath bezierPathWithOvalInRect:button.frame]; //Erstellung von zwei圆形en UIBezierPath-Instanzen; einer für die Größe des Buttons und einer mit einem Radius, der ausreichend ist, um den Bildschirm zu bedecken. Die endgültige Animation erfolgt zwischen diesen Bezier-Pfaden. //Punkt der weitesten Ecke des Bildschirms vom Buttonzentrum CGPoint finalPoint; //Bestimmung des Quadrants des Auslösepunkts if(button.frame.origin.x > (toVc.view.bounds.size.width / 2)) { if (button.frame.origin.y < (toVc.view.bounds.size.height / 2)) { //Erstes Quadrant finalPoint = CGPointMake(0, CGRectGetMaxY(toVc.view.frame)); }else{ //Viertes Quadrant finalPoint = CGPointMake(0, 0); } }else{ if (button.frame.origin.y < (toVc.view.bounds.size.height / 2)) { //Zweites Quadrant finalPoint = CGPointMake(CGRectGetMaxX(toVc.view.frame), CGRectGetMaxY(toVc.view.frame)); }else{ //Drittes Quadrant finalPoint = CGPointMake(CGRectGetMaxX(toVc.view.frame), 0); } } CGPoint startPoint = CGPointMake(button.center.x, button.center.y); //Berechnung des Radius für die Ausbreitung vom Buttonzentrum zur weitesten Ecke des Bildschirms - Kontrollradius 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 controller, use the method to return the custom transition animation class that was just customized
- (id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC{ if (operation == UINavigationControllerOperationPush) { return [LRTranstionAnimationPush new]; }else{ return nil; } }
Up to this point, the custom transition animation is complete
The pop animation is just the reverse of the push animation, which will not be elaborated here. If you have any questions, please refer to the code
Add sliding return gesture
As mentioned above, this method is to add user interaction to this animation, so we need to implement the sliding return in the pop
The simplest way should be to use the UIPercentDrivenInteractiveTransition class provided by UIKit, which has already implemented the UIViewControllerInteractiveTransitioning protocol, students can use objects of this class to specify the completion percentage of the transition animation.
//Add user interaction to this animation - (nullable id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id) animationController NS_AVAILABLE_IOS(7_0);
First step: Add gesture
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; [self.view addGestureRecognizer:gestureRecognizer];
Second step: Determine the animation execution ratio through the change of user's sliding
- (void)handlePan:(UIPanGestureRecognizer *)gestureRecognizer { /*By calling the updateInteractiveTransition: method of UIPercentDrivenInteractiveTransition, you can control to what extent the transition animation has progressed, When the user's pull-down gesture is completed, call finishInteractiveTransition or cancelInteractiveTransition, UIKit will automatically execute the remaining half of the animation, or let the animation return to its initial state.*/ if ([gestureRecognizer translationInView:self.view].x>=0) { //Gestures sliding ratio 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; } }
Dritter Schritt: In der Methode, die als Proxy für die Benutzereingriffe bei der Animation zurückgegeben wird, die Instanz von UIPercentDrivenInteractiveTransition zurückgeben
- (id)navigationController:(UINavigationController *navigationController interactionControllerForAnimationController:(id) animationController { return self.interactiveTransition; }
Wenn Sie den Artikel nützlich finden, geben Sie bitte eine Geste des Likes, danke.
Der Code wurde hier abgelegtGitHubHier können Sie herunterladen, natürlich können Sie auch überLokale Downloads
Zusammenfassung
Das ist der gesamte Inhalt dieses Artikels. Wir hoffen, dass der Inhalt dieses Artikels für Ihre Lern- oder Arbeitsaktivitäten eine gewisse Referenz und Lernwerte hat. Wenn Sie Fragen haben, können Sie gerne Kommentare hinterlassen. Vielen Dank für Ihre Unterstützung für das Lernprogramm 'Schrei'.
Erklärung: Der Inhalt dieses Artikels wurde aus dem Internet übernommen und gehört dem Urheber. Der Inhalt wurde von Internetbenutzern freiwillig beigesteuert und hochgeladen. Diese Website besitzt keine Eigentumsrechte und hat den Inhalt nicht manuell bearbeitet. Sie übernimmt auch keine Haftung für relevante rechtliche Verantwortlichkeiten. Wenn Sie verdächtige urheberrechtliche Inhalte finden, freuen wir uns über eine E-Mail an: notice#oldtoolbag.com (bei der E-Mail sendung, ersetzen Sie bitte # durch @) zur Meldung von Missbrauch und geben Sie relevante Beweise an. Sobald nachgewiesen wird, dass eine Urheberrechtsverletzung vorliegt, wird diese Website die fraglichen Inhalte sofort löschen.