NSTableView无法保留NSTableCellView,无法显示内容且选中时cell为nil
解决NSTableView不显示内容及选中行cell为nil的问题
我来帮你拆解下这两个问题的根源,以及对应的修复方案:
问题1:表格无法显示字符串
你在tableView:viewForTableColumn:row:方法里创建了NSTextField和NSTableCellView,但没有将textField添加到cell的contentView子视图中——这就相当于你把文本框创建出来了,但没把它放到cell的可视区域里,自然不会显示在界面上。另外,手动创建cell时最好加入复用逻辑(哪怕数据量小,这也是view-based表格的规范做法)。
问题2:选中行时cell对象为nil
selectedCell是基于NSCell的旧表格API,而你现在用的是view-based的NSTableView(通过viewForTableColumn:row:提供视图),所以这个属性会直接返回nil。正确的做法是通过选中行的索引,调用viewAtColumn:row:makeIfNecessary:来获取对应的cell视图。
修正后的完整代码
@implementation PreferencesSelectorPanel -(id)initWithWidth:(CGFloat)width { self = [super init]; if(self) { self.translatesAutoresizingMaskIntoConstraints = NO; self.autoresizesSubviews = YES; _preferenceTypes = @[@"Settings 1", @"Settings 2", @"Settings 3", @"Settings 4", @"Settings 5"]; _tv = [NSTableView new]; _tv.translatesAutoresizingMaskIntoConstraints = NO; _tv.autoresizesSubviews = YES; _tv.focusRingType = NSFocusRingTypeNone; _tv.delegate = self; _tv.dataSource = self; _tv.rowHeight = 40; _tv.headerView = nil; _tv.selectionHighlightStyle = NSTableViewSelectionHighlightStyleRegular; _tv.allowsColumnReordering = NO; _tv.allowsColumnResizing = NO; _tv.allowsEmptySelection = NO; _tv.allowsTypeSelect = NO; _tv.gridStyleMask = NSTableViewSolidHorizontalGridLineMask;//NSTableViewGridNone; NSTableColumn *col1 = [[NSTableColumn alloc] initWithIdentifier:@"c1"]; col1.resizingMask = NSTableColumnAutoresizingMask; [_tv addTableColumn:col1]; [self addSubview:_tv]; [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(10)-[_tv(200)]-(>=10)-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_tv)]]; [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(10)-[_tv]-(10)-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_tv)]]; // 注册cell复用(推荐做法) [_tv registerClass:[NSTableCellView class] forIdentifier:@"c1"]; } return self; } -(NSInteger)numberOfRowsInTableView:(NSTableView *)tv { NSLog(@"numberOfRowsInTableView"); return _preferenceTypes.count; } -(NSView *)tableView:(NSTableView *)tv viewForTableColumn:(NSTableColumn *)tc row:(NSInteger)row { // 复用cell(推荐做法) NSTableCellView *cell = [tv makeViewWithIdentifier:tc.identifier owner:self]; if (!cell) { cell = [NSTableCellView new]; cell.identifier = tc.identifier; // 创建textField并添加到contentView NSTextField *tf = [NSTextField labelWithString:_preferenceTypes[row]]; tf.translatesAutoresizingMaskIntoConstraints = NO; tf.textColor = [NSColor blackColor]; [cell.contentView addSubview:tf]; // 设置约束让textField填充cell的contentView,留边距 [NSLayoutConstraint activateConstraints:@[ [tf.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor constant:8], [tf.trailingAnchor constraintEqualToAnchor:cell.contentView.trailingAnchor constant:-8], [tf.centerYAnchor constraintEqualToAnchor:cell.contentView.centerYAnchor] ]]; cell.textField = tf; } else { // 复用cell时更新文本 cell.textField.stringValue = _preferenceTypes[row]; } NSLog(@"Row for row %d with label:%@",(int)row, cell.textField.stringValue); return cell; } -(void)tableViewSelectionDidChange:(NSNotification *)notification { NSTableView *tableView = notification.object; NSInteger selectedRow = tableView.selectedRow; if (selectedRow != -1) { // 获取选中行的cell NSTableCellView *cell = (NSTableCellView *)[tableView viewAtColumn:0 row:selectedRow makeIfNecessary:NO]; if (cell) { NSLog(@"%@", cell.textField.stringValue); } else { NSLog(@"Cell not available"); } } } @end
关键修改点说明
- 显示问题修复:将textField添加到cell的
contentView,并通过Auto Layout约束让它正确适配cell的空间;同时加入了cell复用逻辑,避免重复创建对象。 - 选中行cell获取修复:改用
viewAtColumn:row:makeIfNecessary:方法获取选中行的cell,并且先判断选中行是否有效(避免无选中时的错误)。
这样修改后,表格应该能正常显示所有字符串,选中行时也能正确获取到cell并打印文本内容了。
内容的提问来源于stack exchange,提问作者Cliff Ribaudo
相关产品推荐
相关产品推荐

