简体   繁体   English

可可自动布局:在运行时以编程方式插入(和删除)视图

[英]Cocoa Autolayout: insert (and remove) view programmatically at runtime

I have some issues with Cocoa Autolayout. 我在使用Cocoa Autolayout时遇到了一些问题。 I have a window and I add (programmatically) a NSTableView (with its NSScrollView ). 我有一个窗口,我(以编程方式)添加了一个NSTableView (及其NSScrollView )。 Until now everything is ok. 到现在为止一切正常。 I can resize my window and the table resizes correctly. 我可以调整窗口大小,表格也可以正确调整大小。 This is the code I used. 这是我使用的代码。

MyListViewController *viewController = [[MyListViewController alloc] initWithNibName:@"ListView" bundle:nil];

[self.mainContentView addSubview:viewController.view];
[viewController.view setTranslatesAutoresizingMaskIntoConstraints:NO];

[self.mainContentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[insertedView]|"
                                                                                 options:0
                                                                                 metrics:nil
                                                                                   views:@{@"insertedView" :viewController.view}]];
NSArray *verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[insertedView]|"
                                                                           options:0
                                                                           metrics:nil
                                                                             views:@{@"insertedView" :viewController.view}];

[self.mainContentView addConstraints:verticalConstraints];

Now.. I want to add (and remove) at runtime another view which is placed at the top of the table. 现在,我想在运行时添加(和删除)位于表顶部的另一个视图。 The view is a NSPredicateEditor with its NSScrollView . 视图是一个NSPredicateEditorNSScrollView To be clear: I'm trying to achieve the same behaviour of the Finder when you type something in the search field and the view with the possible search options appears in the main window. 明确说明:当您在搜索字段中键入内容,并且带有可能的搜索选项的视图出现在主窗口中时,我正在尝试实现与Finder相同的行为。

I handle this in this way: 我这样处理:

AdvancedFilterViewController *viewController = [[AdvancedFilterViewController alloc] initWithNibName:@"AdvancedFilterView" bundle:nil];

[self.mainContentView addSubview:viewController.view];
[viewController.view setTranslatesAutoresizingMaskIntoConstraints:NO];

[self.mainContentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[insertedView]|"
                                                                             options:0
                                                                             metrics:nil
                                                                               views:@{@"insertedView" :viewController.view}]];
[self.mainContentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[insertedView(<=225)][prevView]|" // >= size of one row, <= size of 8 + 1 rows
                                                                             options:0
                                                                             metrics:nil
                                                                               views:@{@"insertedView" :viewController.view, @"prevView" : self.listView.view}]];

I would like that at least one line of the predicate (25 points) are visible. 我希望至少有一行谓词(25分)可见。 When the user presses the plus button, then more views start to appears (and the scrollview should adapt its size). 当用户按下加号按钮时,就会出现更多视图(滚动视图应适应其大小)。 After some rows (I decided 9) the scrollbars should start to appear and the main view in the window should stop shrinking. 经过几行(我决定为9)后,滚动条应开始出现,并且窗口中的主视图应停止缩小。

The problem is that when I insert the filter view, it is of almost zero size (like 1 point). 问题是,当我插入过滤器视图时,它的大小几乎为零(例如1点)。 Or if I add a minimum size of 25 points, the view is visible but adding rows only increases the ''inner size'' of the scrollview, so scrollbar appears (but the scrollview does not grow and does not make the list view shrink). 或者,如果我添加最小点数为25点,则该视图可见,但添加行只会增加滚动视图的“内部大小”,因此会出现滚动条(但滚动视图不会增大,并且不会使列表视图缩小) 。

I hope I explained correctly the problem. 我希望我能正确解释问题。

EDIT: 编辑:

Taking inspiration from the answer I implemented the delegate: 从答案中得到启发,我实现了代表:

- (void)ruleEditorRowsDidChange:(NSNotification *)notification
{
    //handle resizing of the view
    [self.predicateEditorHeight setConstant:[self.predicateEditor numberOfRows] * self.predicateEditor.rowHeight];
}

