如何以编程方式展开和折叠部分NSSplitView?

时间:2021-05-19 12:36:47

I want to replace RBSplitView with NSSplitView in my existing project. The application is now leopard only and I would like to replace RBSplitView with the new NSSplitView shipped with Leopard.

我想在我现有的项目中用NSSplitView替换RBSplitView。该应用程序现在只有豹子,我想用Leopard附带的新NSSplitView替换RBSplitView。

However, I'm missing RBSplitView's handy methods expand and collapse in NSSplitView. How can I expand and collapse parts of NSSplitView programmatically?

但是,我缺少RBSplitView的方便方法在NSSplitView中展开和折叠。如何以编程方式展开和折叠部分NSSplitView?

10 个解决方案

#1


I just got programmatic expanding and collapsing of NSSplitView to work. I've also configured my NSSplitView to expand/collapse a subview whenever the divider is double-clicked, so I wanted this to play nice with that feature (and it seems to). This is what I did:

我只是编程扩展和折叠NSSplitView工作。我还配置了我的NSSplitView,以便在双击分割器时展开/折叠子视图,所以我希望这对于该功能很好玩(而且似乎)。这就是我做的:

(in this example, splitView is the NSSplitView itself, splitViewSubViewLeft is the subview I wish to expand/collapse and lastSplitViewSubViewLeftWidth is an instance variable of type CGFloat.)

(在此示例中,splitView是NSSplitView本身,splitViewSubViewLeft是我希望展开/折叠的子视图,lastSplitViewSubViewLeftWidth是CGFloat类型的实例变量。)

// subscribe to splitView's notification of subviews resizing
// (I do this in -(void)awakeFromNib)
[[NSNotificationCenter defaultCenter]
 addObserver:self
 selector:@selector(mainSplitViewWillResizeSubviewsHandler:)
 name:NSSplitViewWillResizeSubviewsNotification
 object:splitView
 ];

// this is the handler the above snippet refers to
- (void) mainSplitViewWillResizeSubviewsHandler:(id)object
{
    lastSplitViewSubViewLeftWidth = [splitViewSubViewLeft frame].size.width;
}

// wire this to the UI control you wish to use to toggle the
// expanded/collapsed state of splitViewSubViewLeft
- (IBAction) toggleLeftSubView:(id)sender
{
    [splitView adjustSubviews];
    if ([splitView isSubviewCollapsed:splitViewSubViewLeft])
        [splitView
         setPosition:lastSplitViewSubViewLeftWidth
         ofDividerAtIndex:0
         ];
    else
        [splitView
         setPosition:[splitView minPossiblePositionOfDividerAtIndex:0]
         ofDividerAtIndex:0
         ];
}

#2


Simply hide the subview you want to collapse, e.g.

只需隐藏您要折叠的子视图,例如

[aSubViewToCollapse setHidden:YES];

You might also want to implement the delegate method -(BOOL)splitView:shouldHideDividerAtIndex: to return YES to hide the divider when a collapsed.

您可能还希望实现委托方法 - (BOOL)splitView:shouldHideDividerAtIndex:返回YES以在折叠时隐藏分隔符。

#3


I tried the solution above, and found it did not work, as isSubviewCollapsed never returned YES

我尝试了上面的解决方案,发现它不起作用,因为isSubviewCollapsed从未返回YES

A combination of the suggestions yielded a result which works

这些建议的组合产生了有效的结果

if ([splitViewTop isHidden]) {
    [splitViewTop setHidden:NO];
    [split
     setPosition:previousSplitViewHeight
     ofDividerAtIndex:0];
}
else {
    [splitViewTop setHidden:YES];
}
[split adjustSubviews];

#4


After some experimenting with the suggestions this was the easiest solution I found:

在尝试了一些建议之后,这是我发现的最简单的解决方案:

-(void)toggleCollapsibleView:(ib)sender {
   [collapsibleView setHidden:![splitView isSubviewCollapsed:collapsibleView]];
   [splitView adjustSubviews];
}

The function is a user defined first-responder action. It is triggered by a menu-item (or keystroke). The collapsibleView is a subview in the splitView both of which are connected in IB with their properties.

该功能是用户定义的第一响应者操作。它由菜单项(或按键)触发。 collapsibleView是splitView中的子视图,它们都在IB中与其属性相连。

#5


In El Capitan, this did the trick for me.

在El Capitan,这对我有用。

splitViewItem.collapsed = YES;

#6


