I have made the following example app to illustrate my question.
The left view is a place holder view (added in Interface Builder). When the App loads I add a subview managed by a NSViewController. The NSViewController draws the different coloured rectangles, each of which is a NSView, and the layout of these coloured views managed by constraint created programmatically and added to the
-loadView
method of the controller.The right view is an NSTableView (added in Interface Builder). When the App loads I use the same NSViewController class to provide views to for the table view (only one row is added).
When I add the subview the the place holder view I also add two additional constraints,
[_placeholderView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[CTRL_VIEW]|" options:0 metrics:nil views:views]];
[_placeholderView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[CTRL_VIEW]|" options:0 metrics:nil views:views]];
These constraints set the frame of the subview to be equal to the bounds of the superview. All is good.
However, when I provide the view for the NSTableView using the delegate method -tableView:viewForTableColumn:row:
, the view has not yet been added to the table. As such it doesn't have a superview, so constraints cannot (yet) be added to the view. This is why the view in the table view does not have the same bounds as the table view cell.
So my question is how can I add constraints to the view I supply to the table view? Can I access the view again after the table view has added it? This seems a bit hack-ish.
The source code for the AppDelegate.h,
#import <Cocoa/Cocoa.h>
@class BlahViewController;
@interface AppDelegate : NSObject <NSApplicationDelegate, NSTableViewDataSource, NSTableViewDelegate>
@property (assign) IBOutlet NSWindow *window;
/* Left view controller and place holding view */
@property (strong) BlahViewController *viewController;
@property (weak) IBOutlet NSView *placeholderView;
/* Right view (which is an NSTableView) */
@property (weak) IBOutlet NSTableView *tableView;
@end
and AppDelegate.m,
#import "AppDelegate.h"
#import "BlahViewController.h"
@interface AppDelegate ()
@property NSMutableArray *tableData;
@end
@implementation AppDelegate
- (id)init
{
self = [super init];
if (self) {
_tableData = [[NSMutableArray alloc] init];
[_tableData addObject:[[BlahViewController alloc] initWithNibName:@"BlahViewController" bundle:nil]];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints"];
}
return self;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
/* Add a managed subview to the place holder view*/
_placeholderView.layer.backgroundColor = CGColorCreateGenericGray(0.5, 1.0);
_viewController = [[BlahViewController alloc] initWithNibName:@"BlahViewController" bundle:nil];
[_viewController.view setFrame:_placeholderView.bounds];
[_placeholderView addSubview:_viewController.view];
/* Additional constraints so the managed subview resizes with the place holder view */
NSDictionary *views = @{ @"CTRL_VIEW" : _viewController.view };
[_placeholderView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[CTRL_VIEW]|" options:0 metrics:nil views:views]];
[_placeholderView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[CTRL_VIEW]|" options:0 metrics:nil views:views]];
}
-(NSInteger) numberOfRowsInTableView:(NSTableView *)tableView
{
return [_tableData count];
}
-(id) tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
return [_tableData[row] view];
}
-(CGFloat) tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row {
return 150.;
}
@end
Update @jrturton
Adding the constraints in -(void) tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row
worked.
@swalkner
The constraints I added are very basic,
-(void) tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row {
NSView *view = [rowView viewAtColumn:0];
NSDictionary *views = NSDictionaryOfVariableBindings(view);
[view.superview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-12-[view]-12-|" options:0 metrics:nil views:views]];
[view.superview addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-12-[view]-12-|" options:0 metrics:nil views:views]];
}
tableView:didAddRowView:forRow:
look like? I'd like to achieve the same thing but don't get it to work... – Akee