ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# NSTableView [TOC] # 简单上手 首先,我们上手做一个如下的简单tableView,然后对部分细节、属性进行详解。 ## 1、 创建基本的tableView 效果如下: ![NSTableView_Simple](/Users/MelissaShu/macos/NSTableView_Simple.png) 1.1 设置tableView 为成员变量,并添加协议 ``` @interface SecWindowController ()<NSTableViewDelegate,NSTableViewDataSource> @property (nonatomic,strong) NSTableView *tableView; @end ``` 1.2 懒加载初始化tableView并添加相关设置 ``` #pragma mark - Getter - (NSTableView *)tableView { if(!_tableView){ _tableView = [[NSTableView alloc] initWithFrame:CGRectMake(10, 10, 200, 200)]; } return _tableView; } - (void)windowDidLoad { [super windowDidLoad]; [self tableViewSetting]; } - (void)tableViewSetting{ self.window.backgroundColor = [NSColor cyanColor]; //第一列 NSTableColumn *column1 = [[NSTableColumn alloc] initWithIdentifier:@"columnFrist"]; column1.title = @"columnFrist"; [column1 setWidth:100]; [self.tableView addTableColumn:column1]; //第二列 NSTableColumn * column2 = [[NSTableColumn alloc] initWithIdentifier:@"columnSecond"]; column2.title = @"columnSecond"; //如果为空,则默认显示‘Field’ [column2 setWidth:70]; [self.tableView addTableColumn:column2]; //第三列 NSTableColumn * column3 = [[NSTableColumn alloc] initWithIdentifier:@"column3"]; column3.title = @"column3"; [column3 setWidth:80]; [self.tableView addTableColumn:column3]; self.tableView.focusRingType = NSFocusRingTypeNone;//tableview获得焦点时的风格 self.tableView.selectionHighlightStyle = NSTableViewSelectionHighlightStyleRegular;//行高亮的风格 self.tableView.backgroundColor = [NSColor orangeColor]; self.tableView.usesAlternatingRowBackgroundColors = YES; //背景颜色的交替,一行白色,一行灰色。设置后,原来设置的 backgroundColor 就无效了。 self.tableView.delegate = self; self.tableView.dataSource = self; self.tableView.gridColor = [NSColor magentaColor]; //实现tableview的滚动效果 NSScrollView *tableContainerView = [[NSScrollView alloc] initWithFrame:CGRectMake(5, 5, 300, 300)]; tableContainerView.backgroundColor = [NSColor redColor]; [tableContainerView setDocumentView:self.tableView]; [tableContainerView setDrawsBackground:NO];//不画背景(背景默认画成白色) [tableContainerView setHasVerticalScroller:YES];//有垂直滚动条 //[_tableContainer setHasHorizontalScroller:YES];  //有水平滚动条 tableContainerView.autohidesScrollers = YES;//自动隐藏滚动条(滚动的时候出现) [self.window.contentView addSubview:tableContainerView]; } ``` 1.3 实现数据源、代理、通知方法 ``` #pragma mark - NSTableViewDelegate,NSTableViewDataSource //返回行数 -(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{ return 15; } -(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{ //获取表格列的标识符 NSString *columnID = tableColumn.identifier; NSLog(@"columnID : %@ ,row : %d",columnID,row); NSString *strIdt = @"123"; NSTableCellView *cell = [tableView makeViewWithIdentifier:strIdt owner:self]; if (!cell) { cell = [[NSTableCellView alloc]init]; cell.identifier = strIdt; } cell.wantsLayer = YES; cell.layer.backgroundColor = [NSColor yellowColor].CGColor; cell.imageView.image = [NSImage imageNamed:@"swift"]; cell.textField.stringValue = [NSString stringWithFormat:@"cell %ld",(long)row]; return cell; } #pragma mark - 行高 -(CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row{ return 44; } #pragma mark - 是否可以选中单元格 -(BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row{ //设置cell选中高亮颜色 NSTableRowView *myRowView = [self.tableView rowViewAtRow:row makeIfNecessary:NO]; [myRowView setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleRegular]; [myRowView setEmphasized:NO]; NSLog(@"shouldSelect : %d",row); return YES; } //选中的响应 -(void)tableViewSelectionDidChange:(nonnull NSNotification *)notification{ NSTableView* tableView = notification.object; NSLog(@"didSelect:%@",notification.userInfo); } ``` *** ## 2、一些细节 - tableView 必须添加到 scrollView 中,才能够显示和滑动。 - tableView 的尺寸为 scrollView 的尺寸,非 tableView初始化时的尺寸。 - 设置 usesAlternatingRowBackgroundColors = YES 时,实现背景颜色的交替(如numbers效果)。但是原来设置的 backgroundColor 就无效了。 - 如果没有设置 column 的 title,默认显示为 “Field” 。 - 如果不想显示表头header,设置rect为0即可,如`self.tableView.headerView.frame = NSZeroRect;` - 如果tableView的x,y值不为0,header显示的内容将会被掩盖一部分。可以尝试。 - ​ *** # 和iOS的不同点 - Mac OS的tableView需要一个Container来包裹它,才可以滑动,而iOS的不用 - Mac OS的tableview里面多了一个概念叫做column(列),而iOS中没有这个概念 - iOS中有section的概念,可是Mac OS中没有(NSCollectionView中有) ------ # 基本属性 & 常见概念 *** ## tableView 视图基本结构 ![NSTableView解剖](/Users/MelissaShu/macos/NSTableView解剖.png) *** ## Cell-Base & View-Base *** ### Cell-Base:基于Cell的TableView视图 Cell-Base 是早期常用的方式,其中每一行的数据载体都**必须是NSCell的子类**。但更老、更轻量。 Cell-Base的TableView必须实现的两个数据源方法是`numberOfRowsInTableView` 和 `objectValueForTableColumn` 方法,第一个方法设置列表行数,第2个方法设置每个数据载体对应的具体数据。 如: ``` -(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{ return 15; } - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { NSString *rowData = [NSString stringWithFormat:@"%@ - %d",tableColumn.title,row]; return rowData; } ``` *** ### View-Base:基于View的TableView视图 ​ 基于View-Base的TableView要比基于Cell的TableView更加灵活,其中每行数据载体可以是**任意NSView的子类**。 *** ## NSTableViewColumn 列由 `NSTableViewColumn` 类表示,负责管理列的宽度和行为,例如调整大小和位置。 这个类不是视图,而是**控制器类**。 使用它指定列的行为,但是不能控制列的视觉样式,因为它已经被包含在头部、行和单元格视图中了。 *** ## NSTableCellView - *** ## NSTableRowView - 行容器 NSTableRowView用在View-Base的TableView中,其作为**行容器**存在。 在这里设置背景色,和选中的背景色。 *** # 自定义 tableView 如实现 显示文字的tableView ![NSTableView_Custom1](/Users/MelissaShu/macos/NSTableView_Custom1.png) ## 自定义 NSTableCellView 1、创建类 CustomTableCellView 继承自 NSTableCellView,添加 NSString 和 NSTextField 等类型成员变量; ``` @interface CustomTableCellView : NSTableCellView @property (nonatomic, strong) NSString *string; @property (nonatomic, strong) NSTextField *label; @end ``` 2、添加控件到cell中,并添加设置方法 ``` -(instancetype)initWithFrame:(NSRect)frameRect{ self = [super initWithFrame:frameRect]; if (self) { [self addSubview:self.label]; } return self; } - (void)setString:(NSString *)string { self.label.frame = self.bounds; self.label.stringValue = string; } //懒加载设置label -(NSTextField *)label { if (!_label) { _label = [[NSTextField alloc] initWithFrame:NSZeroRect]; _label.editable = NO; _label.bordered = YES; _label.backgroundColor = [NSColor purpleColor]; } return _label; } ``` ## 自定义 NSTableRowView 1、创建类 CustomTableRowView 继承自 NSTableRowView 2、在.m 文件中添加如下代码: ``` // 自定义 row 被选中的背景色 -(void)drawSelectionInRect:(NSRect)dirtyRect { if (self.selectionHighlightStyle != NSTableViewSelectionHighlightStyleNone) { [[NSColor cyanColor] setFill]; NSBezierPath *path = [NSBezierPath bezierPathWithRect:NSInsetRect(self.bounds, 0, 0)]; [path fill]; [path stroke]; } } //自定义 row 背景色 - (void)setBackgroundColor:(NSColor *)backgroundColor { super.backgroundColor = [NSColor yellowColor]; } ``` ## 基本属性 ``` @property NSTableViewSelectionHighlightStyle selectionHighlightStyle; //是否强调 @property(getter=isEmphasized) BOOL emphasized; //设置是否行组风格 @property(getter=isGroupRowStyle) BOOL groupRowStyle; //是否选中状态 @property(getter=isSelected) BOOL selected; //其前一行的选中状态 @property(getter=isPreviousRowSelected) BOOL previousRowSelected; //其后一行的选中状态 @property(getter=isNextRowSelected) BOOL nextRowSelected; //设置此行是否浮动 @property(getter=isFloating) BOOL floating; //拖放拖动效果 @property(getter=isTargetForDropOperation) BOOL targetForDropOperation; //拖放风格 @property NSTableViewDraggingDestinationFeedbackStyle draggingDestinationFeedbackStyle; //设置拖放目标的缩进量 @property CGFloat indentationForDropOperation; //背景色 @property(copy) NSColor *backgroundColor; //子类重写下面方法来进行行容器视图的自定义 //画背景色 - (void)drawBackgroundInRect:(NSRect)dirtyRect; //画选中背景 - (void)drawSelectionInRect:(NSRect)dirtyRect; //画分割线 - (void)drawSeparatorInRect:(NSRect)dirtyRect; //绘制拖放时的用户反馈IU - (void)drawDraggingDestinationFeedbackInRect:(NSRect)dirtyRect; //列数 @property(readonly) NSInteger numberOfColumns; //提供的访问特定视图的方法 - (nullable id)viewAtColumn:(NSInteger)column; ``` *** ## NSTableViewDataSource ``` /* 无论基于Cell还是基于View,这个方法都需要实现,用来设置列表的行数 */ - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView; /* 如果使用cell-base的TableView视图,这个方法是必须实现的,其为要渲染的cell提供数据 */ - (nullable id)tableView:(NSTableView *)tableView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row; /* 这个函数当用户编辑了cell中的内容时会被调用,一般需要在其中进行数据源的修改 */ - (void)tableView:(NSTableView *)tableView setObjectValue:(nullable id)object forTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row; /* 当用户修改了行排序规则时调用的回调 */ - (void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray<NSSortDescriptor *> *)oldDescriptors; //下面这些方法全部与列表的数据拖拽相关 - (nullable id <NSPasteboardWriting>)tableView:(NSTableView *)tableView pasteboardWriterForRow:(NSInteger)row; - (void)tableView:(NSTableView *)tableView draggingSession:(NSDraggingSession *)session willBeginAtPoint:(NSPoint)screenPoint forRowIndexes:(NSIndexSet *)rowIndexes NS_AVAILABLE_MAC(10_7); - (void)tableView:(NSTableView *)tableView draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation NS_AVAILABLE_MAC(10_7); - (void)tableView:(NSTableView *)tableView updateDraggingItemsForDrag:(id <NSDraggingInfo>)draggingInfo NS_AVAILABLE_MAC(10_7); - (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard; - (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation; - (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id <NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation; - (NSArray<NSString *> *)tableView:(NSTableView *)tableView namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination forDraggedRowsWithIndexes:(NSIndexSet *)indexSet; ``` *** ## NSTableViewDelegate ``` //view-base的TableView相关delegate方法 /* 设置每个数据载体的View */ - (nullable NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row; /* 自定义行视图 */ - (nullable NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row NS_AVAILABLE_MAC(10_7); /* 添加一行时会调用的回调 */ - (void)tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row; /* 移除一行时会调用的回调 */ - (void)tableView:(NSTableView *)tableView didRemoveRowView:(NSTableRowView *)rowView forRow:(NSInteger)row; //cell-base的TableView相关delegate方法 /* cell将要渲染时调用的回调,可以在其中对cell进行定制 */ - (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row; /* 设置某个cell是否可以编辑 */ - (BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row; /* 设置当鼠标悬停在cell上时 显示的提示文案 */ - (NSString *)tableView:(NSTableView *)tableView toolTipForCell:(NSCell *)cell rect:(NSRectPointer)rect tableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row mouseLocation:(NSPoint)mouseLocation; /* 当cell的宽度不够显示完全cell的内容时,设置是否允许鼠标放置扩展cell */ - (BOOL)tableView:(NSTableView *)tableView shouldShowCellExpansionForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row; /* 设置是否加强cell的交互能力,这样一些按钮状态的修改也会触发cell编辑的状态 */ - (BOOL)tableView:(NSTableView *)tableView shouldTrackCell:(NSCell *)cell forTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row; /* 设置自定义cell */ - (nullable NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row; //通用的TableView代理方法 /* 设置是否允许修改选中 */ - (BOOL)selectionShouldChangeInTableView:(NSTableView *)tableView; /* 设置某行是否可以选中 */ - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row; /* 当用户通过键盘或鼠标将要选中某行时,返回设置要选中的行 如果实现了这个方法,上面一个方法将不会被调用 */ - (NSIndexSet *)tableView:(NSTableView *)tableView selectionIndexesForProposedSelection:(NSIndexSet *)proposedSelectionIndexes; /* 设置某列是否可以被选中 */ - (BOOL)tableView:(NSTableView *)tableView shouldSelectTableColumn:(nullable NSTableColumn *)tableColumn; /* 用户点击列头时调用的方法 */ - (void)tableView:(NSTableView *)tableView mouseDownInHeaderOfTableColumn:(NSTableColumn *)tableColumn; /* 用法同上 */ - (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn; /* 对列进行拖拽改变顺序时调用的方法 */ - (void)tableView:(NSTableView *)tableView didDragTableColumn:(NSTableColumn *)tableColumn; /* 设置行高 */ - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row; /* 下面这些方法与行检索有关 */ - (nullable NSString *)tableView:(NSTableView *)tableView typeSelectStringForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row NS_AVAILABLE_MAC(10_5); - (NSInteger)tableView:(NSTableView *)tableView nextTypeSelectMatchFromRow:(NSInteger)startRow toRow:(NSInteger)endRow forString:(NSString *)searchString NS_AVAILABLE_MAC(10_5); - (BOOL)tableView:(NSTableView *)tableView shouldTypeSelectForEvent:(NSEvent *)event withCurrentSearchString:(nullable NSString *)searchString NS_AVAILABLE_MAC(10_5); /* 设置某行是否绘制成组样式 */ - (BOOL)tableView:(NSTableView *)tableView isGroupRow:(NSInteger)row; /* 调整列宽度 */ - (CGFloat)tableView:(NSTableView *)tableView sizeToFitWidthOfColumn:(NSInteger)column; /* 设置是否支持列的移动排序 */ - (BOOL)tableView:(NSTableView *)tableView shouldReorderColumn:(NSInteger)columnIndex toColumn:(NSInteger)newColumnIndex; //设置某行向左或向右滑动时要显示的功能按钮 /* typedef NS_ENUM(NSInteger, NSTableRowActionEdge) { NSTableRowActionEdgeLeading, // 左划 NSTableRowActionEdgeTrailing, // 右划 } NS_ENUM_AVAILABLE_MAC(10_11); */ - (NSArray<NSTableViewRowAction *> *)tableView:(NSTableView *)tableView rowActionsForRow:(NSInteger)row edge:(NSTableRowActionEdge)edge NS_AVAILABLE_MAC(10_11); /* TableView选中修改时调用 */ - (void)tableViewSelectionDidChange:(NSNotification *)notification; /* TableView列移动完成时调用的函数 */ - (void)tableViewColumnDidMove:(NSNotification *)notification; /* TableView列宽度变化时调用的函数 */ - (void)tableViewColumnDidResize:(NSNotification *)notification; /* TableView选中正在修改时调用的函数 */ - (void)tableViewSelectionIsChanging:(NSNotification *)notification; ``` *** ## 使用示例 ### 获取点击事件 点击的交互可以通过通知 `tableViewSelectionDidChange` 获取: ``` - (void)tableViewSelectionDidChange:(NSNotification *)notification { NSTableView *tableView = notification.object; NSLog(@"---selection row %ld", tableView.selectedRow); // CustomTableCellView *contentView = [tableView makeViewWithIdentifier:@"name" owner:self]; CustomTableCellView *contentView = [tableView viewAtColumn:0 row:tableView.selectedRow makeIfNecessary:NO]; contentView.label.wantsLayer = YES; contentView.label.textColor = [NSColor blueColor]; } ``` ## 相关通知 ``` //列表选择改变后发的通知 APPKIT_EXTERN NSNotificationName NSTableViewSelectionDidChangeNotification; //列移动后发的通知 APPKIT_EXTERN NSNotificationName NSTableViewColumnDidMoveNotification; //列宽度改变后发的通知 APPKIT_EXTERN NSNotificationName NSTableViewColumnDidResizeNotification; //选择改变时发的通知 APPKIT_EXTERN NSNotificationName NSTableViewSelectionIsChangingNotification; ``` *** # 相关样式枚举 ## NSTableColumnResizingOptions - 设置列尺寸的调整模式 @property NSTableColumnResizingOptions resizingMask; ``` typedef NS_OPTIONS(NSUInteger, NSTableColumnResizingOptions) { NSTableColumnNoResizing = 0, //不允许进行宽度调整 //详见NSTabelView的columnAutoresizingStyle属性 NSTableColumnAutoresizingMask = ( 1 << 0 ), //使用tableView的column调整策略 NSTableColumnUserResizingMask = ( 1 << 1 ), //允许用户进行尺寸调整 }; ``` *** ## NSTableViewColumnAutoresizingStyle @property NSTableViewColumnAutoresizingStyle columnAutoresizingStyle; ``` typedef NS_ENUM(NSUInteger, NSTableViewColumnAutoresizingStyle) { //不可调整 NSTableViewNoColumnAutoresizing = 0, //平分 NSTableViewUniformColumnAutoresizingStyle, //从后往前调整 NSTableViewSequentialColumnAutoresizingStyle, //从前往后调整 NSTableViewReverseSequentialColumnAutoresizingStyle, //最后一列可调整 NSTableViewLastColumnOnlyAutoresizingStyle, //第一列可调整 NSTableViewFirstColumnOnlyAutoresizingStyle }; ``` *** ## NSTableViewGridLineStyle - 设置分割线风格 ``` typedef NS_OPTIONS(NSUInteger, NSTableViewGridLineStyle) { //无分割线 NSTableViewGridNone = 0, //竖直分割线 NSTableViewSolidVerticalGridLineMask = 1 << 0, //水平分割线 NSTableViewSolidHorizontalGridLineMask = 1 << 1, //水平虚线分割线 NSTableViewDashedHorizontalGridLineMask , }; ``` *** ## NSTableViewRowSizeStyle @property NSTableViewRowSizeStyle rowSizeStyle; ``` typedef NS_ENUM(NSInteger, NSTableViewRowSizeStyle) { //默认 NSTableViewRowSizeStyleDefault = -1, //自定义 NSTableViewRowSizeStyleCustom = 0, //小尺寸风格 NSTableViewRowSizeStyleSmall = 1, //中等尺寸风格 NSTableViewRowSizeStyleMedium = 2, //大尺寸风格 NSTableViewRowSizeStyleLarge = 3, } NS_ENUM_AVAILABLE_MAC(10_7); ``` *** ## NSTableViewSelectionHighlightStyle - 选中的高亮风格 @property NSTableViewSelectionHighlightStyle selectionHighlightStyle; ``` typedef NS_ENUM(NSInteger, NSTableViewSelectionHighlightStyle) { //无高亮风格 NSTableViewSelectionHighlightStyleNone, //规则的高亮风格 NSTableViewSelectionHighlightStyleRegular = 0, //源列表风格 NSTableViewSelectionHighlightStyleSourceList = 1, ``` *** # 参考资料 - 珲少:macOS开发之NSTableView的应用详解 https://my.oschina.net/u/2340880/blog/886861