天天看點

macOS開發之NSTableView的應用詳解(二)

五、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");

上面代碼中用到了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);

關于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;

繼續閱讀