欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-07-13 17:14:39
...

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

目录

方法一

方法二


方法一

方法一文件结构为:

CXTableView.h
CXTableView.m

Appdelegate.h
Appdelegate.m
MainMenu.xib

CXTableView继承自NSTableview

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

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

 在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,这样确实改变了背景颜色...[Mac开发]自定义NSTableView鼠标悬停改变行的背景颜色Objective-C实现

不过使用过程中我也产生了疑问,就是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 <Cocoa/Cocoa.h>

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.