1. 程式人生 > >macOS開發之NSTableView的應用詳解 - 轉

macOS開發之NSTableView的應用詳解 - 轉

validate creat 編寫 移除 分割線 gen styles 如果 bool

傳送門:https://my.oschina.net/u/2340880/blog/886861

摘要: NSTableView是AppKit中的表視圖控件,是macOS開發中非常重要的一種視圖控件。熟練應用NSTableView控件對mac軟件開發十分重要。

NSTableView的應用詳解

一、引言

和iOS開發中的UITableView有很大差別,NSTableView並非是一個可滾動的列表視圖,其是一個不可滾動、支持多列多行的原始列表視圖。若要使NSTableView支持滾動,通常會將其嵌套入NSScrollView控件中。與UITableView類似,NSTableView的數據也是用過DataSource代理來提供,通過Delegate代理來進行表格視圖的定制化。在OS X v10.6版本之前,NSTableView中行數據載體視圖必須是NSCell的子類,之後版本的OS X支持開發者創建基於View的TableView視圖,同樣也支持基於Cell的TabelView視圖,在開發者,我們可以根據實際需求選擇。

二、構建一個簡單的列表視圖

首先新建一個測試工程,在ViewController.m文件中編寫如下代碼:

#import "ViewController.h"

@interface ViewController()<NSTableViewDelegate,NSTableViewDataSource>

@end

@implementation ViewController
{
    NSTableView * _tableView;
    NSMutableArray * _dataArray;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    _dataArray 
= [NSMutableArray array]; for (int i=0; i<20; i++) { [_dataArray addObject:[NSString stringWithFormat:@"%d行數據",i]]; } NSScrollView * scrollView = [[NSScrollView alloc] init]; scrollView.hasVerticalScroller = YES; scrollView.frame = self.view.bounds; [self.view addSubview:scrollView]; _tableView
= [[NSTableView alloc]initWithFrame:self.view.bounds]; NSTableColumn * column = [[NSTableColumn alloc]initWithIdentifier:@"test"]; [_tableView addTableColumn:column]; _tableView.delegate = self; _tableView.dataSource = self; [_tableView reloadData]; scrollView.contentView.documentView = _tableView; } -(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{ return _dataArray.count; } -(id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{ return _dataArray[row]; } @end

運行工程效果如下圖:

技術分享

這是一個最簡單的TableView示例,但是細讀代碼,麻雀雖小五臟俱全。首先NSTableView中的列是由NSTableColumn類描述的。一個列表可以有多個列。也正如前面所說,numberOfRowsInTableView方法為數據源代理必須實現的方法,其中需要返回列表的行數。objectValueForTableColumn方法則是基於Cell的TableView必須實現的方法,其中需要返回每個列表行所填充的數據。

三、關於NSTableColume的探究

NSTableColume簡單理解就是一列,其中可以進行此列樣式的相關設置,NSTableColumn類中常用屬性解析如下:

//初始化方法,指定一個列ID
- (instancetype)initWithIdentifier:(NSString *)identifier;
//與此列關聯的ID
@property (copy) NSString *identifier;
//關聯的TableView
@property (nullable, assign) NSTableView *tableView;
//設置列寬度
@property CGFloat width;
//設置最小列寬度
@property CGFloat minWidth;
//設置最大列寬度
@property CGFloat maxWidth;
//設置類標題
@property (copy) NSString *title;
/*
列標題視圖 開發者可以對其進行修改
需要註意,NSTableHeaderCell是繼承自NSTextFieldCell
*/
@property (strong) __kindof NSTableHeaderCell *headerCell;
//設置此列是否可以進行編輯
@property (getter=isEditable) BOOL editable;
//進行列尺寸的調整 以列標題視圖的寬度為標準 
- (void)sizeToFit;
//提供了這個屬性,會在列標題那裏顯示一個排序按鈕 點擊列標題後可以進行排序操作(會回調相關協議方法)
@property (nullable, copy) NSSortDescriptor *sortDescriptorPrototype;
//設置列尺寸的調整模式 枚舉如下
/*
typedef NS_OPTIONS(NSUInteger, NSTableColumnResizingOptions) {
    NSTableColumnNoResizing = 0, //不允許進行寬度調整
    //詳見NSTabelView的columnAutoresizingStyle屬性
    NSTableColumnAutoresizingMask = ( 1 << 0 ), //使用tableView的column調整策略
    NSTableColumnUserResizingMask = ( 1 << 1 ), //允許用戶進行尺寸調整
};
*/
@property NSTableColumnResizingOptions resizingMask;
//設置列頭的提示標題 當鼠標懸停在類標題上時  會顯示此提示
@property (nullable, copy) NSString *headerToolTip;
//設置此列是否隱藏
@property (getter=isHidden) BOOL hidden;
//設置此列所有行的數據載體視圖 如果不設置 默認為NSTextFieldCell
@property (strong) id dataCell;
//為TableView列表提供數據載體視圖
- (id)dataCellForRow:(NSInteger)row;

四、Cell-Base:基於Cell的TableView視圖

Cell-Base是OS X早起版本中常用的構造TabelView的方式,其中每一行的數據載體都必須是NSCell的子類。如本文開頭的示例代碼,Cell-Base的TableView必須實現的兩個協議方法是numberOfRowsInTableView和objectValueForTableColumn方法,第一個方法設置列表行數,第2個方法設置每個數據載體對應的具體數據。需要註意,如果只實現這兩個方法,則NSTableView會自動從列對象NSTableColume中取具體的行視圖,通過dataCellForRow方法。當objectValueForTableColumn方法將每個行具體的數據返回後,會調用cell的setObjectValue方法(因此如果要自定義cell,必須實現這個方法)。如果我們要對Cell的渲染進行一些定制,可以在如下方法中實現:

//將要渲染cell調用的方法 開發者可以拿到cell對象做定制
- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row;
實現下面的方法可以返回一個自定義的Cell,如果實現了這個方法,則TableView不會再從NSTableColumn對象中拿Cell實例:

//返回自定義的Cell實例
/*
需要註意,這個方法在第一次調用的時候 tableColumu對象是nil 如果這時返回了Cell,則此Cell寬度會覆蓋整個列表
在使用時要多加註意
*/
- (nullable NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row;
其他方法的實例代碼如下:

#import "ViewController.h"
#import "MyCell.h"
@interface ViewController()<NSTableViewDelegate,NSTableViewDataSource>

@end

@implementation ViewController
{
    NSTableView * _tableView;
    NSMutableArray * _dataArray;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    _dataArray = [NSMutableArray array];
    for (int i=0; i<20; i++) {
        [_dataArray addObject:[NSString stringWithFormat:@"%d行數據",i]];
    }
    NSScrollView * scrollView    = [[NSScrollView alloc] init];
    scrollView.hasVerticalScroller  = YES;
    scrollView.frame = self.view.bounds;
    [self.view addSubview:scrollView];
    _tableView = [[NSTableView alloc]initWithFrame:self.view.bounds];
    NSTableColumn * column = [[NSTableColumn alloc]initWithIdentifier:@"test"];
    NSTableColumn * column2 = [[NSTableColumn alloc]initWithIdentifier:@"test2"];
    column2.width = 100;
    column2.minWidth = 100;
    column2.maxWidth = 100;
    column2.title = @"數據";
    column2.editable = YES ;
    column2.headerToolTip = @"提示";
    column2.hidden=NO;
    column2.sortDescriptorPrototype = [NSSortDescriptor sortDescriptorWithKey:@"title" ascending:NO];
    column.resizingMask =NSTableColumnUserResizingMask;
//    column.dataCell = [[NSButtonCell alloc]initTextCell:@""];
    [_tableView addTableColumn:column];
    [_tableView addTableColumn:column2];
    _tableView.delegate = self;
    _tableView.dataSource = self;
    scrollView.contentView.documentView = _tableView;
}

//設置行數 通用
-(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
    return _dataArray.count;
}
//綁定數據
-(id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
    return _dataArray[row];
}
//用戶編輯列表
- (void)tableView:(NSTableView *)tableView setObjectValue:(nullable id)object forTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row{
    NSLog(@"%@",object);
    _dataArray[row] = object;
}
//cell-base的cell展示前調用 可以進行自定制
- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row{
    NSTextFieldCell * _cell = cell;
   _cell.textColor = [NSColor redColor];
}
//設置是否可以進行編輯
- (BOOL)tableView:(NSTableView *)tableView shouldEditTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row{
    return YES;
}
//設置鼠標懸停在cell上顯示的提示文本
- (NSString *)tableView:(NSTableView *)tableView toolTipForCell:(NSCell *)cell rect:(NSRectPointer)rect tableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row mouseLocation:(NSPoint)mouseLocation{
    return @"tip";
}
//當列表長度無法展示完整某行數據時 當鼠標懸停在此行上 是否擴展顯示
- (BOOL)tableView:(NSTableView *)tableView shouldShowCellExpansionForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row{
    return YES;
}
//設置cell的交互能力
/*
如果返回YES,則Cell的交互能力會變強,例如NSButtonCell的點擊將會調用- (void)tableView:(NSTableView *)tableView setObjectValue方法
*/
- (BOOL)tableView:(NSTableView *)tableView shouldTrackCell:(NSCell *)cell forTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row{
    return YES;
}
//自定義cell
- (nullable NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row{
    if (tableColumn!=nil) {
        MyCell * cell = [[MyCell alloc]init];
        return cell;
    }
    return nil;
    
}
-(CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row{
    return 30;
}
//排序回調函數
-(void)tableView:(NSTableView *)tableView sortDescriptorsDidChange:(NSArray<NSSortDescriptor *> *)oldDescriptors{
    NSLog(@"%@",oldDescriptors[0]);
}

@end

五、View-Base:基於View的TableView視圖

基於View-Base的TableView要比基於Cell的TableView更加靈活,其中每行數據載體可以是任意NSView的子類。代碼示例如下:

//
//  ViewController.m
//  TableView
//
//  Created by jaki on 17/4/14.
//  Copyright ? 2017年 jaki. All rights reserved.
//

#import "ViewController.h"
#import "MyCell.h"
#import "TableRow.h"
@interface ViewController()<NSTableViewDelegate,NSTableViewDataSource>

@end

@implementation ViewController
{
    NSTableView * _tableView;
    NSMutableArray * _dataArray;
}
- (void)viewDidLoad {
    [super viewDidLoad];
    _dataArray = [NSMutableArray array];
    for (int i=0; i<20; i++) {
        [_dataArray addObject:[NSString stringWithFormat:@"%d行數據",i]];
    }
    NSScrollView * scrollView    = [[NSScrollView alloc] init];
    scrollView.hasVerticalScroller  = YES;
    scrollView.frame = self.view.bounds;
    [self.view addSubview:scrollView];
    _tableView = [[NSTableView alloc]initWithFrame:self.view.bounds];
    NSTableColumn * column = [[NSTableColumn alloc]initWithIdentifier:@"test"];
    NSTableColumn * column2 = [[NSTableColumn alloc]initWithIdentifier:@"test2"];
    column2.width = 100;
    column2.minWidth = 100;
    column2.maxWidth = 100;
    column2.title = @"數據";
    column2.editable = YES ;
    column2.headerToolTip = @"提示";
    column2.hidden=NO;
    column2.sortDescriptorPrototype = [NSSortDescriptor sortDescriptorWithKey:@"title" ascending:NO];
    column.resizingMask =NSTableColumnUserResizingMask;
    _tableView.delegate = self;
    _tableView.dataSource = self;
    [_tableView addTableColumn:column];
    [_tableView addTableColumn:column2];
    scrollView.contentView.documentView = _tableView;
}

//設置行數 通用
-(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
    return _dataArray.count;
}
//View-base
//設置某個元素的具體視圖
- (nullable NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row{
    //根據ID取視圖
    NSTextField * view = [tableView makeViewWithIdentifier:@"cellId" owner:self];
    if (view==nil) {
        view = [[NSTextField alloc]initWithFrame:CGRectMake(0, 0, 100, 30)];
        view.backgroundColor = [NSColor clearColor];
        view.identifier = @"cellId";
    }
    return view;
}
//設置每行容器視圖
- (nullable NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row{
    TableRow * rowView = [[TableRow alloc]init];
    return rowView;
}
//當添加行時調用的回調
- (void)tableView:(NSTableView *)tableView didAddRowView:(NSTableRowView *)rowView forRow:(NSInteger)row{
    NSLog(@"add");
}
//當移除行時調用的回調
- (void)tableView:(NSTableView *)tableView didRemoveRowView:(NSTableRowView *)rowView forRow:(NSInteger)row{
    NSLog(@"remove");
}
@end
上面代碼中用到了TableRow類,其實它是一個自定義的繼承自NSTableRowView的類,實現如下:

#import "TablerRow.h"
@implementation TablerRow
//繪制選中狀態的背景
-(void)drawSelectionInRect:(NSRect)dirtyRect{
    NSRect selectionRect = NSInsetRect(self.bounds, 5.5, 5.5);
    [[NSColor colorWithCalibratedWhite:.72 alpha:1.0] setStroke];
    [[NSColor colorWithCalibratedWhite:.82 alpha:1.0] setFill];
    NSBezierPath *selectionPath = [NSBezierPath bezierPathWithRoundedRect:selectionRect xRadius:10 yRadius:10];
    [selectionPath fill];
    [selectionPath stroke];
}
//繪制背景
-(void)drawBackgroundInRect:(NSRect)dirtyRect{
    [super drawBackgroundInRect:dirtyRect];
    [[NSColor greenColor]setFill];
    NSRectFill(dirtyRect);
}
@end

關於NSTableRowView類我們下面來做具體介紹。

六、NSTableRowView解析

NSTableRowView用在View-Base的TableView中,其作為行容器存在。

//選中的高亮風格
/*
typedef NS_ENUM(NSInteger, NSTableViewSelectionHighlightStyle) {
    //無高亮風格
    NSTableViewSelectionHighlightStyleNone,
    //規則的高亮風格
    NSTableViewSelectionHighlightStyleRegular = 0,
    //源列表風格
    NSTableViewSelectionHighlightStyleSourceList = 1,
};
*/
@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;

九、NSTableView中常用的屬性和方法

//初始化方法
- (instancetype)initWithFrame:(NSRect)frameRect;
- (nullable instancetype)initWithCoder:(NSCoder *)coder;

//設置代理
@property (nullable, weak) id <NSTableViewDataSource> dataSource;
@property (nullable, weak) id <NSTableViewDelegate> delegate;

//設置TableView的頭視圖 會被列頭圖就行覆蓋
@property (nullable, strong) NSTableHeaderView *headerView;
//設置頭圖右側視圖 可以自定義圖標
@property (nullable, strong) NSView *cornerView;
//設置是否允許列拖拽排序
@property BOOL allowsColumnReordering;
//設置是否允許調整列寬度
@property BOOL allowsColumnResizing;
//調整列寬度的風格
/*
typedef NS_ENUM(NSUInteger, NSTableViewColumnAutoresizingStyle) {
    //不可調整
    NSTableViewNoColumnAutoresizing = 0,
    //平分
    NSTableViewUniformColumnAutoresizingStyle,
    //從後往前調整
    NSTableViewSequentialColumnAutoresizingStyle,  
    //從前往後調整
    NSTableViewReverseSequentialColumnAutoresizingStyle, 
    //最後一列可調整
    NSTableViewLastColumnOnlyAutoresizingStyle,
    //第一列可調整
    NSTableViewFirstColumnOnlyAutoresizingStyle
};
*/
@property NSTableViewColumnAutoresizingStyle columnAutoresizingStyle;
//設置分割線風格
/*
typedef NS_OPTIONS(NSUInteger, NSTableViewGridLineStyle) {
    //無分割線
    NSTableViewGridNone                    = 0,
    //豎直分割線
    NSTableViewSolidVerticalGridLineMask   = 1 << 0,
    //水平分割線
    NSTableViewSolidHorizontalGridLineMask = 1 << 1,
    //水平虛線分割線
    NSTableViewDashedHorizontalGridLineMask ,
};
*/
@property NSTableViewGridLineStyle gridStyleMask;
//設置cell之間的間隔 需要設置為NSSize對象
@property NSSize intercellSpacing;
//是否開啟斑馬紋
@property BOOL usesAlternatingRowBackgroundColors;
//背景色
@property (copy) NSColor *backgroundColor;
//設置分割線顏色
@property (copy) NSColor *gridColor;
//設置行尺寸風格
/*
typedef NS_ENUM(NSInteger, NSTableViewRowSizeStyle) {
    //默認
    NSTableViewRowSizeStyleDefault = -1,
    //自定義
    NSTableViewRowSizeStyleCustom = 0,
    //小尺寸風格
    NSTableViewRowSizeStyleSmall = 1,
    //中等尺寸風格
    NSTableViewRowSizeStyleMedium = 2,
    //大尺寸風格
    NSTableViewRowSizeStyleLarge = 3,
} NS_ENUM_AVAILABLE_MAC(10_7);
*/
@property NSTableViewRowSizeStyle rowSizeStyle;
//行高
@property CGFloat rowHeight;
//獲取所有列對象
@property (readonly, copy) NSArray<NSTableColumn *> *tableColumns;
//獲取列數
@property (readonly) NSInteger numberOfColumns;
//獲取行數
@property (readonly) NSInteger numberOfRows;
//添加一列
- (void)addTableColumn:(NSTableColumn *)tableColumn;
//移除一列
- (void)removeTableColumn:(NSTableColumn *)tableColumn;
//移動列
- (void)moveColumn:(NSInteger)oldIndex toColumn:(NSInteger)newIndex;
//根據id獲取列的下標
- (NSInteger)columnWithIdentifier:(NSString *)identifier;
//根據id獲取列對象
- (nullable NSTableColumn *)tableColumnWithIdentifier:(NSString *)identifier;
//滾動到指定行可見
- (void)scrollRowToVisible:(NSInteger)row;
//滾動到指定列可見
- (void)scrollColumnToVisible:(NSInteger)column;
//重新加載數據
- (void)reloadData;
//重新加載指定位置的數據
- (void)reloadDataForRowIndexes:(NSIndexSet *)rowIndexes columnIndexes:(NSIndexSet *)columnIndexes;
//獲取編輯的列
@property (readonly) NSInteger editedColumn;
//獲取編輯的行
@property (readonly) NSInteger editedRow;
//獲取點擊的列
@property (readonly) NSInteger clickedColumn;
//獲取點擊的行
@property (readonly) NSInteger clickedRow;
//設置列頭提示圖片
- (void)setIndicatorImage:(nullable NSImage *)image inTableColumn:(NSTableColumn *)tableColumn;
//獲取列頭提示圖片
- (nullable NSImage *)indicatorImageInTableColumn:(NSTableColumn *)tableColumn;

//下面這些方法與列表拖拽有關
@property BOOL verticalMotionCanBeginDrag;
- (BOOL)canDragRowsWithIndexes:(NSIndexSet *)rowIndexes atPoint:(NSPoint)mouseDownPoint;
- (NSImage *)dragImageForRowsWithIndexes:(NSIndexSet *)dragRows tableColumns:(NSArray<NSTableColumn *> *)tableColumns event:(NSEvent *)dragEvent offset:(NSPointPointer)dragImageOffset;
- (void)setDraggingSourceOperationMask:(NSDragOperation)mask forLocal:(BOOL)isLocal;
- (void)setDropRow:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation;

//下面這些方法與列表選中有關
//是否支持多選
@property BOOL allowsMultipleSelection;
//是否允許都不選中
@property BOOL allowsEmptySelection;
//是否支持選中列 如果設置為YES 點擊列頭會將整列選中
@property BOOL allowsColumnSelection;
//全選 用於子類重寫
- (void)selectAll:(nullable id)sender;
//全不選 用於子類重寫
- (void)deselectAll:(nullable id)sender;
//進行列選中
- (void)selectColumnIndexes:(NSIndexSet *)indexes byExtendingSelection:(BOOL)extend;
//進行行選中
- (void)selectRowIndexes:(NSIndexSet *)indexes byExtendingSelection:(BOOL)extend;
//獲取所有選中列index
@property (readonly, copy) NSIndexSet *selectedColumnIndexes;
//獲取所有選中行index
@property (readonly, copy) NSIndexSet *selectedRowIndexes;
//取消某列的選中
- (void)deselectColumn:(NSInteger)column;
//取消某行的選中
- (void)deselectRow:(NSInteger)row;
//判斷某列是否被選中
- (BOOL)isColumnSelected:(NSInteger)column;
//判斷某行是否被選中
- (BOOL)isRowSelected:(NSInteger)row;
//獲取選中的列數
@property (readonly) NSInteger numberOfSelectedColumns;
//獲取選中的行數
@property (readonly) NSInteger numberOfSelectedRows;
//獲取某列的位置尺寸
- (NSRect)rectOfColumn:(NSInteger)column;
//獲取某行的位置尺寸
- (NSRect)rectOfRow:(NSInteger)row;
//獲取某個範圍內的列
- (NSIndexSet *)columnIndexesInRect:(NSRect)rect;
//獲取某個範圍內的行
- (NSRange)rowsInRect:(NSRect)rect;
//獲取包含某個點的列
- (NSInteger)columnAtPoint:(NSPoint)point;
//獲取包含某個點的行
- (NSInteger)rowAtPoint:(NSPoint)point;
//獲取某個cell的位置尺寸
- (NSRect)frameOfCellAtColumn:(NSInteger)column row:(NSInteger)row;
//獲取某個位置的View,用於view-base
- (nullable __kindof NSView *)viewAtColumn:(NSInteger)column row:(NSInteger)row makeIfNecessary:(BOOL)makeIfNecessary;
//獲取某行的視圖 用於view-base
- (nullable __kindof NSTableRowView *)rowViewAtRow:(NSInteger)row makeIfNecessary:(BOOL)makeIfNecessary;
//獲取某個View所在的行 用於view-base
- (NSInteger)rowForView:(NSView *)view;
//獲取某個View所在的列 用於view-base
- (NSInteger)columnForView:(NSView *)view;
//創建一個用於渲染的View 用於view-base
- (nullable __kindof NSView *)makeViewWithIdentifier:(NSString *)identifier owner:(nullable id)owner;

//下面這些方法用來根據列表數據
//開始更新
- (void)beginUpdates NS_AVAILABLE_MAC(10_7);
//結束更新
- (void)endUpdates NS_AVAILABLE_MAC(10_7);
//插入行
- (void)insertRowsAtIndexes:(NSIndexSet *)indexes withAnimation:(NSTableViewAnimationOptions)animationOptions NS_AVAILABLE_MAC(10_7);
//刪除行
- (void)removeRowsAtIndexes:(NSIndexSet *)indexes withAnimation:(NSTableViewAnimationOptions)animationOptions NS_AVAILABLE_MAC(10_7);
//移動行
- (void)moveRowAtIndex:(NSInteger)oldIndex toIndex:(NSInteger)newIndex NS_AVAILABLE_MAC(10_7);
//隱藏行
- (void)hideRowsAtIndexes:(NSIndexSet *)indexes withAnimation:(NSTableViewAnimationOptions)rowAnimation NS_AVAILABLE_MAC(10_11);
//取消隱藏行
- (void)unhideRowsAtIndexes:(NSIndexSet *)indexes withAnimation:(NSTableViewAnimationOptions)rowAnimation NS_AVAILABLE_MAC(10_11);
//所有隱藏狀態的行
@property (readonly, copy) NSIndexSet *hiddenRowIndexes;

十、相關通知

//列表選擇改變後發的通知
APPKIT_EXTERN NSNotificationName NSTableViewSelectionDidChangeNotification;
//列移動後發的通知
APPKIT_EXTERN NSNotificationName NSTableViewColumnDidMoveNotification;    
//列寬度改變後發的通知
APPKIT_EXTERN NSNotificationName NSTableViewColumnDidResizeNotification;
//選擇改變時發的通知   
APPKIT_EXTERN NSNotificationName NSTableViewSelectionIsChangingNotification;

macOS開發之NSTableView的應用詳解 - 轉