簡體   English   中英

在不使用導航控制器堆棧,子視圖或模態控制器的情況下更改視圖控制器的動畫?

[英]Animate change of view controllers without using navigation controller stack, subviews or modal controllers?

NavigationControllers具有ViewController堆棧來管理和限制動畫過渡。

將視圖控制器作為子視圖添加到現有視圖控制器需要將事件傳遞給子視圖控制器,這很難管理,幾乎沒有煩惱,並且通常在實現時感覺像是一個糟糕的黑客(Apple也建議不要這樣做)。

呈現模式視圖控制器再次將視圖控制器放在另一個上面,雖然它沒有上面描述的事件傳遞問題,但它並沒有真正“交換”視圖控制器,而是堆疊它。

故事板僅限於iOS 5,幾乎是理想的,但不能在所有項目中使用。

有人可以在沒有上述限制的情況下更改視圖控制器的方式提供一個SOLID代碼示例,並允許它們之間的動畫過渡?

一個接近的例子,但沒有動畫: 如何在沒有導航控制器的情況下使用多個iOS自定義視圖控制器

編輯:導航控制器使用很好,但需要動畫過渡樣式(不僅僅是幻燈片效果)顯示的視圖控制器需要完全交換(不是堆疊)。 如果第二個視圖控制器必須從堆棧中刪除另一個視圖控制器,那么它的封裝不夠。

編輯2:iOS 4應該是這個問題的基本操作系統,我應該在提到故事板時澄清(上圖)。

編輯:適用於任何方向的新答案。 原始答案僅在界面處於縱向時才有效。 這是b / c視圖轉換動畫,用於替換具有不同視圖的視圖必須在視圖至少低於添加到窗口的第一個視圖的某個級別(例如window.rootViewController.view.anotherView )。

我已經實現了一個名為TransitionController的簡單容器類。 您可以在https://gist.github.com/1394947找到它。

順便說一句,我更喜歡在單獨的類b / c中實現它更容易重用。 如果您不想這樣,您可以直接在您的app委托中實現相同的邏輯,從而無需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];
}

編輯:下面的原始答案 - 僅適用於肖像方向

我為這個例子做了以下假設:

  1. 您有一個視圖控制器被指定為窗口的rootViewController

  2. 當您切換到新視圖時,您希望將當前viewController替換為擁有新視圖的viewController。 在任何時候,只有當前的viewController是活的(例如,alloc'ed)。

代碼可以很容易地修改為不同的工作,關鍵點是動畫過渡和單視圖控制器。 確保在將窗口分配給window.rootViewController之外的任何地方都不保留視圖控制器。

用於在app委托中設置轉換動畫的代碼

- (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];
}

您可以使用Apple的新viewController包含系統。 有關更深入的信息,請查看WWDC 2011會話視頻“實現UIViewController遏制”。

iOS5新增功能, UIViewController Containment允許您擁有父視圖控制器和包含在其中的多個子視圖控制器。 這就是UISplitViewController的工作原理。 這樣做可以在父級中堆疊視圖控制器,但對於您的特定應用程序,您只需使用父級來管理從一個可見的viewController到另一個的可見視圖控制器的轉換。 這是Apple批准的做事方式和動畫從一個孩子viewController是無痛的。 另外,您可以使用各種不同的UIViewAnimationOption過渡!

此外,使用UIViewContainment,除非您想要了解在定向事件期間管理子視圖控制器的混亂,否則您不必擔心。 您只需使用以下命令確保您的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 這個其他項目展示了如何在一些不占用整個屏幕的各種輸入viewController類型上使用UIViewController Containment。 祝好運

好的,我知道這個問題沒有使用導航控制器,但沒有理由不這樣做。 OP沒有及時回應我的睡覺時間。 不要投票給我。 :)

以下是使用導航控制器彈出當前視圖控制器並翻轉到新視圖控制器的方法:

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];

由於我剛剛遇到了這個確切的問題,並嘗試了所有預先存在的有限成功答案的變體,我將發布我最終如何解決它:

正如本文關於自定義segues的描述,實際上很容易制作自定義segues。 它們也非常容易在Interface Builder中連接,它們使IB中的關系可見,並且它們不需要segue的源/目標視圖控制器的大量支持。

上面鏈接的帖子提供了iOS 4代碼,使用從上到下滑動的動畫替換了navigationController堆棧上的當前頂視圖控制器。

在我的情況下,我想要一個類似的替換segue發生,但有一個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

現在,控制 - 拖動以設置任何其他類型的segue,然后將其設置為Custom segue,並輸入自定義segue類的名稱,etvoilà!

我很長一段時間都在努力解決這個問題,我的一個問題列在這里 ,我不確定你是否遇到過這個問題。 但如果它必須適用於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];

試試此代碼。


此代碼提供從視圖控制器到另一個具有導航控制器的視圖控制器的轉換。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM