gpt4 book ai didi

macos - Xcode 6 中具有多个 subview Controller 的 NSContainerView

转载 作者:行者123 更新时间:2023-12-03 16:13:25 25 4
gpt4 key购买 nike

我正在尝试将 Xcode 6 Storyboard 中的两个不同的 View Controller 与 NSContainerView 链接起来,以便可以有条件地切换它们。不幸的是这个教程here没有任何帮助,因为自从 Xcode 中以来事情似乎已经发生了变化。

所以我有两个不同的 View Controller ,其中一个默认加载到容器 View 中,但我希望能够以编程方式将第二个 View Controller 加载到容器 View 中。 Xcode 6 仅允许在我从一个拖动到另一个时创建嵌入 Segue,因此这没有太大帮助。

有人可以告诉我这是如何使用 Xcode 6 实现的吗?

最佳答案

首先,这是解决方案的示例 GitHub 项目:click 。我不确定您是想交换 View 还是只是将第二个 View 推到众所周知的堆栈上,所以我采用了推/弹出方案。如果您想交换 View ,您应该能够通过跳过堆栈存储来相当轻松地做到这一点。

本质上,我们有一个“主机”NSViewController,它内部包含一个容器 View (CV)。该主机实际上并不手动管理 CV 当前显示的 View Controller 。完成此操作的方法是通过一种嵌套 View Controller ,然后管理您要显示/隐藏/推送/弹出/交换等的所有其他 View Controller 。 (注意:您也许可以稍微删除分层,但就 iOS 而言,我将 Storyboard屏幕截图中的“ subview Controller 管理器”视为 UINavigationController )。

我们还利用一些自定义转场/转场动画师,以便能够在 Storyboard中完成更多工作。

您只需告诉内容 View 管理器 View Controller 以这样的方式操作其 subview ,即保留您想要弹出“返回”的旧 View (在本例中,使用 NSMutableArray )等等新观点有权利frame或者正确设置它们的约束。

这是 Storyboard的屏幕截图:enter image description here您在自定义类型的 Storyboard上看到的每个 Segue(看起来像这样 -> { } )的类型都是 SegueBetweenEmbedded在示例项目中。按下的按钮执行 segue,标记为“Pop”的按钮执行 dismissController:关于NSViewController (所以这是在 Storyboard中完成的)。

这里有一些代码(代码很多,所以我建议查看示例项目):

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.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

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

关于macos - Xcode 6 中具有多个 subview Controller 的 NSContainerView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30071264/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com