where self.predicateEditorHeight is an IBOutlet to a constraint on the height of the NSScrollView . 其中self.predicateEditorHeight是对NSScrollView高度的约束的IBOutlet Then in the enclosing NSWindowController , when I add the predicate editor view I also add a constraint on the proportions of the NSTableView with respect to the predicate view. 然后在封闭的NSWindowController ,当我添加谓词编辑器视图时,我还添加了对NSTableView相对于谓词视图的比例的约束。 In this way (because I set it to 0.3) the scroll view can grow until a certain point, and then, after that, it must use its scrollbars. 通过这种方式(因为我将其设置为0.3),滚动视图可以增长到某个点,然后,此后必须使用其滚动条。

I still have some issues on the constraints: For example, when I add too many rows in the editor I get 我仍然遇到一些约束方面的问题:例如,当我在编辑器中添加太多行时,我得到

2014-04-26 09:38:27.769 MyApp[2531:303] Unable to simultaneously satisfy constraints:
(
    "<NSLayoutConstraint:0x60000029dc40 V:[NSView:0x60000013fb80]-(0)-|   (Names: '|':NSView:0x60000013e500 )>",
    "<NSLayoutConstraint:0x60000029dbf0 V:[NSView:0x600000320b40]-(0)-[NSView:0x60000013fb80]>",
    "<NSLayoutConstraint:0x60000029dc90 NSView:0x60000013fb80.height >= 0.3*NSView:0x600000320b40.height>",
    "<NSAutoresizingMaskLayoutConstraint:0x608000288b60 h=--& v=--& V:[NSView:0x60000013e500(360)]>",
    "<NSLayoutConstraint:0x60000029dba0 V:|-(0)-[NSView:0x600000320b40]   (Names: '|':NSView:0x60000013e500 )>",
    "<NSLayoutConstraint:0x60000029d1a0 V:[NSView:0x600000320f00(275)]>",
    "<NSLayoutConstraint:0x60000029d420 V:[NSView:0x600000320f00]-(0)-|   (Names: '|':NSView:0x600000320b40 )>",
    "<NSLayoutConstraint:0x60000029d510 V:[NSView:0x600000320dc0]-(0)-[NSView:0x600000320f00]>",
    "<NSLayoutConstraint:0x60000029d330 V:|-(0)-[NSView:0x600000320dc0]   (Names: '|':NSView:0x600000320b40 )>",
    "<NSLayoutConstraint:0x60000029d060 V:[NSButton:0x6000001569a0'Search']-(4)-|   (Names: '|':NSView:0x600000320dc0 )>",
    "<NSLayoutConstraint:0x60000029d0b0 V:|-(5)-[NSButton:0x6000001569a0'Search']   (Names: '|':NSView:0x600000320dc0 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x60000029d060 V:[NSButton:0x6000001569a0'Search']-(4)-|   (Names: '|':NSView:0x600000320dc0 )>

2014-04-26 09:38:27.770 MyApp[2531:303] Unable to simultaneously satisfy constraints:
(
    "<NSLayoutConstraint:0x60000029dc40 V:[NSView:0x60000013fb80]-(0)-|   (Names: '|':NSView:0x60000013e500 )>",
    "<NSLayoutConstraint:0x60000029dbf0 V:[NSView:0x600000320b40]-(0)-[NSView:0x60000013fb80]>",
    "<NSLayoutConstraint:0x60000029dc90 NSView:0x60000013fb80.height >= 0.3*NSView:0x600000320b40.height>",
    "<NSAutoresizingMaskLayoutConstraint:0x608000288b60 h=--& v=--& V:[NSView:0x60000013e500(360)]>",
    "<NSLayoutConstraint:0x60000029dba0 V:|-(0)-[NSView:0x600000320b40]   (Names: '|':NSView:0x60000013e500 )>",
    "<NSLayoutConstraint:0x60000029d1a0 V:[NSView:0x600000320f00(275)]>",
    "<NSLayoutConstraint:0x60000029d420 V:[NSView:0x600000320f00]-(0)-|   (Names: '|':NSView:0x600000320b40 )>",
    "<NSLayoutConstraint:0x60000029d510 V:[NSView:0x600000320dc0]-(0)-[NSView:0x600000320f00]>",
    "<NSLayoutConstraint:0x60000029d330 V:|-(0)-[NSView:0x600000320dc0]   (Names: '|':NSView:0x600000320b40 )>",
    "<NSLayoutConstraint:0x60000029d100 V:|-(4)-[NSButton:0x6000001564d0]   (Names: '|':NSView:0x600000320dc0 )>",
    "<NSLayoutConstraint:0x60000029d150 V:[NSButton:0x6000001564d0]-(5)-|   (Names: '|':NSView:0x600000320dc0 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x60000029d150 V:[NSButton:0x6000001564d0]-(5)-|   (Names: '|':NSView:0x600000320dc0 )>

2014-04-26 09:38:27.775 MyApp[2531:303] Unable to simultaneously satisfy constraints:
(
    "<NSLayoutConstraint:0x60000029cf70 V:[NSTextField:0x600000198940]-(4)-|   (Names: '|':NSView:0x600000320dc0 )>",
    "<NSLayoutConstraint:0x60000029cfc0 V:|-(4)-[NSTextField:0x600000198940]   (Names: '|':NSView:0x600000320dc0 )>",
    "<NSLayoutConstraint:0x60000029dc40 V:[NSView:0x60000013fb80]-(0)-|   (Names: '|':NSView:0x60000013e500 )>",
    "<NSLayoutConstraint:0x60000029dbf0 V:[NSView:0x600000320b40]-(0)-[NSView:0x60000013fb80]>",
    "<NSLayoutConstraint:0x60000029dc90 NSView:0x60000013fb80.height >= 0.3*NSView:0x600000320b40.height>",
    "<NSAutoresizingMaskLayoutConstraint:0x608000288b60 h=--& v=--& V:[NSView:0x60000013e500(360)]>",
    "<NSLayoutConstraint:0x60000029dba0 V:|-(0)-[NSView:0x600000320b40]   (Names: '|':NSView:0x60000013e500 )>",
    "<NSLayoutConstraint:0x60000029d1a0 V:[NSView:0x600000320f00(275)]>",
    "<NSLayoutConstraint:0x60000029d420 V:[NSView:0x600000320f00]-(0)-|   (Names: '|':NSView:0x600000320b40 )>",
    "<NSLayoutConstraint:0x60000029d510 V:[NSView:0x600000320dc0]-(0)-[NSView:0x600000320f00]>",
    "<NSLayoutConstraint:0x60000029d330 V:|-(0)-[NSView:0x600000320dc0]   (Names: '|':NSView:0x600000320b40 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x60000029cf70 V:[NSTextField:0x600000198940]-(4)-|   (Names: '|':NSView:0x600000320dc0 )>

You have to 'inform' the parent view, that the inner view will resize. 您必须“通知”父视图,内部视图将调整大小。 My approach was to watch predicate grow and shrink by its delegate: 我的方法是观察谓词由其代表增长和收缩:

- (void)ruleEditorRowsDidChange:(NSNotification *)notification{

  NSInteger newRowCount = [_predicateEditor numberOfRows];
  NSInteger rowHeight = [_predicateEditor rowHeight];

  // Send a notification - size changes
  NSRect newFrame = self.view.frame;
  newFrame.size.height = 30 + newRowCount*rowHeight;
  [[NSNotificationCenter defaultCenter]postNotificationName:@"RowsDidChange" object:[NSValue valueWithRect:newFrame]];
  [[_heightConstraint animator] setConstant:rowHeight*newRowCount];
}

And a 'observer' in the parent ViewController to watch the size changes: 在父级ViewController中有一个“观察者”来观察大小变化:

 [[NSNotificationCenter defaultCenter]addObserverForName:@"RowsDidChange" 
    object:nil 
    queue:nil 
    usingBlock:^(NSNotification * notification){
        NSValue *value =  (NSValue*)notification.object;
        NSRect rectValue = [value rectValue];

        NSRect newContentRect = self.resultsView.frame;
        newContentRect.size.height = self.resultsView.frame.size.height - rectValue.size.height;
        newContentRect.size.width = self.resultsView.frame.size.width;

        // Set new height to the mainViewController
        [[self.mainViewController view] setFrame:newContentRect];
}];

You don't need to send a notification, you can also send some delegate method to you parent viewcontroller. 您不需要发送通知,也可以向您的父级viewcontroller发送一些委托方法。

Good luck. 祝好运。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM