天天看点

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;

继续阅读