Пользовательская анимация перехода к размотке

#ios #objective-c #animation #transition #segue

#iOS #objective-c #Анимация #переход #segue

Вопрос:

У меня есть следующая настройка:

Идея настройки

У красного контроллера есть метод

 - (IBAction)unwindToRed:(UISegue *)segue
  

и

 - (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier
  

которая возвращает пользовательский переход для этого события.

В моем пользовательском переходе у меня есть следующее в коде выполнения:

 - (void)perform
{
    // Just helpers to get the controllers from the segue
    UIViewController *destination = self.destinationViewController;
    UIViewController *source = self.sourceViewController;

    // Setting transitioning delegate for custom transitions
    destination.transitioningDelegate = self;
    source.transitioningDelegate = self;

    destination.modalTransitionStyle = UIModalPresentationCustom;
    source.modalPresentationStyle = UIModalPresentationCurrentContext;

    // When I am transitioning to a new one
    if(!self.reversed)
    {
        [source presentViewController:destination animated:YES completion:nil];
    }
    // Or reversing from a current one
    else
    {
        [source dismissViewControllerAnimated:YES completion:nil];
    }
}
  

Как вы можете видеть, я настроил делегат перехода, который, в свою очередь, вызывает

 - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
  

на контроллере анимации, где я применяю свою пользовательскую анимацию. Но теперь, когда я нажимаю «Размотать» на красный в желтом представлении, он только «разматывается» на своего родителя. (например, синий).

Когда я оставляю пользовательский переход из уравнения, он работает просто отлично. Она проходит весь путь до вершины.

Теперь я думаю, что это связано с

 [source dismissViewControllerAnimated:YES];
  

строка, поскольку обычно она просто идет «на один», мой вопрос, я думаю, в том, что мне следует вызвать там, чтобы при необходимости она полностью переключалась на красный? Желтый — это модальное наложение. Таким образом, «pop too root» не будет работать.

Комментарии:

1. Как transitionContext выглядит исходный код, пункт назначения, фреймы и контейнер? Я думаю, вам не следует использовать [source dismissViewControllerAnimated:YES]; , вы должны просто вызвать [transitionContext completeTransition:YES];

Ответ №1:

Задание пользовательского перехода

Решение состояло в том, чтобы использовать пользовательский переход для размотки. К сожалению, вы не можете указать пользовательский переход для размотки в interface builder, как вы можете для обычного перехода. Вы должны указать это с помощью кода.

Существует функция, UIViewController которую вы можете переопределить, вызываемая segueForUnwindingToViewController , которая указывает, какой переход использовать для размотки. Сложная часть заключается в том, чтобы знать, на каком контроллере просмотра переопределить эту функцию. Ответ заключается в том, чтобы сделать это на родительском из контроллеров просмотра, к которым вы переходите. В моем случае это UINavigationController . Навигационный контроллер является контроллером представления контейнера для первого и третьего контроллеров представления. Если бы у меня были встроенные дочерние контроллеры просмотра в моих представлениях, то ответом был бы не навигационный контроллер, а родительский контроллер просмотра.

Создайте пользовательский навигационный контроллер, унаследовав от UINavigationController . Затем обязательно установите пользовательский класс вашего навигационного контроллера в interface builder. Теперь вы можете переопределить segueForUnwindingToViewController функцию. Вот минимальная реализация.

 class MyNavigationController: UINavigationController {
    override func segueForUnwindingToViewController(toViewController: UIViewController,
                                                    fromViewController: UIViewController,
                                                    identifier: String?) -> UIStoryboardSegue {
        return UIStoryboardSegue(identifier: identifier, source: fromViewController, destination: toViewController)
    }
}
  

Добавление анимации в пользовательский переход

 override func segueForUnwindingToViewController(toViewController: UIViewController,
                                                    fromViewController: UIViewController,
                                                    identifier: String?) -> UIStoryboardSegue {
        return UIStoryboardSegue(identifier: identifier, source: fromViewController, destination: toViewController) {
            let fromView = fromViewController.view
            let toView = toViewController.view
            if let containerView = fromView.superview {
                let initialFrame = fromView.frame
                var offscreenRect = initialFrame
                offscreenRect.origin.x -= CGRectGetWidth(initialFrame)
                toView.frame = offscreenRect
                containerView.addSubview(toView)
                // Being explicit with the types NSTimeInterval and CGFloat are important
                // otherwise the swift compiler will complain
                let duration: NSTimeInterval = 1.0
                let delay: NSTimeInterval = 0.0
                let options = UIViewAnimationOptions.CurveEaseInOut
                let damping: CGFloat = 0.5
                let velocity: CGFloat = 4.0
                UIView.animateWithDuration(duration, delay: delay, usingSpringWithDamping: damping,
                        initialSpringVelocity: velocity, options: options, animations: {
                    toView.frame = initialFrame
                }, completion: { finished in
                    toView.removeFromSuperview()
                    if let navController = toViewController.navigationController {
                        navController.popToViewController(toViewController, animated: false)
                    }
                })
            }
        }
    }
  

Подробности из этого поста

Комментарии:

1. segueForUnwindingToViewController(to:from:identifier:) была устаревшей в iOS10.

2. и теперь вы можете указать пользовательский класс для размотки

Ответ №2:

Вы хотите использовать popToViewController навигационного контроллера:

  [source.navigationController popToViewController:destination animated:YES];
  

или используйте animated:NO и поместите все это в блок анимации: например:

 UIViewAnimationOptions animation  = UIViewAnimationOptionTransitionFlipFromRight | UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowAnimatedContent;

UIViewController *source = (UIViewController *) self.sourceViewController;
UIViewController *dest = (UIViewController *) self.destinationViewController;


[UIView transitionWithView:src.navigationController.view duration:0.4
                   options: animation
                animations:^{
                    [source.navigationController popToViewController:dest animated:NO];
                }
                completion:^(BOOL finished) {
                }];
  

Ответ №3:

  1. Проверьте свою UIStoryboardSegue реализацию. Вы использовали modalTransitionStyle опечатку в своем сообщении или в вашем реальном коде? Исправлено:

     destination.modalPresentationStyle = UIModalPresentationCustom;
      
  2. Я также добился успеха без написания пользовательского UIStoryboardSegue . Попробуйте связать метод действия кнопки «размотать на красный» с пустым -unwindToRed: методом без переопределения -segueForUnwindingToViewController: (например, CTRL перетащите с кнопки в синем VC на глиф «Exit» синего VC в IB и выберите -unwindToRed: из списка.)

  3. Если # 2 не отменяет синий VC, вы можете попробовать вызвать следующее вручную в -unwindToRed: методе IBAction:

     [self dismissViewControllerAnimated:NO completion:nil];