问题
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.
However, I'm missing RBSplitView
's handy methods expand
and collapse
in NSSplitView
. How can I expand and collapse parts of NSSplitView programmatically?
回答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:
(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
.)
// 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.
回答3:
I tried the solution above, and found it did not work, as isSubviewCollapsed never returned 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.
回答5:
In El Capitan, this did the trick for me.
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:
- (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.
El Capitan Update
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:
.
回答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 SplitViewItem
s.
@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 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
回答9:
I recommend to use NSSplitViewController
instead, and NSSplitViewItem.isCollapsed
to control them. This just work.
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.
回答10:
You could try Brandon Walkin's BWToolKit.
The BWSplitView class has a method
- (IBAction)toggleCollapse:(id)sender;
来源:https://stackoverflow.com/questions/925020/how-to-expand-and-collapse-parts-of-nssplitview-programmatically