14

我有一个 NSSplitView,它有两个窗格——左侧的侧边栏表格视图和右侧的 Web 视图。我还有一个委托集,它处理侧边栏的约束,如下所示:

- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)dividerIndex {
    return 500.0f;
}

- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
    return 175.0f;
}

- (BOOL)splitView:(NSSplitView *)splitView canCollapseSubview:(NSView *)subview {
    return NO;
}

这意味着侧边栏只能在 175 到 500 像素之间调整大小,并且在使用分隔手柄时效果很好。但是当调整整个窗口的大小时,分隔符会重新定位这些约束。

有人知道如何控制吗?

另外:如果我想存储用户对侧边栏宽度的选择,是否最好将其读出,将其保存到首选项文件并稍后恢复,还是有更直接的方法来做到这一点?我注意到在某些情况下窗口的状态会被保存 - 这通常会发生还是我必须控制它?

提前致谢

阿恩

4

9 回答 9

6

我最初实现了NSSplitView委托函数,最后编写了很多代码来尝试做一些简单的事情,比如限制每个拆分视图边的最小大小。

然后我改变了方法,找到了一个干净且极其简单的解决方案。我只是在. _ 我在另一边也做了同样的事情。有了这两个简单的约束,就可以完美地工作,而无需委托调用。NSViewNSSplitViewNSSplitView

于 2016-01-02T02:34:34.060 回答
4

您正在寻找的是:

- (void)splitView:(NSSplitView*)sender resizeSubviewsWithOldSize:(NSSize)oldSize

[sender frame]将是您NSSplitView调整大小后的新大小。然后相应地重新调整您的子视图。

于 2012-03-03T22:36:03.570 回答
3

问题是,当调整 NSSplitView 本身的大小时,-adjustSubviews会调用它来完成工作,但它完全忽略了委托的最小/最大约束!

但是-setPosition:ofDividerAtIndex:确实考虑了约束。

您需要做的就是将两者结合起来——这个例子假设一个只有 2 个视图的 NSSplitView:

- (CGFloat)splitView:(NSSplitView*)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
  return 300;
}

- (CGFloat)splitView:(NSSplitView*)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex {
  return (splitView.vertical ? splitView.bounds.size.width : splitView.bounds.size.height) - 500;
}

- (void)splitView:(NSSplitView*)splitView resizeSubviewsWithOldSize:(NSSize)oldSize {
  [splitView adjustSubviews];  // Use default resizing behavior from NSSplitView
  NSView* view = splitView.subviews.firstObject;
  [splitView setPosition:(splitView.vertical ? view.frame.size.width : view.frame.size.height) ofDividerAtIndex:0];  // Force-apply constraints afterwards
}

这似乎在 OS X 10.8、10.9 和 10.10 上运行良好,并且比其他方法更简洁,因为它是最少的代码并且不重复约束。

于 2015-05-27T23:14:23.957 回答
2

解决此问题的另一种方法是使用splitView:shouldAdjustSizeOfSubview:

对于我的目的,我发现这要简单得多。

例如,如果您想防止 sidebarTableView 永远小于您的 175 最小宽度,那么您可以执行以下操作(假设您将 sidebarTableView 作为视图控制器/委托上的插座);

- (BOOL)splitView:(NSSplitView *)splitView shouldAdjustSizeOfSubview:(NSView *)subview
{
    if ((subview==self.sidebarTableView) && subview.bounds.size.width<=175) {
        return NO;
    }
    return YES;
}
于 2014-09-03T23:31:42.893 回答
1

这是我的实现-splitView:resizeSubviewsWithOldSize:

-(void)splitView:(NSSplitView *)splitView resizeSubviewsWithOldSize:(NSSize)oldSize {
    if (![splitView isSubviewCollapsed:self.rightView] &&
        self.rightView.frame.size.width < 275.0f + DBL_EPSILON) {
        NSSize splitViewFrameSize = splitView.frame.size;
        CGFloat leftViewWidth = splitViewFrameSize.width - 275.0f - splitView.dividerThickness;
        self.leftView.frameSize = NSMakeSize(leftViewWidth,
                                             splitViewFrameSize.height);
        self.rightView.frame = NSMakeRect(leftViewWidth + splitView.dividerThickness,
                                          0.0f,
                                          275.0,
                                          splitViewFrameSize.height);
    } else
        [splitView adjustSubviews];
}

在我的例子中,rightView是两个子视图中的第二个,它是可折叠的,最小宽度为 275.0。leftView没有最小值或最大值,并且不可折叠。

于 2012-11-08T15:59:57.660 回答
0

我用了

- (void)splitView:(NSSplitView*)sender resizeSubviewsWithOldSize:(NSSize)oldSize

但我没有更改子视图框架,而是使用

    [sender setPosition:360 ofDividerAtIndex:0]; //or whatever your index and position should be

改变框架并没有给我一致的结果。设置分隔线的位置。

于 2014-05-22T15:06:15.987 回答
0

