[iphone] 네비게이션 컨트롤러 스택, 서브 뷰 또는 모달 컨트롤러를 사용하지 않고 뷰 컨트롤러의 애니메이션 변경?

NavigationController에는 관리 할 ViewController 스택과 제한된 애니메이션 전환이 있습니다.

기존의보기 컨트롤러에 하위보기로보기 컨트롤러를 추가하려면 이벤트를 하위보기 컨트롤러에 전달해야합니다. 하위보기 컨트롤러는 관리하기가 어렵고 약간의 성가심으로로드되며 일반적으로 구현시 나쁜 해킹처럼 느껴집니다 (Apple은 이 작업을 수행).

모달 뷰 컨트롤러를 다시 표시하면 뷰 컨트롤러가 다른 뷰 컨트롤러 위에 배치되며 위에서 설명한 이벤트 전달 문제가 없지만 실제로는 뷰 컨트롤러를 ‘스왑’하지 않고 스택합니다.

스토리 보드는 iOS 5로 제한되며 거의 이상적이지만 모든 프로젝트에서 사용할 수는 없습니다.

위의 제한없이 뷰 컨트롤러를 변경하고 애니메이션 전환을 허용하는 방법으로 SOLID CODE EXAMPLE을 제시 할 수 있습니까?

가까운 예제이지만 애니메이션은 없음 :
탐색 컨트롤러없이 여러 iOS 사용자 정의보기 컨트롤러를 사용하는 방법

편집 : Nav Controller 사용은 좋지만 슬라이드 효과가 아닌 애니메이션 전환 스타일이 있어야합니다.보기 컨트롤러가 완전히 스왑되어야합니다 (스택되지 않음). 두 번째 뷰 컨트롤러가 스택에서 다른 뷰 컨트롤러를 제거해야하는 경우 캡슐화되지 않은 것입니다.

편집 2 : iOS 4 가이 질문의 기본 OS 여야합니다. 스토리 보드를 언급 할 때 위의 내용을 분명히 했어야합니다.



답변

편집 : 모든 방향에서 작동하는 새로운 답변.
원래 답변은 인터페이스가 세로 방향 일 때만 작동합니다. 이것은 다른 뷰가있는 뷰를 대체하는 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];
}

편집 : 아래의 원래 답변-portait 방향에서만 작동합니다

이 예제에서는 다음과 같은 가정을했습니다.

  1. rootViewController창에 뷰 컨트롤러가 할당되어 있습니다.

  2. 새보기로 전환하면 현재 viewController를 새보기를 소유 한 viewController로 바꾸려고합니다. 언제든지 현재 viewController 만 활성화됩니다 (예 : 할당 됨).

코드는 다르게 작동하도록 쉽게 수정할 수 있습니다. 요점은 애니메이션 전환 및 단일 뷰 컨트롤러입니다. 뷰 컨트롤러를에 할당하는 것 외에는 아무 곳에 나 보관하지 마십시오 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];
}


답변

Apple의 새로운 viewController 격리 시스템을 사용할 수 있습니다. 보다 자세한 정보는 WWDC 2011 세션 비디오 “Implementing UIViewControllerContainment”를 확인하십시오.

iOS5에 새로 도입 된 UIViewControllerContainment를 사용하면 부모 viewController와 그 안에 포함 된 여러 자식 viewController를 가질 수 있습니다. 이것이 UISplitViewController의 작동 방식입니다. 이렇게하면 뷰 컨트롤러를 부모에 스택 할 수 있지만 특정 응용 프로그램의 경우 부모를 사용하여 하나의 보이는 viewController에서 다른 viewController 로의 전환을 관리하고 있습니다. 이것은 애플이 승인 한 일을하고 하나의 자식 viewController에서 애니메이션을 만드는 방법입니다. 또한 다양한 UIViewAnimationOption전환을 모두 사용할 수 있습니다 !

또한 UIViewContainment를 사용하면 오리엔테이션 이벤트 중에 자식 viewController를 관리해야하는 지저분함에 대해 걱정할 필요가 없습니다. 다음을 사용하여 parentViewController가 회전 이벤트를 자식 viewController로 전달하도록 할 수 있습니다.

- (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 유형에서 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대한 게시물에서 설명했듯이 실제로 사용자 정의 segue를 만드는 것은 실제로 쉽습니다. 또한 Interface Builder에서 매우 쉽게 연결할 수 있으며 IB의 관계를 계속 볼 수 있으며 segue의 소스 / 대상 뷰 컨트롤러에서 많은 지원을 필요로하지 않습니다.

위에 링크 된 게시물은 내비게이션 컨트롤러 스택의 현재 상단 뷰 컨트롤러를 슬라이드-인-투-탑 애니메이션을 사용하여 새 것으로 교체하기위한 iOS 4 코드를 제공합니다.

필자의 경우 비슷한 교체 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

이제 Control- 드래그하여 다른 종류의 segue를 설정 한 다음 Custom segue로 만들고 custom 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];

이 코드를 사용해보십시오.


이 코드는 뷰 컨트롤러에서 내비게이션 컨트롤러가있는 다른 뷰 컨트롤러로의 전환을 제공합니다.


답변