通过这个小案例练习使用了delegate等知识,想讲讲我两种不同的实现方法,一种是简单粗暴,在自定义的NSTableView中实现。更推荐第二种方法,更符合逻辑。
目录
方法一
方法二
方法一文件结构为:
CXTableView.h
CXTableView.m
Appdelegate.h
Appdelegate.m
MainMenu.xib
CXTableView继承自NSTableview
运行效果为,鼠标悬停在哪一行,哪一行的背景颜色就变成红色。
在Appdelegate中,我创建了新的Person类来表示这一行,两个属性,姓名和性别,都是NSString类型。
@interface Person : NSObject
@property (copy) NSString *name;
@property (copy) NSString *gender;
@end
@implementation Person
@synthesize name;
@synthesize gender;
@end
在Appdelegate中添加代理,这一步是为了在tableview中自定义行。
- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row{
return 30;
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
return _dataArray.count;
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
Person *person1 = [_dataArray objectAtIndex:row];
NSString *identifier = tableColumn.identifier;
NSTableCellView *tableCellView = [tableView makeViewWithIdentifier:identifier owner:nil];
if([tableColumn.identifier isEqualToString:@"NAME"] == YES){
tableCellView.textField.stringValue = person1.name;
}
if([tableColumn.identifier isEqualToString:@"GENDER"] == YES){
tableCellView.textField.stringValue = person1.gender;
}
return tableCellView;
}
写完之后,在Appdelegate的awakeFromNib中,添加你想要的数据,想多添加几行也行,我现在是写死的。_dataArray是一个类型为可变的数组(NSMutableArray)是property
- (void)awakeFromNib{
[super awakeFromNib];
_dataArray = [NSMutableArray array];
Person *person1 = [[Person alloc] init];
person1.name = @"amy";
person1.gender = @"female";
[_dataArray addObject:person1];
Person *person2 = [[Person alloc] init];
person2.name = @"jimmy";
person2.gender = @"male";
[_dataArray addObject:person2];
_tableView.delegate = self;
_tableView.dataSource = self;
[_tableView reloadData];
_tableView.allowsMultipleSelection = YES;
}
现在来做鼠标悬停改变背景颜色的功能。
在初始化的时候把鼠标所在行设置成-1。在awakeFromNib中添加鼠标检测的区域。
#import "CXTableView.h"
@interface CXTableView ()
@end
@implementation CXTableView
{
NSInteger mouseRow;
NSRect mouseRowFrame;
}
- (id)initWithFrame:(NSRect)frameRect{
self = [super initWithFrame:frameRect];
if(self){
mouseRow = -1;
}
return self;
}
- (void)awakeFromNib{
[self.window setAcceptsMouseMovedEvents:YES];
NSRect trackRect = self.bounds;
int opts = (NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow);
NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:trackRect
options:opts
owner:self
userInfo:nil];
[self addTrackingArea:trackingArea];
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
[[NSColor redColor] setFill];
//画一个方框宽度为100的方框哈哈
NSFrameRectWithWidth(mouseRowFrame, 100.);
}
- (void)mouseMoved:(NSEvent *)event{
NSLog(@"mosuemoved");
NSPoint mouseLocation = [event locationInWindow];
NSPoint viewLocation = [self convertPoint:mouseLocation fromView:nil];
NSInteger row = [self rowAtPoint:viewLocation];
if(row != mouseRow){
mouseRowFrame = [self rectOfRow:row];
[self setNeedsDisplay:YES];
mouseRow = row;
}
}
这个方法是网上查的,效果是一个红色方框框住选中行,我要实现的功能却是改变这一行的背景颜色,当时实在不知道怎么实现了,就把方框的宽度画成100,这样确实改变了背景颜色...
不过使用过程中我也产生了疑问,就是awakFromNib/initWithFrame/还有其他init函数,到底有什么区别和联系呢?
要是有人留言就好了!
使用了自定义的NSTableRowView,创建一个行,再来改变这一行的背景颜色,在设计结构上就合理很多。
在Appdelegate的代理中,改变了一些东西,以下是所有使用到的代理的代码,额,开发过程中也可能有的没用到没被我删掉。
看第一个- (NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row,这个代理里面创建自定义的行,放到tableview里面去。因为tableview是复用的,如果有很多的行,滑动到后面,前面的行会进入复用区,并没有销毁对象,所以用一个if语句来判断,如果为空(可能是第一次进入)就生成新的行,如果不为空那就直接返回。(这部分不是很熟悉,也可能讲的不对)。
//MARK: delegate
- (NSTableRowView *)tableView:(NSTableView *)tableView rowViewForRow:(NSInteger)row{
CXTableRowView *rowView = [_tableView makeViewWithIdentifier:[CXTableRowView className] owner:nil];
if(rowView == nil){
rowView = [[CXTableRowView alloc] init];
rowView.identifier = [CXTableRowView className];
}
return rowView;
}
- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row{
return 30;
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
return _dataArray.count;
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
Person *person1 = [_dataArray objectAtIndex:row];
NSString *identifier = tableColumn.identifier;
NSTableCellView *tableCellView = [tableView makeViewWithIdentifier:identifier owner:nil];
if([tableColumn.identifier isEqualToString:@"NAME"] == YES){
tableCellView.textField.stringValue = person1.name;
}
if([tableColumn.identifier isEqualToString:@"GENDER"] == YES){
tableCellView.textField.stringValue = person1.gender;
}
return tableCellView;
}
在自定义的NSTableRowView中,既然我们要实现hover改背景颜色的功能,就给他添加一个布尔类型的属性,表示鼠标是否悬停在该行上,当鼠标事件mouseEntered的时候就把该值设置为YES,在mouseExited的时候设置为NO。
下面是CXTableRowView头文件里的内容,其实有些属性没用到,比如颜色什么的。
#import
NS_ASSUME_NONNULL_BEGIN
@interface CXTableRowView : NSTableRowView{
BOOL _mouseFocus;
}
@property (nonatomic, strong) NSColor *highlightColor;
@property (nonatomic, strong) NSColor *selectedColor;
@property (nonatomic, strong) NSColor *bgColor;
@property (assign) NSInteger row;
@end
NS_ASSUME_NONNULL_END
在m文件中,添加鼠标事件,然后在初始化函数中初始化要用到的highlightColor值,在drawRect中用贝塞尔来填充背景颜色,这样就可以实现功能了。
- (instancetype)initWithFrame:(NSRect)frameRect{
if(self = [super initWithFrame:frameRect]){
self.highlightColor = [NSColor redColor];
}
return self;
}
- (void)updateTrackingAreas{
NSRect trackRect = self.bounds;
int opts = (NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveInKeyWindow);
NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:trackRect
options:opts
owner:self
userInfo:nil];
[self addTrackingArea:trackingArea];
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
[self setIdentifier:@"CXTableRowView"];
if(!_mouseFocus){
//鼠标没有hover
return;
}
if(self.isSelected){
//鼠标在已经选中的按钮上
return;
}
NSRect selectRect = self.bounds;
if(self.highlightColor){
[self.highlightColor setFill];
NSBezierPath *selectPath = [NSBezierPath bezierPathWithRoundedRect:selectRect xRadius:0 yRadius:0];
[selectPath fill];
}
NSLog(@"drawRect");
}
- (void)mouseEntered:(NSEvent *)event{
NSLog(@"mosueenterd");
_mouseFocus = YES;
[self display];
}
- (void)mouseExited:(NSEvent *)event{
_mouseFocus = NO;
[self display];
}
是OC和Mac开发初学者,如果有讲错的地方请指出哦。
我应该会把项目代码放在github上,有空的话更新链接。
Fin.