进阶使用和技巧
1. 单击和双击行事件处理
Objective-C
// 单击行时的处理
- (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn {
NSInteger clickedRow = [tableView clickedRow];
if (clickedRow >= 0) {
NSLog(@"Single click on row: %ld", (long)clickedRow); // 处理单击事件
}
}
// 双击行时的处理
- (void)tableViewDoubleClick:(id)sender {
NSInteger clickedRow = [tableView clickedRow];
if (clickedRow >= 0) {
NSLog(@"Double click on row: %ld", (long)clickedRow); // 处理双击事件
}
}
// 配置双击事件
- (void)setupDoubleClickEventForTableView:(NSTableView *)tableView {
[tableView setTarget:self]; // 设置点击事件的目标
[tableView setDoubleAction:@selector(tableViewDoubleClick:)]; // 设置双击事件处理方法
}
Swift
// 单击行时的处理
func tableView(_ tableView: NSTableView, didClick tableColumn: NSTableColumn) {
let clickedRow = tableView.clickedRow
if clickedRow >= 0 {
print("Single click on row: \(clickedRow)") // 处理单击事件
}
}
// 双击行时的处理
@objc func tableViewDoubleClick(_ sender: AnyObject) {
let clickedRow = tableView.clickedRow
if clickedRow >= 0 {
print("Double click on row: \(clickedRow)") // 处理双击事件
}
}
// 配置双击事件
func setupDoubleClickEventForTableView(_ tableView: NSTableView) {
tableView.target = self // 设置点击事件的目标
tableView.doubleAction = #selector(tableViewDoubleClick(_:)) // 设置双击事件处理方法
}
2. 拖动行重新排序
Objective-C
// 开始拖动行时的处理
- (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pasteboard {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:rowIndexes];
[pasteboard declareTypes:@[NSPasteboardTypeString] owner:self];
[pasteboard setData:data forType:NSPasteboardTypeString];
return YES; // 开始拖动
}
// 拖动时的验证
- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id<NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation {
return NSDragOperationMove; // 验证拖动操作
}
// 接受拖放后的处理
- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id<NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation {
NSPasteboard *pasteboard = [info draggingPasteboard];
NSData *data = [pasteboard dataForType:NSPasteboardTypeString];
NSIndexSet *rowIndexes = [NSKeyedUnarchiver unarchiveObjectWithData:data];
// 获取拖动的行并重新排序数据源
NSInteger movingRow = [rowIndexes firstIndex];
id object = _dataArray[movingRow];
[_dataArray removeObjectAtIndex:movingRow];
[_dataArray insertObject:object atIndex:row];
[tableView reloadData]; // 重新加载表格
return YES;
}
Swift
// 开始拖动行时的处理
func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pasteboard: NSPasteboard) -> Bool {
let data = NSKeyedArchiver.archivedData(withRootObject: rowIndexes)
pasteboard.declareTypes([.string], owner: self)
pasteboard.setData(data, forType: .string)
return true // 开始拖动
}
// 拖动时的验证
func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableView.DropOperation) -> NSDragOperation {
return .move // 验证拖动操作
}
// 接受拖放后的处理
func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableView.DropOperation) -> Bool {
guard let pasteboard = info.draggingPasteboard.data(forType: .string),
let rowIndexes = NSKeyedUnarchiver.unarchiveObject(with: pasteboard) as? IndexSet
else {
return false
}
// 获取拖动的行并重新排序数据源
let movingRow = rowIndexes.first ?? 0
let object = dataArray[movingRow]
dataArray.remove(at: movingRow)
dataArray.insert(object, at: row)
tableView.reloadData() // 重新加载表格
return true
}
3. 预加载内容和缓存优化
Objective-C
// 使用内存缓存来优化单元格的创建
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
NSString *identifier = [tableColumn identifier];
NSTableCellView *cellView = [tableView makeViewWithIdentifier:identifier owner:self];
if (!cellView) {
cellView = [[NSTableCellView alloc] init];
cellView.identifier = identifier;
}
// 配置单元格的内容
cellView.textField.stringValue = _dataArray[row];
return cellView;
}
Swift
// 使用内存缓存来优化单元格的创建
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let identifier = tableColumn?.identifier ?? NSUserInterfaceItemIdentifier(rawValue: "")
var cellView = tableView.makeView(withIdentifier: identifier, owner: self) as? NSTableCellView
if cellView == nil {
cellView = NSTableCellView()
cellView?.identifier = identifier
}
// 配置单元格的内容
cellView?.textField?.stringValue = dataArray[row]
return cellView
}
4. 自定义表头视图和排序功能
Objective-C
#import "CustomHeaderView.h"
@implementation CustomHeaderView
// 自定义表头视图,可以加入按钮和其他控件
@end
@interface MyViewController ()
// 记录当前的排序键和排序方向
@property (nonatomic, strong) NSString *sortedColumnIdentifier;
@property (nonatomic, assign) BOOL isAscending;
@end
@implementation MyViewController
- (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn {
NSString *identifier = tableColumn.identifier;
if ([self.sortedColumnIdentifier isEqualToString:identifier]) {
self.isAscending = !self.isAscending; // 切换排序方向
} else {
self.sortedColumnIdentifier = identifier;
self.isAscending = YES; // 默认升序
}
// 按照列标识符排序数据源
[self.dataArray sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
if (self.isAscending) {
return [[obj1 valueForKey:identifier] compare:[obj2 valueForKey:identifier]];
} else {
return [[obj2 valueForKey:identifier] compare:[obj1 valueForKey:identifier]];
}
}];
[tableView reloadData];
}
Swift
import Cocoa
class CustomHeaderView: NSView {
// 自定义表头视图,可以加入按钮和其他控件
}
class MyViewController: NSViewController {
// 记录当前的排序键和排序方向
var sortedColumnIdentifier: String?
var isAscending: Bool = true
func tableView(_ tableView: NSTableView, didClick tableColumn: NSTableColumn) {
let identifier = tableColumn.identifier.rawValue
if sortedColumnIdentifier == identifier {
isAscending.toggle() // 切换排序方向
} else {
sortedColumnIdentifier = identifier
isAscending = true // 默认升序
}
// 按照列标识符排序数据源
dataArray.sort {
if isAscending {
return ($0[identifier] as? String ?? "") < ($1[identifier] as? String ?? "")
} else {
return ($0[identifier] as? String ?? "") > ($1[identifier] as? String ?? "")
}
}
tableView.reloadData()
}
}
5. 单元格内嵌按钮事件处理
Objective-C
// 自定义单元格视图,带按钮
@interface CustomButtonCellView : NSTableCellView
@property (nonatomic, strong) NSButton *actionButton;
@end
@implementation CustomButtonCellView
- (instancetype)initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
if (self) {
_actionButton = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 50, 20)];
_actionButton.title = @"Click";
_actionButton.target = self;
_actionButton.action = @selector(buttonClicked:);
[self addSubview:_actionButton];
}
return self;
}
// 按钮事件处理
- (void)buttonClicked:(id)sender {
NSLog(@"Button in row %ld clicked", self.row);
}
@end
// 在视图控制器中返回自定义单元格
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
CustomButtonCellView *cellView = [tableView makeViewWithIdentifier:@"CustomButtonCell" owner:self];
if (!cellView) {
cellView = [[CustomButtonCellView alloc] initWithFrame:NSMakeRect(0, 0, tableColumn.width, 20)];
cellView.identifier = @"CustomButtonCell";
}
cellView.row = row;
return cellView;
}
Swift
// 自定义单元格视图,带按钮
class CustomButtonCellView: NSTableCellView {
var actionButton: NSButton!
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
actionButton = NSButton(frame: NSRect(x: 0, y: 0, width: 50, height: 20))
actionButton.title = "Click"
actionButton.target = self
actionButton.action = #selector(buttonClicked(_:))
addSubview(actionButton)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// 按钮事件处理
@objc func buttonClicked(_ sender: Any) {
print("Button in row \(self.row ?? -1) clicked")
}
}
// 在视图控制器中返回自定义单元格
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
var cellView = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier("CustomButtonCell"), owner: self) as? CustomButtonCellView
if cellView == nil {
cellView = CustomButtonCellView(frame: NSRect(x: 0, y: 0, width: tableColumn?.width ?? 100, height: 20))
cellView?.identifier = NSUserInterfaceItemIdentifier("CustomButtonCell")
}
cellView?.row = row
return cellView
}
封装工具类
为了更方便地使用 NSTableView
,我们可以封装一个工具类,提供常见功能的高层接口。
Objective-C
#import <Cocoa/Cocoa.h>
@interface NSTableViewHelper : NSObject
+ (NSTableView *)createTableViewWithColumns:(NSArray<NSString *> *)columnIdentifiers target:(id)target;
+ (void)setupDragAndDropForTableView:(NSTableView *)tableView;
+ (void)enableDoubleClickEventForTableView:(NSTableView *)tableView target:(id)target action:(SEL)action;
@end
@implementation NSTableViewHelper
+ (NSTableView *)createTableViewWithColumns:(NSArray<NSString *> *)columnIdentifiers target:(id)target {
NSTableView *tableView = [[NSTableView alloc] initWithFrame:NSMakeRect(0, 0, 400, 300)];
for (NSString *identifier in columnIdentifiers) {
NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:identifier];
column.headerCell.title = identifier;
column.width = 100;
[tableView addTableColumn:column];
}
tableView.dataSource = target;
tableView.delegate = target;
return tableView;
}
+ (void)setupDragAndDropForTableView:(NSTableView *)tableView {
[tableView registerForDraggedTypes:@[NSPasteboardTypeString]];
tableView.draggingSourceOperationMask = NSDragOperationEvery;
}
+ (void)enableDoubleClickEventForTableView:(NSTableView *)tableView target:(id)target action:(SEL)action {
[tableView setTarget:target];
[tableView setDoubleAction:action];
}
@end
Swift
import Cocoa
class NSTableViewHelper {
// 创建表格视图并添加列
static func createTableView(columnIdentifiers: [String], target: NSObject) -> NSTableView {
let tableView = NSTableView(frame: NSRect(x: 0, y: 0, width: 400, height: 300))
for identifier in columnIdentifiers {
let column = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: identifier))
column.headerCell.title = identifier
column.width = 100
tableView.addTableColumn(column)
}
tableView.dataSource = target as? NSTableViewDataSource
tableView.delegate = target as? NSTableViewDelegate
return tableView
}
// 配置拖放功能
static func setupDragAndDrop(for tableView: NSTableView) {
tableView.registerForDraggedTypes([.string])
tableView.draggingSourceOperationMask = .every
}
// 启用双击事件处理
static func enableDoubleClickEvent(for tableView: NSTableView, target: AnyObject, action: Selector) {
tableView.target = target
tableView.doubleAction = action
}
}
使用示例
Objective-C
// 创建表格视图
NSTableView *tableView = [NSTableViewHelper createTableViewWithColumns:@[@"Column1", @"Column2"] target:self];
// 配置拖放功能
[NSTableViewHelper setupDragAndDropForTableView:tableView];
// 启用双击事件
[NSTableViewHelper enableDoubleClickEventForTableView:tableView target:self action:@selector(tableViewDoubleClick:)];
Swift
// 创建表格视图
let tableView = NSTableViewHelper.createTableView(columnIdentifiers: ["Column1", "Column2"], target: self)
// 配置拖放功能
NSTableViewHelper.setupDragAndDrop(for: tableView)
// 启用双击事件
NSTableViewHelper.enableDoubleClickEvent(for: tableView, target: self, action: #selector(tableViewDoubleClick(_:)))
标签:identifier,tableView,19,self,cellView,Mac,NSTableView,row
From: https://www.cnblogs.com/chglog/p/18345641