首先,這裏是解決方案的示例GitHub項目:click。我不確定你是否想交換視圖,或者只是將第二個視圖推到一個衆所周知的堆棧上,所以我採用了推/拉方案。如果你想交換視圖,你應該能夠通過跳過堆棧存儲相當容易地做到這一點。基本上,我們有我們的「主機」NSViewController,其中包含一個容器視圖(CV)。該主機實際上並不手動管理CV目前正在顯示的視圖控制器。這樣做的方式是,通過一種嵌套的視圖控制器,然後管理所有其他視圖控制器,您將顯示/隱藏/ push/pop/swap /等。 (注意:你可以稍微移除分層,但是從iOS的角度來看,我在故事板屏幕截圖中將'Sub View Controller Manager'視爲UINavigationController
)。
我們還利用一些自定義的segues/segue動畫,以便能夠在故事板中做更多的工作。
你只需告訴內容視圖管理器視圖控制器來操縱它的子視圖,使得你想彈出的「舊視圖」被保留(在這種情況下,使用NSMutableArray
)等等新視圖有權限frame
或正確設置其約束。
以下是故事板的屏幕截圖:在示例項目中,您在自定義類型的故事板上看到的每個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
,我不知道你是否需要ContainerView其他原因,但如果你只想雙視圖控制器的功能,你可以不同的方法處理它。在Storyboard中創建你的第一個'ViewController的視圖;將其分配爲自定義類;大小任何你需要的組件,給第二個ViewController留下空間。然後在第一個VC代碼中,將第二個VC加載到您剩下的空間中。如果這種方法有幫助,我可以提供代碼片段? – Slowburner