Навигационный контроллер пользовательская анимация перехода
Я следил за некоторыми учебниками по созданию пользовательской анимации при переходе от одного вида к другому.
мой тестовый проект с использованием пользовательского segue from здесь отлично работает, но кто-то сказал мне, что больше не рекомендуется делать пользовательскую анимацию в пользовательском сегменте, и я должен использовать UIViewControllerAnimatedTransitioning
.
Я следил за несколькими учебниками, которые используют этот протокол, но все они касаются модального представления (например этот учебник).
то, что я пытаюсь сделать, это push-сегмент внутри дерева навигационного контроллера, но когда я пытаюсь сделать то же самое с show (push) segue, он больше не работает.
Пожалуйста, скажите мне правильный способ сделать пользовательские анимации перехода из одного вида в другой в контроллер навигации.
и есть ли в любом случае я могу использовать один метод для всех переходных анимаций? Было бы неловко, если однажды я хочу сделать ту же анимацию, но конец пришлось дублировать два раза этот код, чтобы работать на режимный регулятор против перехода.
4 ответа:
чтобы сделать пользовательский переход с навигационным контроллером (
UINavigationController
), вы должны:
определить ваш контроллер представления, чтобы соответствовать
UINavigationControllerDelegate
протокол. Например, вы можете иметь расширение частного класса в контроллере вида.m
файл, который указывает соответствие этому протоколу:@interface ViewController () <UINavigationControllerDelegate> @end
убедитесь, что вы действительно указали свой контроллер вида в качестве навигационного контроллера делегат:
- (void)viewDidLoad { [super viewDidLoad]; self.navigationController.delegate = self; }
реализовать
animationControllerForOperation
в вашем контроллере вида:- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController*)fromVC toViewController:(UIViewController*)toVC { if (operation == UINavigationControllerOperationPush) return [[PushAnimator alloc] init]; if (operation == UINavigationControllerOperationPop) return [[PopAnimator alloc] init]; return nil; }
реализовать аниматоры для push и pop анимации, например:
@interface PushAnimator : NSObject <UIViewControllerAnimatedTransitioning> @end @interface PopAnimator : NSObject <UIViewControllerAnimatedTransitioning> @end @implementation PushAnimator - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext { return 0.5; } - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext { UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; [[transitionContext containerView] addSubview:toViewController.view]; toViewController.view.alpha = 0.0; [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{ toViewController.view.alpha = 1.0; } completion:^(BOOL finished) { [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; }]; } @end @implementation PopAnimator - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext { return 0.5; } - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext { UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; [[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view]; [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{ fromViewController.view.alpha = 0.0; } completion:^(BOOL finished) { [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; }]; } @end
это действительно исчезает переход, но вы должны чувствовать себя свободно, чтобы настроить анимацию, как вы считаете нужным.
если вы хотите обрабатывать интерактивные жесты (например, что-то вроде собственного салфетки слева направо, чтобы поп), вы должны реализовать контроллер взаимодействия:
определить свойство для контроллера взаимодействия (объект, который соответствует
UIViewControllerInteractiveTransitioning
):@property (nonatomic, strong) UIPercentDrivenInteractiveTransition *interactionController;
этой
UIPercentDrivenInteractiveTransition
это хороший объект, который делает тяжелую работу по обновлению пользовательской анимации на основе того, насколько полным является жест.добавить распознаватель жестов к вашему представлению. Здесь я просто реализую распознаватель левого жеста для имитации поп:
UIScreenEdgePanGestureRecognizer *edge = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFromLeftEdge:)]; edge.edges = UIRectEdgeLeft; [view addGestureRecognizer:edge];
реализовать обработчик распознавания жестов:
/** Handle swipe from left edge * * This is the "action" selector that is called when a left screen edge gesture recognizer starts. * * This will instantiate a UIPercentDrivenInteractiveTransition when the gesture starts, * update it as the gesture is "changed", and will finish and release it when the gesture * ends. * * @param gesture The screen edge pan gesture recognizer. */ - (void)handleSwipeFromLeftEdge:(UIScreenEdgePanGestureRecognizer *)gesture { CGPoint translate = [gesture translationInView:gesture.view]; CGFloat percent = translate.x / gesture.view.bounds.size.width; if (gesture.state == UIGestureRecognizerStateBegan) { self.interactionController = [[UIPercentDrivenInteractiveTransition alloc] init]; [self popViewControllerAnimated:TRUE]; } else if (gesture.state == UIGestureRecognizerStateChanged) { [self.interactionController updateInteractiveTransition:percent]; } else if (gesture.state == UIGestureRecognizerStateEnded) { CGPoint velocity = [gesture velocityInView:gesture.view]; if (percent > 0.5 || velocity.x > 0) { [self.interactionController finishInteractiveTransition]; } else { [self.interactionController cancelInteractiveTransition]; } self.interactionController = nil; } }
в делегате навигационного контроллера вы также должны реализовать
interactionControllerForAnimationController
метод- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController { return self.interactionController; }
если вы google" UINavigationController custom transition tutorial", и вы получите много хитов. Или увидеть WWDC 2013 пользовательские переходы видео.
вы можете добавить следующий код перед
addSubview
toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController];
другой вопрос таможни-переход на пуш-анимации-с-navigationcontroller-на-СВН-9
из документации Apple для finalFrameForViewController:
возвращает прямоугольник конечного кадра для указанного контроллера вида вид.
прямоугольник, возвращаемый этим методом, представляет размер соответствующее представление в конец перехода. Для представления рассмотренное во время презентации значение, возвращаемое этим методом может быть CGRectZero, но это также может быть допустимый прямоугольник кадра.
используя идеальные ответы Роба и Q i, вот упрощенный Swift-код, используя ту же анимацию fade.нажать и. поп:
extension YourViewController: UINavigationControllerDelegate { func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { //INFO: use UINavigationControllerOperation.push or UINavigationControllerOperation.pop to detect the 'direction' of the navigation class FadeAnimation: NSObject, UIViewControllerAnimatedTransitioning { func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.5 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) if let vc = toViewController { transitionContext.finalFrame(for: vc) transitionContext.containerView.addSubview(vc.view) vc.view.alpha = 0.0 UIView.animate(withDuration: self.transitionDuration(using: transitionContext), animations: { vc.view.alpha = 1.0 }, completion: { finished in transitionContext.completeTransition(!transitionContext.transitionWasCancelled) }) } else { NSLog("Oops! Something went wrong! 'ToView' controller is nill") } } } return FadeAnimation() } }
Не забудьте установить делегат в методе viewDidLoad() вашего ViewController:
override func viewDidLoad() { //... self.navigationController?.delegate = self //... }
Он работает как swift 3 и 4
@IBAction func NextView(_ sender: UIButton) { let newVC = self.storyboard?.instantiateViewControllerWithIdentifier(withIdentifier: "NewVC") as! NewViewController let transition = CATransition() transition.duration = 0.5 transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) transition.type = kCATransitionPush transition.subtype = kCAGravityLeft //instead "kCAGravityLeft" try with different transition subtypes self.navigationController?.view.layer.add(transition, forKey: kCATransition) self.navigationController?.pushViewController(newVC, animated: false) }