Bad*_*Cat 4 macos cocoa nsviewcontroller xcode6
我正在尝试将Xcode 6故事板上的两个不同的视图控制器与链接起来,NSContainerView以便可以有条件地切换它们。不幸的是,这里的本教程没有任何帮助,因为自Xcode以来,情况似乎已发生变化。
因此,我有两个不同的视图控制器,默认情况下其中一个已加载到容器视图中,但是我希望能够以编程方式将第二个视图控制器加载到容器视图中。Xcode 6仅允许在我从一个拖动到另一个时创建嵌入Segues,所以并没有太大帮助。
有人可以告诉我Xcode 6是如何实现的吗?
首先,这是该解决方案的示例GitHub项目:单击。我不确定是要交换视图还是将第二个视图推入一个众所周知的堆栈,所以我采用了推/弹出方案。如果您想交换视图,则只需跳过堆栈存储,就可以轻松地做到这一点。
本质上,我们有一个“主机” NSViewController,其中包含一个容器视图(CV)。该主机实际上并没有手动管理CV目前正在显示的视图控制器。好的方法是通过一种嵌套的视图控制器,然后管理要显示/隐藏/推送/ pop / swap / etc的所有其他视图控制器。(请注意:您也许可以删除一些分层,但是用iOS术语来说,我正在情节提要中将“ Sub View Controller Manager”当作情节提要截图中的一种UINavigationController)。
我们还利用了一些自定义的segues / segue动画师,以便能够在情节提要中做更多的工作。
您只需要告诉内容视图管理器视图控制器以某种方式操作其子视图,即可保留要弹出的“旧”旧视图(在这种情况下,使用NSMutableArray),并使新视图具有权利frame或适当设置约束条件。
这是情节提要的屏幕截图:
您在自定义类型的情节提要上看到的每个segue都是SegueBetweenEmbedded示例项目中的类型。按下按钮会执行顺序,而标记为“ Pop”的按钮将在dismissController:上执行NSViewController(因此在情节提要中完成)。
这是一些代码(其中有很多,所以我建议改为看示例项目):
ViewController.h
#import <Cocoa/Cocoa.h>
#import "ContentManagerViewController.h"
@class ContentManagerViewController;
@protocol ContentManagerViewControllerHolder <NSObject>
-(ContentManagerViewController*)retreiveContentManagerController;
@end
@interface ViewController : NSViewController <ContentManagerViewControllerHolder>
@end
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
SegueBetweenEmbedded.h
#import <Cocoa/Cocoa.h>
@interface SegueBetweenEmbedded : NSStoryboardSegue
@end
Run Code Online (Sandbox Code Playgroud)
SegueBetweenEmbedded.m(对不起嵌套类,对不起)
#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
Run Code Online (Sandbox Code Playgroud)
ContentManagerViewController.h
#import <Cocoa/Cocoa.h>
@interface ContentManagerViewController : NSViewController
-(void)push:(NSViewController*)viewController;
-(void)pop;
-(void)popToRoot;
@end
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
BackForwardViewController.h
#import <Cocoa/Cocoa.h>
@interface BackForwardViewController : NSViewController
@end
Run Code Online (Sandbox Code Playgroud)
BackForwardViewController.m
#import "BackForwardViewController.h"
@interface BackForwardViewController ()
@end
@implementation BackForwardViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do view setup here.
}
@end
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2584 次 |
| 最近记录: |