#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:
-
Проверьте свою
UIStoryboardSegue
реализацию. Вы использовалиmodalTransitionStyle
опечатку в своем сообщении или в вашем реальном коде? Исправлено:destination.modalPresentationStyle = UIModalPresentationCustom;
-
Я также добился успеха без написания пользовательского
UIStoryboardSegue
. Попробуйте связать метод действия кнопки «размотать на красный» с пустым-unwindToRed:
методом без переопределения-segueForUnwindingToViewController:
(например, CTRL перетащите с кнопки в синем VC на глиф «Exit» синего VC в IB и выберите-unwindToRed:
из списка.) -
Если # 2 не отменяет синий VC, вы можете попробовать вызвать следующее вручную в
-unwindToRed:
методе IBAction:[self dismissViewControllerAnimated:NO completion:nil];