2013-01-13 10 views
14

私の質問を説明するために、以下のサンプルアプリケーションを作成しました。ビューがNSViewControllerによって提供されるとき、ビューベースのNSTableViewでautolayoutを使用するには?

  • 左図は、(Interface Builderで添加)プレースホルダ図です。アプリケーションがロードされると、NSViewControllerによって管理されるサブビューを追加します。 NSViewControllerは、それぞれがNSViewである異なる色の長方形を描画し、これらの色付きビューのレイアウトはプログラムで作成された制約によって管理され、コントローラの-loadViewメソッドに追加されます。

  • 右のビューは、NSTableView(Interface Builderで追加)です。 Appがロードされると、同じNSViewControllerクラスを使用して、テーブルビューのビューを提供します(1つの行だけが追加されます)。

IがサブビューをIは、2つの追加の制約を追加するプレースホルダビューを追加し、

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

これらの制約は、スーパーの境界に等しくなるようにサブビューのフレームを設定します。すべてが良いです。

ただし、デリゲートメソッド-tableView:viewForTableColumn:row:を使用してNSTableViewのビューを提供すると、そのビューはまだテーブルに追加されていません。そのため、スーパービューがないため、ビューに制約を追加することはできません。これは、テーブルビューのビューがテーブルビューセルと同じ境界を持たない理由です。

私の質問は、私がテーブルビューに提供するビューに制約を追加する方法です。テーブルビューを追加した後、ビューに再度アクセスできますか?これは少しハックされているようです。

Two views using autolayout.

AppDelegate.hのソースコード、

@jrturton

#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 

と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 

更新に制約を追加-(void) tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)rowが働いた。私は追加

With constraints added.

@swalkner

制約が非常に基本的なもの、

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

あなたの 'tableView:didAddRowView:forRow:'はどのように見えますか?私は同じことを達成したいと思いますが、それを働かせないでください。 – swalkner

+0

注目に値する。文字通り、ビューに制約を適用します(上記の私は編集を行いました)。 –

答えて

6

それはデリゲートメソッドでテーブルに追加された後は、ビューにアクセスすることができますtableView:willDisplayCell:forTableColumn:row: 。この時点で制約を追加することができますが、同じ制約を何度も何度も繰り返して追加しないように注意してください。

自分で見つけたので、tableView:didAddRowView:forRow:というメソッドは、新しいビューごとに1回だけ呼び出されるため、より良い場所になります。

また、水平サイズの制約の代わりに、ビューに柔軟な幅の自動サイズ変更マスクを設定することで、これを実現することもできます。テーブルは、セルビューを追加するときにこれを考慮に入れているでしょう。注意が必要な場合は、自動サイズ設定と制約を混在させることができます。

私はいくつかのiOS、いくつかのAutolayout、わずかなOS Xしか知っていないので、それ以上のことはできません。私たちはiOSの土地でセルの幅が大きく変わることを心配する必要はありません!

+0

iOSの世界からアドバイスをいただきありがとうございます。私がiOSについて学ぶほど、嫉妬深くなります。もっと現代的なAPIのようだ。私はOSXが追いついていると思う。 Lionの新機能NSTableViewDelegateでtableView:didAddRowView:forRow: が見つかりました。 –

+0

それは完璧に聞こえる。それがあなたのために働いていれば私は答えを更新します。そうすれば、今後の読者はコメントを打つ必要はありません。 – jrturton

+1

これは問題を解決しました。tableView:didAddRowView:forRow:ビューを追加した後で、実行ループが終了する前に呼び出されたようです。私は必要な制約を加えました。それはうまくいくようです。 –

関連する問題