English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Введение
Недавно нашлось немного свободного времени, чтобы привести в порядок последние проекты. Эта статья в основном рассказывает о настройке анимации перехода push для iOS и делится этим для обсуждения и обучения. Теперь не будем тратить время на пустые слова, давайте посмотрим на подробное описание.
Эффект изображения:
С iOS 7 Apple начала предлагать API для настройки анимации перехода. С тех пор, любая анимация, которую можно реализовать с помощью CoreAnimation, может出现在 переходе между двумя ViewController. И способ реализации сильно декомпозирован, что означает, что для замены другого плана анимации вам нужно только изменить имя класса, что действительно позволяет насладиться удовольствием от кода с высоким качеством.
На самом деле в Интернете много инструкций по настройке анимации перехода, но я хочу, чтобы студенты могли легко понять и начать использовать.
Анимация перехода делится на два типа Push и Modal, поэтому настройка анимации также делится на два типа, сегодня мы поговорим о Push
Настройка анимации перехода Push
Сначала создадим интерфейс и добавим 4 кнопки:
- (void)addButton{ self.buttonArr = [NSMutableArray array]; CGFloat отступ = 50; CGFloat ширина = (self.view.frame.size.width - отступ * 3) / 2; CGFloat высота = ширина; CGFloat x = 0; CGFloat y = 0; // столбцы NSInteger колонка = 2; for (NSInteger i = 0; i < 4; i++) { x = отступ + (i%колонка) * (отступ + ширина); 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]; } }
Добавление анимации:
- (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) ? 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]; }; }
Макет интерфейса готов:
Затем, чтобы реализовать пользовательские анимации перехода при-push, нужно соблюдать протокол UINavigationControllerDelegate
Apple предоставляет несколько методов протокола в UINavigationControllerDelegate, и их конкретное действие можно легко понять по типу возвращаемого значения.
//Используется для создания пользовательских анимаций перехода - (nullable id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);
//Добавьте пользовательский интерфейс для этой анимации - (nullable id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id) animationController NS_AVAILABLE_IOS(7_0);
В первом методе нужно вернуть объект, соблюдающий протокол UIViewControllerInteractiveTransitioning, и реализовать анимацию в нем.
//返回动画时间 - (NSTimeInterval)transitionDuration:(nullable id)transitionContext; // Напишите код анимации внутрь - (void)animateTransition:(id)transitionContext;
Сначала я создаю класс под названием LRTransitionPushController, который наследуется от NSObject и соблюдает протокол UIViewControllerAnimatedTransitioning
- (void)animateTransition:(id)transitionContext{ self.transitionContext = transitionContext; // Получение контроллера источника. Не пишите UITransitionContextFromViewKey LRTransitionPushController *fromVc = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; // Получение контроллера цели. Не пишите UITransitionContextToViewKey LRTransitionPopController *toVc = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; // Получение контейнерного视图 UIView *containView = [transitionContext containerView]; // Все добавляются в container. Обратите внимание на порядок. Вид контроллера цели нужно добавить позже [containView addSubview:fromVc.view]; [containView addSubview:toVc.view]; UIButton *button = fromVc.button; // Рисование окружности UIBezierPath *startPath = [UIBezierPath bezierPathWithOvalInRect:button.frame]; // Создание двух экземпляров UIBezierPath; один из них соответствует размеру кнопки, а другой имеет半径, достаточный для全覆盖屏幕. Финальная анимация происходит между этими двумя кривыми Бе́зье. // Точка, наиболее удалённая от центра экрана, на углу кнопки CGPoint finalPoint; // Определение того, в каком квадранте находится точка триггера if(button.frame.origin.x > (toVc.view.bounds.size.width / 2)){ if (button.frame.origin.y < (toVc.view.bounds.size.height / 2)) { // Первый квадрант finalPoint = CGPointMake(0, CGRectGetMaxY(toVc.view.frame)); } иначе { // Четвёртый квадрант finalPoint = CGPointMake(0, 0); } } иначе { if (button.frame.origin.y < (toVc.view.bounds.size.height / 2)) { // Второй квадрант finalPoint = CGPointMake(CGRectGetMaxX(toVc.view.frame), CGRectGetMaxY(toVc.view.frame)); } иначе { // Третий квадрант finalPoint = CGPointMake(CGRectGetMaxX(toVc.view.frame), 0); } } CGPoint startPoint = CGPointMake(button.center.x, button.center.y); // Расчёт向外扩散的 радиус = расстояние от центра кнопки до наиболее отдалённого угла экрана - радиус кнопки 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)]; //Присвоение значения для toVc视图layer's mask CAShapeLayer *maskLayer = [CAShapeLayer слой]; maskLayer.path = endPath.CGPath; toVc.view.layer.mask = maskLayer; CABasicAnimation *maskAnimation =[CABasicAnimation анимация с ключом:@"path"]; maskAnimation.fromValue = (__bridge id)startPath.CGPath; maskAnimation.toValue = (__bridge id)endPath.CGPath; maskAnimation.duration = [self переход продолжительность:transitionContext]; maskAnimation.timingFunction = [CAMediaTimingFunction функция с именем:kCAMediaTimingFunctionEaseInEaseOut]; maskAnimation.delegate = self; [maskLayer добавить анимацию:maskAnimation forKey:@"path"]; }
В контроллере используется метод для создания пользовательских анимаций перехода, чтобы вернуть только что созданный класс анимации.
- (id)nавигационный控制器:(UINavigationController *)навигационный控制器 анимационный контроллер для операции:(UINavigationControllerOperation)операция от ViewController:(UIViewController *)от ViewController до ViewController:(UIViewController *)до ViewController{ если (операция == UINavigationControllerOperationPush) { возврат [LRTranstionAnimationPush новый]; } иначе { возврат nil; } }
Таким образом, пользовательский переход анимации завершен
Анимация pop просто делает push в обратном порядке, не будем углубляться, если у вас есть вопросы, посмотрите код
Добавьте手势 свайп-назад
Как уже говорилось, этот метод добавляет пользовательский интерфейс для этой анимации, поэтому нам нужно реализовать свайп-назад при выводе
Самый простой способ - это использовать класс UIPercentDrivenInteractiveTransition, предоставляемый UIKit, который уже реализует протокол UIViewControllerInteractiveTransitioning, студенты могут использовать объект этого класса для указания процента выполнения перехода анимации.
//Добавьте пользовательский интерфейс для этой анимации - (nullable id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id) animationController NS_AVAILABLE_IOS(7_0);
第一步: Добавьте手势
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; [self.view addGestureRecognizer:gestureRecognizer];
第二步: Определите пропорцию выполнения анимации по изменению手势а пользователя
- (void)handlePan:(UIPanGestureRecognizer *)gestureRecognizer { /*Использование метода updateInteractiveTransition: класса UIPercentDrivenInteractiveTransition позволяет контролировать, до какой степени выполнена анимация перехода, Когда手势下拉完成,调用finishInteractiveTransition или cancelInteractiveTransition, UIKit автоматически выполнит оставшуюся часть анимации, или верните анимацию в начальное состояние.*/ if ([gestureRecognizer translationInView:self.view].x>=0) { //手势滑动的比例 CGFloat per = [gestureRecognizer translationInView:self.view].x / (self.view.bounds.size.width); per = MIN(1.0, (MAX(0.0, per))); если (gestureRecognizer.state == UIGestureRecognizerStateBegan) { self.interactiveTransition = [UIPercentDrivenInteractiveTransition new]; [self.navigationController popViewControllerAnimated:YES]; } иначе если (gestureRecognizer.state == UIGestureRecognizerStateChanged) { если ([gestureRecognizer translationInView:self.view].x == 0) { [self.interactiveTransition updateInteractiveTransition:0.01]; } иначе { [self.interactiveTransition updateInteractiveTransition:per]; } } иначе если (gestureRecognizer.state == UIGestureRecognizerStateEnded || gestureRecognizer.state == UIGestureRecognizerStateCancelled) { если ([gestureRecognizer translationInView:self.view].x == 0) { [self.interactiveTransition cancelInteractiveTransition]; self.interactiveTransition = nil; } иначе если (per > 0.5) { [ self.interactiveTransition finishInteractiveTransition]; } иначе { [ self.interactiveTransition cancelInteractiveTransition]; } self.interactiveTransition = nil; } } иначе если (gestureRecognizer.state == UIGestureRecognizerStateChanged) { [self.interactiveTransition updateInteractiveTransition:0.01]; [self.interactiveTransition cancelInteractiveTransition]; } else if ((gestureRecognizer.state == UIGestureRecognizerStateEnded || gestureRecognizer.state == UIGestureRecognizerStateCancelled)){ self.interactiveTransition = nil; } }
Шаг 3: В методе агента, добавляющем пользовательский интерфейс к анимации, верните экземпляр UIPercentDrivenInteractiveTransition
- (id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id) animationController { return self.interactiveTransition; }
Если это статья была полезна для вас, нажмите "Нравится", спасибо.
Код размещен вGitHubВы можете скачать здесь, конечно, вы также можете черезЛокальное скачивание
Резюме
Вот и все, что есть в этой статье, надеюсь, что содержимое статьи будет иметь определенную ценность для вашего обучения или работы, если у вас есть вопросы, вы можете оставить комментарий для обмена, спасибо за поддержку呐喊 Уроков.
Заявление: содержимое этой статьи взято из Интернета, авторские права принадлежат соответствующему владельцу, содержимое предоставлено пользователями Интернета, веб-сайт не обладает правами собственности, не прошел редактирование, также не несет ответственности за соответствующие юридические последствия. Если вы обнаружите подозрительное содержимое, пожалуйста, отправьте письмо по адресу: notice#oldtoolbag.com (во время отправки письма замените # на @) для сообщения о нарушении,并提供 соответствующие доказательства. Если будет установлено, что содержимое нарушает авторские права, сайт немедленно удаляет подозрительное содержимое.