Анимировать изменение контроллеров вида без использования стека навигационных контроллеров, подвидов или модальных контроллеров?


NavigationControllers имеют стеки ViewController для управления и ограниченные переходы анимации.

добавление контроллера вида в качестве подвида к существующему контроллеру вида требует передачи событий в контроллер подвида, что является болью для управления, загружается с небольшими неприятностями и в целом чувствует себя как плохой Хак при реализации (Apple также рекомендует не делать этого).

представление модального контроллера Вида снова помещает контроллер вида поверх другой, и хотя у него нет проблем с прохождением событий, описанных выше, он на самом деле не "меняет" контроллер вида, он складывает его.

раскадровки ограничены iOS 5 и почти идеальны, но не могут использоваться во всех проектах.

может ли кто-нибудь представить твердый пример кода на способе изменения контроллеров вида без вышеуказанных ограничений и позволяет анимировать переходы между ними?

близкий пример, но без анимации: Как использовать несколько прошивкой пользовательские контроллеры вида без навигационного контроллера

Edit: использование навигационного контроллера отлично, но должны быть анимированные стили перехода (а не просто эффекты слайдов) отображаемый контроллер вида должен быть полностью заменен (не сложен). Если второй контроллер вида должен удалить другой контроллер вида из стека, то он недостаточно инкапсулирован.

Edit 2: iOS 4 должна быть базовой ОС для этого вопроса, я должен был уточнить, что когда упоминание раскадровки (выше).

6 140

6 ответов:

EDIT: новый ответ, который работает в любой ориентации. Оригинальный ответ работает только тогда, когда интерфейс находится в портретной ориентации. Это B / c вид анимации перехода, которые заменяют вид ж / другой вид должен происходить с видами по крайней мере на уровне ниже первого вида, добавленного в окно (например window.rootViewController.view.anotherView).

я реализовал простой класс контейнера, который я назвал TransitionController. Вы можете найти его в https://gist.github.com/1394947.

в стороне, я предпочитаю реализацию в отдельном классе b/c легче использовать. Если вы этого не хотите, вы можете просто реализовать ту же логику непосредственно в делегате приложения, устраняя необходимость в 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];
}

EDIT: оригинальный ответ ниже-работает только для ориентации portait

Я сделал следующие предположения для этого примера:

  1. у вас есть представление-контроллер назначен rootViewController окна

  2. при переключении на новое представление вы хотите заменить текущий 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 и ряд дочерних viewControllers, которые содержатся в нем. Вот как работает 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];

поскольку я только что столкнулся с этой точной проблемой и попробовал варианты всех ранее существовавших ответов на ограниченный успех, я опубликую, как я в конечном итоге решил ее:

как описано в этот пост на пользовательские сегменты, это на самом деле очень легко сделать пользовательские переходами. Они также очень легко подключаются в Interface Builder, они сохраняют отношения в IB видимыми, и они не требуют большой поддержки контроллерами представления источника/назначения segue.

сообщение, связанное выше, содержит код iOS 4 для замены текущего контроллера верхнего вида в стеке navigationController на новый, используя анимацию слайдов сверху.

в моем случае, я хотел, чтобы подобный сегмент замены произошел, но с FlipFromLeft переход. Мне также нужна была только поддержка iOS 5+. Код:

От RAFlipReplaceSegue.h:

#import <UIKit/UIKit.h>

@interface RAFlipReplaceSegue : UIStoryboardSegue
@end

От RAFlipReplaceSegue.м:

#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

Теперь, управление-перетащите, чтобы настроить любой другой вид segue, затем сделайте его пользовательским segue и введите имя пользовательского класса segue, и вуаля!

Я долго боролся с этим, и одна из моих проблем указана здесь, Я не уверен, что у вас была эта проблема. Но вот что я бы рекомендовал, если он должен работать с 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];

Попробуйте Этот Код.


этот код дает переход от контроллера вида к другому контроллеру вида, который имеет навигационный контроллер.