Анимация изменения контроллеров представления без использования стека контроллера навигации, подпредставлений или модальных контроллеров?
NavigationController имеет стеки ViewController для управления и ограниченные переходы анимации.
Добавление контроллера представления в качестве вспомогательного представления к существующему контроллеру представления требует передачи событий в контроллер вспомогательного просмотра, что является трудной задачей для управления, загружается с небольшим раздражением и в целом выглядит как неудачный взлом при реализации (Apple также рекомендует против делая это).
Представление модального контроллера представления снова помещает контроллер представления поверх другого, и, хотя у него нет проблем передачи событий, описанных выше, он на самом деле не "заменяет" контроллер представления, он укладывает его в стек.
Раскадровки ограничены iOS 5 и почти идеальны, но не могут использоваться во всех проектах.
Может ли кто-нибудь представить ПРИМЕР СОЛИДНОГО КОДА о способе изменения контроллеров представления без вышеуказанных ограничений и допускает анимированные переходы между ними?
Близкий пример, но без анимации: как использовать несколько пользовательских контроллеров представления iOS без контроллера навигации
Редактировать: использование Nav Controller хорошо, но должны быть анимированные стили перехода (а не просто эффекты слайдов), отображаемый контроллер представления должен быть полностью заменен (не сложен). Если второй контроллер представления должен удалить другой контроллер представления из стека, то он недостаточно инкапсулирован.
Редактировать 2: iOS 4 должна быть базовой ОС для этого вопроса, я должен был уточнить это при упоминании раскадровки (выше).
6 ответов
РЕДАКТИРОВАТЬ: Новый ответ, который работает в любой ориентации. Оригинальный ответ работает только тогда, когда интерфейс находится в портретной ориентации. Это анимация перехода вида b/c, которая заменяет вид, и должен иметь место другой вид, с представлениями, по крайней мере, на уровне ниже первого, добавленного в окно (например, window.rootViewController.view.anotherView
).
Я реализовал простой контейнерный класс, который я назвал TransitionController
, Вы можете найти его на https://gist.github.com/1394947.
Кроме того, я предпочитаю реализацию в отдельном классе, потому что его проще использовать повторно. Если вы этого не хотите, вы можете просто реализовать ту же логику непосредственно в делегате приложения, устраняя необходимость в TransitionController
учебный класс. Однако логика, которая вам нужна, будет такой же.
Используйте это следующим образом:
В вашем приложении делегат
// add a property for the TransitionController
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
MyViewController *vc = [[MyViewContoller alloc] init...];
self.transitionController = [[TransitionController alloc] initWithViewController:vc];
self.window.rootViewController = self.transitionController;
[self.window makeKeyAndVisible];
return YES;
}
Для перехода на новый контроллер представления из любого контроллера представления
- (IBAction)flipToView
{
anotherViewController *vc = [[AnotherViewController alloc] init...];
MyAppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
[appDelegate.transitionController transitionToViewController:vc withOptions:UIViewAnimationOptionTransitionFlipFromRight];
}
РЕДАКТИРОВАТЬ: оригинальный ответ ниже - работает только для ориентации портрета
Я сделал следующие предположения для этого примера:
У вас есть контроллер вида, назначенный как
rootViewController
вашего окнаКогда вы переключаетесь на новое представление, вы хотите заменить текущий viewController на viewController, которому принадлежит новое представление. В любое время активен только текущий viewController (например, alloc'ed).
Код может быть легко изменен для работы по-другому, ключевым моментом является анимированный переход и контроллер единого представления. Убедитесь, что вы не сохраняете контроллер представления нигде, кроме назначения его window.rootViewController
,
Код для анимации перехода в приложении делегат
- (void)transitionToViewController:(UIViewController *)viewController
withTransition:(UIViewAnimationOptions)transition
{
[UIView transitionFromView:self.window.rootViewController.view
toView:viewController.view
duration:0.65f
options:transition
completion:^(BOOL finished){
self.window.rootViewController = viewController;
}];
}
Пример использования в контроллере вида
- (IBAction)flipToNextView
{
AnotherViewController *anotherVC = [[AnotherVC alloc] init...];
MyAppDelegate *appDelegate = (MyAppDelegate *)[UIApplication sharedApplication].delegate;
[appDelegate transitionToViewController:anotherVC
withTransition:UIViewAnimationOptionTransitionFlipFromRight];
}
Вы можете использовать новую систему сдерживания viewController от Apple. Для получения более подробной информации ознакомьтесь с видео-сессией WWDC 2011 "Внедрение UIViewController
Сдерживание".
Новое в iOS5, UIViewController
Containment позволяет вам иметь родительский viewController и несколько дочерних viewController, которые содержатся в нем. Вот как работает UISplitViewController. Делая это, вы можете сложить контроллеры представления в родительском, но для вашего конкретного приложения вы просто используете родительский для управления переходом от одного видимого viewController к другому. Это одобренный Apple способ работы, и анимация с помощью одного дочернего viewController безболезненна. Плюс вы можете использовать все различные UIViewAnimationOption
переходы!
Кроме того, с UIViewContainment вам не нужно беспокоиться, если вы не хотите, о беспорядке управления дочерними viewControllers во время событий ориентации. Вы можете просто использовать следующее, чтобы убедиться, что ваш parentViewController перенаправляет события вращения в дочерние viewControllers.
- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers{
return YES;
}
Вы можете сделать следующее или подобное в методе viewDidLoad вашего родителя, чтобы настроить первый childViewController:
[self addChildViewController:self.currentViewController];
[self.view addSubview:self.currentViewController.view];
[self.currentViewController didMoveToParentViewController:self];
[self.currentViewController.swapViewControllerButton setTitle:@"Swap" forState:UIControlStateNormal];
затем, когда вам нужно изменить дочерний viewController, вы вызываете что-то вроде следующего в родительском viewController:
-(void)swapViewControllers:(childViewController *)addChildViewController:aNewViewController{
[self addChildViewController:aNewViewController];
__weak __block ViewController *weakSelf=self;
[self transitionFromViewController:self.currentViewController
toViewController:aNewViewController
duration:1.0
options:UIViewAnimationOptionTransitionCurlUp
animations:nil
completion:^(BOOL finished) {
[aNewViewController didMoveToParentViewController:weakSelf];
[weakSelf.currentViewController willMoveToParentViewController:nil];
[weakSelf.currentViewController removeFromParentViewController];
weakSelf.currentViewController=[aNewViewController autorelease];
}];
}
Я разместил полный пример проекта здесь: https://github.com/toolmanGitHub/stackedViewControllers. Этот другой проект показывает, как использовать UIViewController
Ограничение на несколько различных типов ввода viewController, которые не занимают весь экран. Удачи
Хорошо, я знаю, что вопрос говорит без использования контроллера навигации, но нет причин не делать этого. ОП не отвечала на комментарии вовремя, чтобы я пошла спать. Не голосуй за меня.:)
Вот как вывести текущий контроллер представления и перейти к новому контроллеру представления с помощью контроллера навигации:
UINavigationController *myNavigationController = self.navigationController;
[[self retain] autorelease];
[myNavigationController popViewControllerAnimated:NO];
PreferencesViewController *controller = [[PreferencesViewController alloc] initWithNibName:nil bundle:nil];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration: 0.65];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:myNavigationController.view cache:YES];
[myNavigationController pushViewController:controller animated:NO];
[UIView commitAnimations];
[controller release];
Поскольку я только что натолкнулся на эту точную проблему и попробовал варианты всех ранее существовавших ответов на ограниченный успех, я опубликую, как в конце концов решил ее:
Как описано в этом посте о пользовательских сегментах, на самом деле очень легко создавать собственные сегменты. Их также очень легко подключить в Интерфейсном Разработчике, они поддерживают отношения в IB видимыми и не требуют особой поддержки со стороны контроллеров исходного / целевого вида.
В сообщении, приведенном выше, приведен код iOS 4 для замены текущего контроллера вида сверху в стеке navigationController новым, использующего анимацию скольжения сверху.
В моем случае я хотел, чтобы произошла аналогичная замена, но с FlipFromLeft
переход. Мне также нужна была только поддержка iOS 5+. Код:
Из RAFlipReplaceSegue.h:
#import <UIKit/UIKit.h>
@interface RAFlipReplaceSegue : UIStoryboardSegue
@end
От RAFlipReplaceSegue.m:
#import "RAFlipReplaceSegue.h"
@implementation RAFlipReplaceSegue
-(void) perform
{
UIViewController *destVC = self.destinationViewController;
UIViewController *sourceVC = self.sourceViewController;
[destVC viewWillAppear:YES];
destVC.view.frame = sourceVC.view.frame;
[UIView transitionFromView:sourceVC.view
toView:destVC.view
duration:0.7
options:UIViewAnimationOptionTransitionFlipFromLeft
completion:^(BOOL finished)
{
[destVC viewDidAppear:YES];
UINavigationController *nav = sourceVC.navigationController;
[nav popViewControllerAnimated:NO];
[nav pushViewController:destVC animated:NO];
}
];
}
@end
Теперь, удерживая нажатой клавишу Control, настройте любой другой вид перехода, затем сделайте его "Пользовательским переходом" и введите имя пользовательского класса перехода, et voilà!
Я долго боролся с этим, и одна из моих проблем перечислена здесь, я не уверен, что у вас была эта проблема. Но вот что я бы порекомендовал, если он должен работать с iOS 4.
Во-первых, создать новый NavigationController
учебный класс. Здесь мы сделаем всю грязную работу - другие классы смогут "чисто" вызывать методы экземпляра, такие как pushViewController:
и тому подобное. В вашем .h
:
@interface NavigationController : UIViewController {
NSMutableArray *childViewControllers;
UIViewController *currentViewController;
}
- (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController duration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL))completion;
- (void)addChildViewController:(UIViewController *)childController;
- (void)removeChildViewController:(UIViewController *)childController;
Массив дочерних контроллеров представления будет служить хранилищем для всех контроллеров представления в нашем стеке. Мы будем автоматически пересылать весь код ротации и изменения размера из NavigationController
взгляд на currentController
,
Теперь в нашей реализации:
- (void)transitionFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController duration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL))completion
{
currentViewController = [toViewController retain];
// Put any auto- and manual-resizing handling code here
[UIView animateWithDuration:duration animations:animations completion:completion];
[fromViewController.view removeFromSuperview];
}
- (void)addChildViewController:(UIViewController *)childController {
[childViewControllers addObject:childController];
}
- (void)removeChildViewController:(UIViewController *)childController {
[childViewControllers removeObject:childController];
}
Теперь вы можете реализовать свой собственный pushViewController:
, popViewController
и такие, используя эти вызовы методов.
Удачи, и я надеюсь, что это поможет!
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UINavigationController *viewController = (UINavigationController *)[storyboard instantiateViewControllerWithIdentifier:@"storyBoardIdentifier"];
viewController.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentViewController:viewController animated:YES completion:nil];
Попробуйте этот код.
Этот код дает Переход от контроллера представления к другому контроллеру представления, который имеет контроллер навигации.