2013-01-13 5 views
14

Ho realizzato la seguente app di esempio per illustrare la mia domanda.Come utilizzare l'autolayout con NSTableView basato su visualizzazione quando la visualizzazione viene fornita da un NSViewController?

  • La vista di sinistra è una vista segnaposto (aggiunta in Interface Builder). Quando l'app viene caricata, aggiungo una sottoview gestita da NSViewController. NSViewController disegna i diversi rettangoli colorati, ciascuno dei quali è un NSView, e il layout di queste viste colorate gestite da vincoli creati a livello di codice e aggiunti al metodo -loadView del controller.

  • La vista di destra è una NSTableView (aggiunta in Interface Builder). Quando l'app viene caricata, utilizzo la stessa classe NSViewController per fornire viste per la vista tabella (viene aggiunta una sola riga).

Quando aggiungo la visualizzazione secondaria la vista posto titolare aggiungo anche due vincoli aggiuntivi,

[_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]]; 

Questi vincoli impostare il telaio della visualizzazione secondaria uguale ai limiti della superview. Va tutto bene.

Tuttavia, quando fornisco la vista per NSTableView utilizzando il metodo delegato -tableView:viewForTableColumn:row:, la vista non è stata ancora aggiunta alla tabella. Come tale non ha una superview, quindi i vincoli non possono (ancora) essere aggiunti alla vista. Questo è il motivo per cui la vista nella vista tabella non ha gli stessi limiti della cella di visualizzazione tabella.

Quindi la mia domanda è: come posso aggiungere vincoli alla vista che fornisco alla vista tabella? Posso accedere nuovamente alla vista dopo che la vista tabella è stata aggiunta? Questo sembra un po 'hack-ish.

Two views using autolayout.

Il codice sorgente per l'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 

e 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 

Aggiorna @jrturton

Aggiungendo i vincoli -(void) tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row ha funzionato.

With constraints added.

@swalkner

I vincoli che ho aggiunto sono molto semplici,

-(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]]; 
} 
+0

come si presenta il tuo 'tableView: didAddRowView: forRow:'? Mi piacerebbe ottenere la stessa cosa ma non farlo funzionare ... – swalkner

+0

Osservando lo speciale. Letteralmente basta applicare i vincoli alla vista (vedi sopra ho fatto una modifica per te). –

risposta

6

È possibile accedere alla vista dopo che è stato aggiunto alla tabella nel metodo delegato tableView:willDisplayCell:forTableColumn:row: . A questo punto puoi aggiungere i vincoli, ma dovresti fare attenzione a non continuare ad aggiungere gli stessi vincoli più e più volte.

Come hai scoperto tu stesso, il metodo tableView:didAddRowView:forRow: sarebbe un posto migliore, in quanto verrà richiamato solo una volta per ogni nuova visualizzazione.

Potrebbe anche essere possibile ottenere ciò impostando una maschera di autoresizing larghezza flessibile sulla vista invece di qualsiasi vincolo di dimensione orizzontale. La tabella probabilmente ne terrà conto durante l'aggiunta di viste cella. Se stai attento, puoi mescolare e abbinare autoresizing e vincoli.

Conosco un po 'di iOS, un po' di Autolayout e solo un piccolo OS X, quindi non posso darvi molto di più. Non dobbiamo preoccuparci che le dimensioni delle celle cambino molto nella terra di iOS!

+0

Grazie per il consiglio dal mondo iOS :) Più apprendo su iOS, più diventa geloso. Sembra un'API molto più moderna. Penso che OSX stia recuperando terreno. Nuovo in Lion ho trovato tableView: didAddRowView: forRow: in NSTableViewDelegate seguendo il tuo consiglio. –

+0

Sembra perfetto. Aggiornerò la mia risposta per includerla, se ha funzionato per te? In questo modo i futuri lettori non dovranno fare commenti. – jrturton

+1

Sì, questo ha risposto al problema, tableView: didAddRowView: forRow: sembra essere chiamato dopo aver aggiunto la vista ma prima che il ciclo di esecuzione termini. Ho aggiunto i vincoli di cui avevo bisogno e sembra funzionare. –