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

六月ゝ 毕业季﹏ 提交于 2019-12-11 09:33:59

问题


I have some issues with Cocoa Autolayout. I have a window and I add (programmatically) a NSTableView (with its 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. 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.

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. 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.

The problem is that when I insert the filter view, it is of almost zero size (like 1 point). 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).

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. 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. 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.

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 )>

回答1:


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:

 [[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.

Good luck.



来源:https://stackoverflow.com/questions/22966386/cocoa-autolayout-insert-and-remove-view-programmatically-at-runtime

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!