2015-05-06 78 views
3

我試圖鏈接兩個不同的視圖控制器在Xcode 6故事板與NSContainerView,以便它們可以有條件地切換。不幸的是,這個教程here沒有任何幫助,因爲事情似乎在Xcode中發生了變化。NSContainerView與Xcode 6中的多個子視圖控制器

所以我有兩個不同的視圖控制器,其中一個默認加載到容器視圖中,但我希望能夠以編程方式將第二個視圖控制器加載到容器視圖中。 Xcode 6只允許在從一個拖拽到另一個時創建嵌入Segues,所以這沒什麼幫助。

有人能告訴我Xcode 6是如何實現的嗎?

+0

,我不知道你是否需要ContainerView其他原因,但如果你只想雙視圖控制器的功能,你可以不同的方法處理它。在Storyboard中創建你的第一個'ViewController的視圖;將其分配爲自定義類;大小任何你需要的組件,給第二個ViewController留下空間。然後在第一個VC代碼中,將第二個VC加載到您剩下的空間中。如果這種方法有幫助,我可以提供代碼片段? – Slowburner

回答

2

首先,這裏是解決方案的示例GitHub項目:click。我不確定你是否想交換視圖,或者只是將第二個視圖推到一個衆所周知的堆棧上,所以我採用了推/拉方案。如果你想交換視圖,你應該能夠通過跳過堆棧存儲相當容易地做到這一點。基本上,我們有我們的「主機」NSViewController,其中包含一個容器視圖(CV)。該主機實際上並不手動管理CV目前正在顯示的視圖控制器。這樣做的方式是,通過一種嵌套的視圖控制器,然後管理所有其他視圖控制器,您將顯示/隱藏/ push/pop/swap /等。 (注意:你可以稍微移除分層,但是從iOS的角度來看,我在故事板屏幕截圖中將'Sub View Controller Manager'視爲UINavigationController)。

我們還利用一些自定義的segues/segue動畫,以便能夠在故事板中做更多的工作。

你只需告訴內容視圖管理器視圖控制器來操縱它的子視圖,使得你想彈出的「舊視圖」被保留(在這種情況下,使用NSMutableArray)等等新視圖有權限frame或正確設置其約束。

以下是故事板的屏幕截圖:enter image description here在示例項目中,您在自定義類型的故事板上看到的每個segue(看起來像這個 - > {})都是SegueBetweenEmbedded。推動按鈕執行一個segue,並且標記爲'Pop'的按鈕在NSViewController上執行dismissController:(這是在故事板中完成的)。

下面是一些代碼(和有很多的,所以我建議在示例項目尋找替代):

ViewController.h

#import <Cocoa/Cocoa.h> 
#import "ContentManagerViewController.h" 

@class ContentManagerViewController; 

@protocol ContentManagerViewControllerHolder <NSObject> 

-(ContentManagerViewController*)retreiveContentManagerController; 

@end 

@interface ViewController : NSViewController <ContentManagerViewControllerHolder> 

@end 

ViewController.m

#import "ViewController.h" 
#import "ContentManagerViewController.h" 
#import "BackForwardViewController.h" 

@interface ViewController() 

@property ContentManagerViewController *vcController; 

-(IBAction)pushViewController:(id)sender; 
-(IBAction)popViewController:(id)sender; 
-(IBAction)popToRootViewController:(id)sender; 

@end 

@implementation ViewController 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view. 
} 

-(void)prepareForSegue:(NSStoryboardSegue *)segue sender:(id)sender { 
    if ([[segue destinationController] class] == [ContentManagerViewController class]) { 
     self.vcController = segue.destinationController; 
    } 
} 

-(ContentManagerViewController*)retreiveContentManagerController { 
    return self.vcController; 
} 

-(IBAction)pushViewController:(id)sender { 
    // note: this works, but then pop is broken via dismissController: since it wasn't done with a segue. 
    // Better way is to rig up a manual segue and execute the segue. 
    //BackForwardViewController *viewController = [[NSStoryboard storyboardWithName:@"Main" bundle:nil] instantiateControllerWithIdentifier:@"BackForwardStoryboardID"]; 
    //[self.vcController push:viewController]; 

    [self performSegueWithIdentifier:@"CustomSegueToBackForward" sender:self]; 
} 

-(IBAction)popViewController:(id)sender { 
    [self.vcController pop]; 
} 

-(IBAction)popToRootViewController:(id)sender { 
    [self.vcController popToRoot]; 
} 

@end 

SegueBetweenEmbedded.h

#import <Cocoa/Cocoa.h> 

@interface SegueBetweenEmbedded : NSStoryboardSegue 

@end 

SegueBetweenEmbedded。米(抱歉不是爲嵌套類抱歉)

#import "SegueBetweenEmbedded.h" 
#import "ContentManagerViewController.h" 
#import "ViewController.h" 

@interface SegueAnimator : NSObject <NSViewControllerPresentationAnimator> 

- (void)animatePresentationOfViewController:(NSViewController *)viewController fromViewController:(NSViewController *)fromViewController; 
- (void)animateDismissalOfViewController:(NSViewController *)viewController fromViewController:(NSViewController *)fromViewController; 

@end 

@implementation SegueAnimator 

- (void)animatePresentationOfViewController:(NSViewController *)viewController fromViewController:(NSViewController *)fromViewController { 
    NSViewController *parent = [fromViewController parentViewController]; 
    if (parent && [parent class] == [ContentManagerViewController class]) { 
     ContentManagerViewController *manager = (ContentManagerViewController*)parent; 
     [manager push:viewController]; 
    } 
    else if ([fromViewController conformsToProtocol:@protocol(ContentManagerViewControllerHolder)]) { 
     id<ContentManagerViewControllerHolder> holder = (id<ContentManagerViewControllerHolder>)fromViewController; 
     [[holder retreiveContentManagerController] push:viewController]; 
    } 
} 

- (void)animateDismissalOfViewController:(NSViewController *)viewController fromViewController:(NSViewController *)fromViewController { 
    NSViewController *parent = [viewController parentViewController]; 
    if ([parent class] == [ContentManagerViewController class]) { 
     ContentManagerViewController *manager = (ContentManagerViewController*)parent; 
     [manager pop]; 
    } 
} 

@end 

@implementation SegueBetweenEmbedded 

- (void)perform { 
    SegueAnimator *animator = [[SegueAnimator alloc] init]; 
    [self.sourceController presentViewController:self.destinationController 
             animator:(id<NSViewControllerPresentationAnimator>)animator]; 
} 

@end 

ContentManagerViewController.h

#import <Cocoa/Cocoa.h> 

@interface ContentManagerViewController : NSViewController 

-(void)push:(NSViewController*)viewController; 
-(void)pop; 
-(void)popToRoot; 

@end 

ContentManagerViewController.m

#import "ContentManagerViewController.h" 
#import "BackForwardViewController.h" 

@interface ContentManagerViewController() 

@property (weak) IBOutlet NSView *subViewControllerManager; 

@property NSViewController *currentViewController; 
@property NSMutableArray<NSViewController*> *viewControllerStack; 

@end 

@implementation ContentManagerViewController 

-(instancetype)init { 
    self = [super init]; 
    self.viewControllerStack = [NSMutableArray array]; 
    return self; 
} 

-(instancetype)initWithCoder:(NSCoder *)coder { 
    self = [super initWithCoder:coder]; 
    self.viewControllerStack = [NSMutableArray array]; 
    return self; 
} 

-(instancetype)initWithNibName:(NSNibName)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { 
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 
    self.viewControllerStack = [NSMutableArray array]; 
    return self; 
} 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
} 

-(void)showViewController:(NSViewController*)viewController { 
    [self addChildViewController:viewController]; 
    viewController.view.frame = self.currentViewController.view.frame; 
    [self.view addSubview:viewController.view]; 
    self.currentViewController = viewController; 
} 

-(void)removeCurrentViewControllerFromView { 
    [self.currentViewController.view removeFromSuperview]; 
    [self.currentViewController removeFromParentViewController]; 
} 

-(void)push:(NSViewController*)viewController { 
    [self removeCurrentViewControllerFromView]; 
    [self.viewControllerStack addObject:viewController]; 
    [self showViewController:viewController]; 
} 

-(void)pop { 
    if (self.viewControllerStack.count > 1) { 
     [self removeCurrentViewControllerFromView]; 
     [self.viewControllerStack removeLastObject]; 
     NSViewController *viewController = [self.viewControllerStack lastObject]; 
     [self showViewController:viewController]; 
    } 
} 

-(void)popToRoot { 
    while (self.viewControllerStack.count > 1) { 
     [self pop]; 
    } 
} 

-(void)prepareForSegue:(NSStoryboardSegue *)segue sender:(id)sender { 
    // this will be called on the initial embed to set up the first view controller 
    self.currentViewController = segue.destinationController; 
    [self.viewControllerStack addObject:segue.destinationController]; 
} 

@end 

BackForwardViewController.h

#import <Cocoa/Cocoa.h> 

@interface BackForwardViewController : NSViewController 

@end 

BackForwardViewController.m

#import "BackForwardViewController.h" 

@interface BackForwardViewController() 

@end 

@implementation BackForwardViewController 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    // Do view setup here. 
} 

@end 
+1

我發現它很有用,謝謝,不過需要類似的東西很快。如果有人需要它 - 在這裏你去:https://github.com/Ruzard/ContainerSequencedView 如果你有提供如何改進它使用迅速技術 - 我將不勝感激。由於缺乏時間進行優化,因此逐行重寫很多 – Ruzard

相關問題