参加聚会可能为时已晚,但这是我对resizeSubviewWithOldSize:. 在我的项目中,我需要一个垂直可调整大小的 NSplitView,leftView 宽度在 100.0 到 300.0 之间;没有考虑到“崩溃”。您应该注意子视图的所有可能尺寸。

-(void)splitView:(NSSplitView *)splitView resizeSubviewsWithOldSize:(NSSize)oldSize {
    if (self.leftView.frame.size.width >= kMaxLeftWidth) {
        NSSize splitViewFrameSize = splitView.frame.size;
        CGFloat leftViewWidth = kMaxLeftWidth;
        CGFloat rightViewWidth = splitViewFrameSize.width - leftViewWidth - splitView.dividerThickness;

        self.leftView.frameSize = NSMakeSize(leftViewWidth,
                                             splitViewFrameSize.height);

        self.rightView.frame = NSMakeRect(leftViewWidth + splitView.dividerThickness,
                                          0.0f,
                                          rightViewWidth,
                                          splitViewFrameSize.height);
    } else if (self.leftView.frame.size.width <= kMinLeftWidth) {
        NSSize splitViewFrameSize = splitView.frame.size;
        CGFloat leftViewWidth = kMinLeftWidth;
        CGFloat rightViewWidth = splitViewFrameSize.width - leftViewWidth - splitView.dividerThickness;

        self.leftView.frameSize = NSMakeSize(leftViewWidth,
                                             splitViewFrameSize.height);

        self.rightView.frame = NSMakeRect(leftViewWidth + splitView.dividerThickness,
                                          0.0f,
                                          rightViewWidth,
                                          splitViewFrameSize.height);
    } else {
        NSSize splitViewFrameSize = splitView.frame.size;
        CGFloat leftViewWidth = self.leftView.frame.size.width;
        CGFloat rightViewWidth = splitViewFrameSize.width - leftViewWidth - splitView.dividerThickness;

        self.leftView.frameSize = NSMakeSize(leftViewWidth,
                                             splitViewFrameSize.height);

        self.rightView.frame = NSMakeRect(leftViewWidth + splitView.dividerThickness,
                                          0.0f,
                                          rightViewWidth,
                                          splitViewFrameSize.height);
    }
}
于 2015-08-31T11:39:33.637 回答
0

我只需要这样做,并想出了这个比前面的例子简单一点的方法。此代码假定 NSSplitView 容器的左右 NSScrollView 有 IBOutlets,以及左右视图最小尺寸的 CGFloat 常量。

#pragma mark - NSSplitView sizing override

//------------------------------------------------------------------------------
// This is implemented to ensure that when the window is resized that our main table
// remains at it's smallest size or larger (the default proportional sizing done by
// -adjustSubviews would size it smaller w/o -constrainMinCoordiante being called).

- (void) splitView: (NSSplitView *)inSplitView resizeSubviewsWithOldSize: (NSSize)oldSize
{
    // First, let the default proportional adjustments take place
    [inSplitView adjustSubviews];

    // Then ensure that our views are at least their min size
    // *** WARNING: this does not handle allowing the window to be made smaller than the total of the two views!

    // Gather current sizes
    NSSize leftViewSize = self.leftSideView.frame.size;
    NSSize rightViewSize = self.rightSideView.frame.size;
    NSSize splitViewSize = inSplitView.frame.size;
    CGFloat dividerWidth = inSplitView.dividerThickness;

    // Assume we don't have to resize anything
    CGFloat newLeftWidth = 0.0f;

    // Always adjust the left view first if we need to change either view's size
    if( leftViewSize.width < kLeftSplitViewMinSize )
    {
        newLeftWidth = kLeftSplitViewMinSize;
    }
    else if( rightViewSize.width < kRightSplitViewMinSize )
    {
        newLeftWidth = splitViewSize.width - (kRightSplitViewMinSize + dividerWidth);
    }

    // Do we need to adjust the size?
    if( newLeftWidth > 0.0f )
    {
        // Yes, do so by setting the left view and setting the right view to the space left over
        leftViewSize.width = newLeftWidth;
        rightViewSize.width = splitViewSize.width - (newLeftWidth + dividerWidth);

        // We also need to set the origin of the right view correctly
        NSPoint origin = self.rightSideView.frame.origin;
        origin.x = splitViewSize.width - rightViewSize.width;
        [self.rightSideView setFrameOrigin: origin];

        // Set the the ajusted view sizes
        leftViewSize.height = rightViewSize.height = splitViewSize.height;
        [self.leftSideView setFrameSize: leftViewSize];
        [self.rightSideView setFrameSize: rightViewSize];
    }
}
于 2017-11-10T17:14:34.020 回答
0

我通过在 Interface Builder 中将固定侧的holdingPriorityon设置为 Required(1000) 来实现此行为。NSSplitViewItem然后,您可以通过在底层设置约束来控制固定边的宽度NSView

于 2016-08-26T12:38:32.770 回答