22

NSSplitView我应该如何在子视图中使用自动布局约束?

我的NSSplitView子视图有 3 个子视图:topPanetableContainer并且bottomPane我设置了这样的约束:

NSDictionary* views = NSDictionaryOfVariableBindings(topPane, tableContainer, bottomPane);

for (NSView* view in [views allValues]) {
    [view setTranslatesAutoresizingMaskIntoConstraints:NO];
}

[myView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[topPane(34)][tableContainer][bottomPane(24)]|"
                                                               options:0 
                                                               metrics:nil 
                                                                 views:views]];

[mySplitView addSubview:myView];

并在控制台中得到了这个:

Unable to simultaneously satisfy constraints:
(
    "<NSLayoutConstraint:0x7fd6c4b1f770 V:[NSScrollView:0x7fd6c4b234c0]-(0)-[CPane:0x7fd6c4b2fd10]>",
    "<NSLayoutConstraint:0x7fd6c4b30910 V:[CPane:0x7fd6c4b2f870(34)]>",
    "<NSLayoutConstraint:0x7fd6c4b30770 V:|-(0)-[CPane:0x7fd6c4b2f870]   (Names: '|':NSView:0x7fd6c4b22e50 )>",
    "<NSLayoutConstraint:0x7fd6c4b212f0 V:[CPane:0x7fd6c4b2fd10]-(0)-|   (Names: '|':NSView:0x7fd6c4b22e50 )>",
    "<NSLayoutConstraint:0x7fd6c4b2f910 V:[CPane:0x7fd6c4b2f870]-(0)-[NSScrollView:0x7fd6c4b234c0]>",
    "<NSLayoutConstraint:0x7fd6c4b21290 V:[CPane:0x7fd6c4b2fd10(24)]>",
    "<NSAutoresizingMaskLayoutConstraint:0x7fd6c3630430 h=--& v=--& V:[NSView:0x7fd6c4b22e50(0)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7fd6c4b1f770 V:[NSScrollView:0x7fd6c4b234c0]-(0)-[CPane:0x7fd6c4b2fd10]>

我认为<NSAutoresizingMaskLayoutConstraint:0x7fd6c3630430 h=--& v=--& V:[NSView:0x7fd6c4b22e50(0)]>会导致这种情况,但我无法重置自动调整掩码,因为NSSplitView设置了它。

在拆分视图中使用自动布局的最佳方法是什么?有没有什么方法可以在没有自动布局的情况下处理拆分视图子视图的最小/最大大小NSSplitViewDelegate

4

9 回答 9

7

我发现如果我的窗口中有工具栏并通过任何此委托方法控制拆分视图,则会出现此错误:

splitView:constrainMinCoordinate:ofSubviewAt:   
splitView:constrainMaxCoordinate:ofSubviewAt:
splitView:shouldAdjustSizeOfSubview:

在 windowDidLoad 中将工具栏附加到窗口中找到了解决方案。

于 2012-11-05T17:31:01.260 回答
4

对于将来偶然发现这一点并正在寻找基于约束的替代品的快速启动的任何人NSSplitView,我在这里编写了一个小项目,尝试NSSplitView使用 Auto Layout 重新创建 's 的部分功能:

https://github.com/jwilling/JWSplitView

它有些错误,但对于任何想要走这条路的人来说,它可能是一个有用的参考。

于 2012-12-20T02:39:21.093 回答
4

NSSplitView 从一开始就是一件奇怪的事情,如果它很快就会消失,我也不会感到惊讶。在尝试让 NSSplitView 与 AutoLayout 一起工作一个月并从一次绝望的攻击陷入另一次之后,我终于放弃了。

我的解决方案是根本不使用带有 AutoLayout的 NSSplitView。因此,无论是没有 Autolayout 的 NSSplitView 还是没有 NSSplitView 的 Autolayout:这并不像听起来那么复杂:只需将您的子视图彼此相邻并添加NSLayoutConstraintsIBOutlets. 然后可以在代码中从控制器设置和更改这些约束的常量。使用这种方法,您可以设置原点(将其滑出窗口的负偏移量)、宽度以及与其他子视图的关系——另外,使用视图的动画器为约束设置动画非常容易(曾经尝试为NSSplitView 设置动画?

唯一缺少的是在分隔线上的鼠标拖动,但这可以通过几行来实现,在您的自定义“SplitView”中跟踪 mouseEvents。

Apple 有一个自动布局“splitview”示例(不幸的是只有垂直),我最近在 github 上至少看到了一个新项目。虽然对我来说,我认为针对我的应用程序的特定需求,从我的自定义解决方案重新开始会更容易,而不是尝试创建非常通用的东西(从而使其过于复杂而无法处理)。

编辑:我现在完成了从单独的笔尖加载其子视图的自定义 splitView。没有约束问题,没有自动布局警告。与试图让它与 NSSplitView 一起工作的整个月相比,我现在有了一个基于约束的工作自定义 splitView,易于动画化,仅在一个晚上创建。我绝对推荐走这条路!

于 2012-08-18T02:01:20.220 回答
3

10.8 修复了该问题,请参阅其发行说明。

这是我的 10.7 解决方案(自定义拆分视图): https ://github.com/benuri/HASplitView.git

于 2012-10-16T15:04:16.200 回答
1

您根本不想禁用translatesAutoresizingMaskIntoConstraints。您不应该混淆系统视图约束。NSSplitView处理各个视图本身的大小,您实际上是在试图剥夺它的控制权。更不用说,你忘了考虑分离器。

在拆分视图上设置最小或最大(或恒定)宽度/高度的正确方法是在视图上单独设置这些东西。特别是,如果您在代码中执行此操作,您将需要使用 2 次单独调用 constraintsWithVisualFormat,因为否则视觉格式语言将在视图之间创建约束。

您可以在 IB 中完成所有这些工作。您甚至可以在拆分视图中设置每个视图的优先级,这将导致一个或另一个视图在窗口调整大小时调整大小,而不是平均分配调整大小。

于 2012-08-17T14:58:58.543 回答
0

我使用这个类作为一种解决方法,它并不完美(子视图有点口吃),但它让我畅通无阻。我将此类用作每个拆分视图窗格中的自定义类。

@interface FBSplitPaneView : NSView

@end

@implementation FBSplitPaneView

- (void)setFrame:(NSRect)frame
{
  for (NSView *subview in self.subviews) {
    subview.frame = self.bounds;
  }
  [super setFrame:frame];
}

@end
于 2015-04-22T19:23:42.450 回答
0

尽管我讨厌不同意,但奥科的回答不应该被评为最高。通过足够的工作量来解决问题在任何方面都没有帮助。在我看来,NSSplitView 只是那些没有充分阅读文档的人的问题。

这里提到的问题的实际解决方案相当简单:Auto Layout 在 NSSplitView 上引入了新的“Holding Priorities API”。正如文档所说:将较低的值设置为子视图的持有优先级将使他更有可能更早地采用宽度。所有这些都可以在 IB 中以编程方式设置,而不会感到绝望。所需工作量:大约 20 秒。

于 2012-10-09T10:03:48.423 回答
0

我通过一个 nib 文件加载所有内容,setTranslatesAutoresizingMaskIntoConstraints:NO然后再加载。

所以也许你应该首先添加[mySplitView addSubview:myView];你的视图,然后禁用自动调整掩码到约束的转换,然后你将你的约束添加到myView.

编辑:

好的,我似乎误解了 myView。您必须将约束添加到子视图而不是拆分视图。

[topPane addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topPane(34)]" options:0 metrics:nil views:views]];

[bottomPane addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[bottomPane(24)]" options:0 metrics:nil views:views]];

您不必添加边缘约束(“V:|[topPane(34)]”中的“|”),因为其中的子视图NSSplitView已经自动调整大小。

这导致了这种情况,例如对于 topPane 约束:

屏幕截图

注意:忽略子视图内容,它们只是占位符

于 2012-07-15T12:43:57.473 回答
0

我花了一些时间让我的自动布局清除警告,但我确实在 IB 中处理了它(几个拆分视图和子视图)。

我的布局看起来像:

RootView
  |--第一个 NSSplitView(3 个垂直子视图)
      |----UIView(左)
      |----第 2 个 NSSplitView(中心和 2 个水平子视图)
           |---UIView(顶部)
           |---第 3 个 NSSplitView(底部& 3个垂直子视图)
               |---UIView(左)
               |---UIView(中)
               |---UIView(右)
      |----UIView(右)

我的问题是,我的所有子视图中都有 19 个警告,但我的布局看起来很好,并且工作正常。过了一会儿,我找到了警告的原因:我的第一个拆分视图中外部视图的约束。

两个视图(左和右)都具有“宽度 >= 200”的宽度约束,而中心视图(第二个拆分视图)没有约束(因为它的最小宽度和最大宽度由其子视图处理)。

警告告诉我,自动布局想要缩小我的 IB-UI-Layout,因为计算出的最小宽度小于我的布局,但我不想在 IB 中缩小它。

我向我的第一个拆分视图的两个外部子视图添加了一个固定约束“宽度 = 200”,并选中了“在构建时删除”。

现在我的布局没有警告,一切正常。

我的结论

我认为自动布局和拆分视图的问题在于自动布局无法处理子视图的宽度约束。我们想要使用拆分视图的原因是,我们想要视图的动态宽度,并且我们想要它在两个方向上,收缩和扩展。

所以没有 width <= xxx && width >= xxx 。Autolayout 只能处理其中一个,我们会在 IB 中收到警告。您可以使用 IB 中的临时约束来解决此问题,该约束将在运行前删除。

我希望我写的东西有意义,但它在我的项目中运行良好。

PS:直到今天我找到了这个帖子,我才找到任何解决方案。所以我想你的帖子启发了我:-)

于 2015-02-09T18:49:52.160 回答