[Mac开发]自定义NSTableView鼠标悬停改变行的背景颜色Objective-C实现

通过这个小案例练习使用了delegate等知识,想讲讲我两种不同的实现方法,一种是简单粗暴[Mac开发]自定义NSTableView鼠标悬停改变行的背景颜色Objective-C实现_第1张图片,在自定义的NSTableView中实现。更推荐第二种方法,更符合逻辑。

目录

方法一

方法二


方法一

方法一文件结构为:

CXTableView.h
CXTableView.m

Appdelegate.h
Appdelegate.m
MainMenu.xib

CXTableView继承自NSTableview

运行效果为,鼠标悬停在哪一行,哪一行的背景颜色就变成红色。

[Mac开发]自定义NSTableView鼠标悬停改变行的背景颜色Objective-C实现_第2张图片

 在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.

你可能感兴趣的:(Mac,ios,mac,os,x,objective-c)