NSSplitView actually has a private method -(void)_setSubview:(NSView *)view isCollapsed:(BOOL)collapsed that does this. Those who would like to ignore all warnings against using private methods, behold:

NSSplitView实际上有一个私有方法 - (void)_setSubview :( NSView *)视图isCollapsed:(BOOL)折叠执行此操作。那些想忽略所有使用私有方法的警告的人,看哪:

- (void)toggleSubview:(NSView *)view {
    SEL selector = @selector(_setSubview:isCollapsed:);
    NSMethodSignature *signature = [NSSplitView instanceMethodSignatureForSelector:selector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = selector;
    [invocation setArgument:&view atIndex:2];
    BOOL arg = ![self isSubviewCollapsed:view];
    [invocation setArgument:&arg atIndex:3];
    [invocation invoke];
}

I implemented this as a category on NSSplitView. The only issue is that Xcode gives a warning about _setSubview:isCollapsed: being undeclared... I'm not really sure how to get around that.

我在NSSplitView上将其实现为一个类别。唯一的问题是Xcode给出了关于_setSubview的警告:isCollapsed:未申报......我真的不确定如何解决这个问题。


El Capitan Update

El Capitan更新

I haven't written any code for OS X in ~2 years now so I haven't been able to verify this, but according to lemonmojo in the comments below, _setSubview:isCollapsed: was renamed in El Capitan to _setArrangedView:isCollapsed:.

我在2年内没有为OS X编写任何代码所以我无法验证这一点,但根据下面评论中的lemonmojo,_setSubview:isCollapsed:在El Capitan中重命名为_setArrangedView:isCollapsed:。

#7


In macOS Sierra, the collapsed property is changed to isCollapsed. Is straight forward just setting the property to true or false. The following code is from my WindowController, where I have two SplitViewItems.

在macOS Sierra中,折叠的属性更改为isCollapsed。直接将属性设置为true或false。以下代码来自我的WindowController,我有两个SplitViewItems。

@IBAction func toggleMap(_ sender: Any) {
    if let splitViewController = contentViewController as? NSSplitViewController {
        let splitViewItem = splitViewController.splitViewItems
        if splitViewItem.first!.isCollapsed {
            splitViewItem.first!.isCollapsed = false
        } else if splitViewItem.last!.isCollapsed {
            splitViewItem.last!.isCollapsed = false
        } else {
            if splitViewItem.first!.isCollapsed {
                splitViewItem.first!.isCollapsed = false
            }
            splitViewItem.last!.isCollapsed = true
        }
    }
}

#8


In swift this works

在迅捷这是有效的

func togglePanel() {
    let splitViewItem = self.mySplitView.arrangedSubviews

    if mySplitView.isSubviewCollapsed(outline.view){
        splitViewItem[0].hidden = false
    } else {
        splitViewItem[0].hidden = true
    }

call this from IBAction, outline is an OutlineViewController with own xib and we need the view hence outline.view, keeping it simple but hope you get the idea

从IBAction调用这个,outline是一个带有自己的xib的OutlineViewController,我们需要视图,因此outline.view,保持简单,但希望你明白这个想法

@IBAction func segmentAction(sender: NSSegmentedControl) {
    splitVC?.togglePanel(sender.selectedSegment)
}

and

func togglePanel(segmentID: Int) {
    let splitViewItem = self.mySplitView.arrangedSubviews

    switch segmentID {

    case segmentID:
        if mySplitView.isSubviewCollapsed(splitViewItem[segmentID]) {
            splitViewItem[segmentID].hidden = false
        } else {
            splitViewItem[segmentID].hidden = true
        }
    default:
        break
    }

}

And implement delegate

并实施委托

func splitView(splitView: NSSplitView, shouldHideDividerAtIndex dividerIndex: Int) -> Bool {
    return true
}

And with 10.11 you might just use toggleSidebar action method. How to toggle visibility of NSSplitView subView + hide Pane Splitter divider? https://github.com/Dis3buted/SplitViewController

使用10.11,您可能只使用toggleSidebar操作方法。如何切换NSSplitView子视图+隐藏窗格拆分器分割器的可见性? https://github.com/Dis3buted/SplitViewController

#9


You could try Brandon Walkin's BWToolKit.

你可以试试Brandon Walkin的BWToolKit。

The BWSplitView class has a method

BWSplitView类有一个方法

- (IBAction)toggleCollapse:(id)sender;

#10


I recommend to use NSSplitViewController instead, and NSSplitViewItem.isCollapsed to control them. This just work.

我建议改用NSSplitViewController,并使用NSSplitViewItem.isCollapsed来控制它们。这只是工作。

let item: NSSplitViewItem = ...
item.isCollapsed = true

To make this to work properly, you have to configure split-UI components with mainly view-controllers. Otherwise, it can be broken.

要使其正常工作,您必须配置主要是视图控制器的split-UI组件。否则,它可能被打破。

#1


I just got programmatic expanding and collapsing of NSSplitView to work. I've also configured my NSSplitView to expand/collapse a subview whenever the divider is double-clicked, so I wanted this to play nice with that feature (and it seems to). This is what I did:

我只是编程扩展和折叠NSSplitView工作。我还配置了我的NSSplitView,以便在双击分割器时展开/折叠子视图,所以我希望这对于该功能很好玩(而且似乎)。这就是我做的:

(in this example, splitView is the NSSplitView itself, splitViewSubViewLeft is the subview I wish to expand/collapse and lastSplitViewSubViewLeftWidth is an instance variable of type CGFloat.)

(在此示例中,splitView是NSSplitView本身,splitViewSubViewLeft是我希望展开/折叠的子视图,lastSplitViewSubViewLeftWidth是CGFloat类型的实例变量。)

// subscribe to splitView's notification of subviews resizing
// (I do this in -(void)awakeFromNib)
[[NSNotificationCenter defaultCenter]
 addObserver:self
 selector:@selector(mainSplitViewWillResizeSubviewsHandler:)
 name:NSSplitViewWillResizeSubviewsNotification
 object:splitView
 ];

// this is the handler the above snippet refers to
- (void) mainSplitViewWillResizeSubviewsHandler:(id)object
{
    lastSplitViewSubViewLeftWidth = [splitViewSubViewLeft frame].size.width;
}

// wire this to the UI control you wish to use to toggle the
// expanded/collapsed state of splitViewSubViewLeft
- (IBAction) toggleLeftSubView:(id)sender
{
    [splitView adjustSubviews];
    if ([splitView isSubviewCollapsed:splitViewSubViewLeft])
        [splitView
         setPosition:lastSplitViewSubViewLeftWidth
         ofDividerAtIndex:0
         ];
    else
        [splitView
         setPosition:[splitView minPossiblePositionOfDividerAtIndex:0]
         ofDividerAtIndex:0
         ];
}

#2


Simply hide the subview you want to collapse, e.g.

只需隐藏您要折叠的子视图,例如

[aSubViewToCollapse setHidden:YES];

You might also want to implement the delegate method -(BOOL)splitView:shouldHideDividerAtIndex: to return YES to hide the divider when a collapsed.

您可能还希望实现委托方法 - (BOOL)splitView:shouldHideDividerAtIndex:返回YES以在折叠时隐藏分隔符。

#3


I tried the solution above, and found it did not work, as isSubviewCollapsed never returned YES

我尝试了上面的解决方案,发现它不起作用,因为isSubviewCollapsed从未返回YES

A combination of the suggestions yielded a result which works

这些建议的组合产生了有效的结果

if ([splitViewTop isHidden]) {
    [splitViewTop setHidden:NO];
    [split
     setPosition:previousSplitViewHeight
     ofDividerAtIndex:0];
}
else {
    [splitViewTop setHidden:YES];
}
[split adjustSubviews];

#4


After some experimenting with the suggestions this was the easiest solution I found:

在尝试了一些建议之后,这是我发现的最简单的解决方案:

-(void)toggleCollapsibleView:(ib)sender {
   [collapsibleView setHidden:![splitView isSubviewCollapsed:collapsibleView]];
   [splitView adjustSubviews];
}

The function is a user defined first-responder action. It is triggered by a menu-item (or keystroke). The collapsibleView is a subview in the splitView both of which are connected in IB with their properties.

该功能是用户定义的第一响应者操作。它由菜单项(或按键)触发。 collapsibleView是splitView中的子视图,它们都在IB中与其属性相连。

#5


In El Capitan, this did the trick for me.

在El Capitan,这对我有用。

splitViewItem.collapsed = YES;

#6


NSSplitView actually has a private method -(void)_setSubview:(NSView *)view isCollapsed:(BOOL)collapsed that does this. Those who would like to ignore all warnings against using private methods, behold:

NSSplitView实际上有一个私有方法 - (void)_setSubview :( NSView *)视图isCollapsed:(BOOL)折叠执行此操作。那些想忽略所有使用私有方法的警告的人,看哪:

- (void)toggleSubview:(NSView *)view {
    SEL selector = @selector(_setSubview:isCollapsed:);
    NSMethodSignature *signature = [NSSplitView instanceMethodSignatureForSelector:selector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.target = self;
    invocation.selector = selector;
    [invocation setArgument:&view atIndex:2];
    BOOL arg = ![self isSubviewCollapsed:view];
    [invocation setArgument:&arg atIndex:3];
    [invocation invoke];
}

I implemented this as a category on NSSplitView. The only issue is that Xcode gives a warning about _setSubview:isCollapsed: being undeclared... I'm not really sure how to get around that.

我在NSSplitView上将其实现为一个类别。唯一的问题是Xcode给出了关于_setSubview的警告:isCollapsed:未申报......我真的不确定如何解决这个问题。


El Capitan Update

El Capitan更新

I haven't written any code for OS X in ~2 years now so I haven't been able to verify this, but according to lemonmojo in the comments below, _setSubview:isCollapsed: was renamed in El Capitan to _setArrangedView:isCollapsed:.

我在2年内没有为OS X编写任何代码所以我无法验证这一点,但根据下面评论中的lemonmojo,_setSubview:isCollapsed:在El Capitan中重命名为_setArrangedView:isCollapsed:。

#7


In macOS Sierra, the collapsed property is changed to isCollapsed. Is straight forward just setting the property to true or false. The following code is from my WindowController, where I have two SplitViewItems.

在macOS Sierra中,折叠的属性更改为isCollapsed。直接将属性设置为true或false。以下代码来自我的WindowController,我有两个SplitViewItems。

@IBAction func toggleMap(_ sender: Any) {
    if let splitViewController = contentViewController as? NSSplitViewController {
        let splitViewItem = splitViewController.splitViewItems
        if splitViewItem.first!.isCollapsed {
            splitViewItem.first!.isCollapsed = false
        } else if splitViewItem.last!.isCollapsed {
            splitViewItem.last!.isCollapsed = false
        } else {
            if splitViewItem.first!.isCollapsed {
                splitViewItem.first!.isCollapsed = false
            }
            splitViewItem.last!.isCollapsed = true
        }
    }
}

#8


In swift this works

在迅捷这是有效的

func togglePanel() {
    let splitViewItem = self.mySplitView.arrangedSubviews

    if mySplitView.isSubviewCollapsed(outline.view){
        splitViewItem[0].hidden = false
    } else {
        splitViewItem[0].hidden = true
    }

call this from IBAction, outline is an OutlineViewController with own xib and we need the view hence outline.view, keeping it simple but hope you get the idea

从IBAction调用这个,outline是一个带有自己的xib的OutlineViewController,我们需要视图,因此outline.view,保持简单,但希望你明白这个想法

@IBAction func segmentAction(sender: NSSegmentedControl) {
    splitVC?.togglePanel(sender.selectedSegment)
}

and

func togglePanel(segmentID: Int) {
    let splitViewItem = self.mySplitView.arrangedSubviews

    switch segmentID {

    case segmentID:
        if mySplitView.isSubviewCollapsed(splitViewItem[segmentID]) {
            splitViewItem[segmentID].hidden = false
        } else {
            splitViewItem[segmentID].hidden = true
        }
    default:
        break
    }

}

And implement delegate

并实施委托

func splitView(splitView: NSSplitView, shouldHideDividerAtIndex dividerIndex: Int) -> Bool {
    return true
}

And with 10.11 you might just use toggleSidebar action method. How to toggle visibility of NSSplitView subView + hide Pane Splitter divider? https://github.com/Dis3buted/SplitViewController

使用10.11,您可能只使用toggleSidebar操作方法。如何切换NSSplitView子视图+隐藏窗格拆分器分割器的可见性? https://github.com/Dis3buted/SplitViewController

#9


You could try Brandon Walkin's BWToolKit.

你可以试试Brandon Walkin的BWToolKit。

The BWSplitView class has a method

BWSplitView类有一个方法

- (IBAction)toggleCollapse:(id)sender;

#10


I recommend to use NSSplitViewController instead, and NSSplitViewItem.isCollapsed to control them. This just work.

我建议改用NSSplitViewController,并使用NSSplitViewItem.isCollapsed来控制它们。这只是工作。

let item: NSSplitViewItem = ...
item.isCollapsed = true

To make this to work properly, you have to configure split-UI components with mainly view-controllers. Otherwise, it can be broken.

要使其正常工作,您必须配置主要是视图控制器的split-UI组件。否则,它可能被打破。