Simple mouseover effect on NSButton

You need to Subclass the NSButton class (or even better the NSButtonCell class). As Justin said if you put the two method

- (void)mouseEntered:(NSEvent *)theEvent;
- (void)mouseExited:(NSEvent *)theEvent;

They should get called when the mouse enter and exit the area. You may also need to re create the tracking area, look here:

- (void)updateTrackingAreas

For fade in and fade out effect I played with animator and alpha value for example:

[self animator]setAlphaValue:0.5]; 

Swift 5 version with callback, super easy to use:

final class HoverButton: NSButton {

    private let callback: (HoverButton, Bool) -> Void

    init(callback: @escaping (HoverButton, Bool) -> Void) {
        self.callback = callback
        super.init(frame: .zero)
        let area = NSTrackingArea(rect: bounds, options: [.mouseEnteredAndExited, .activeAlways, .inVisibleRect], owner: self, userInfo: nil)
        addTrackingArea(area)
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func mouseEntered(with event: NSEvent) {
        super.mouseEntered(with: event)
        callback(self, true)
    }

    override func mouseExited(with event: NSEvent) {
        super.mouseExited(with: event)
        callback(self, false)
    }

}

Usage:

let button = HoverButton { button, isHovered in
    button.animator().alphaValue = isHovered ? 1 : 0.5
}

Here is i have created and worked for me perfectly...

Step 1: Create the Button with tracking area

 NSButton *myButton = [[NSButton alloc] initWithFrame:NSMakeRect(100, 7, 100, 50)];
[myButton setTitle:@"sample"];

[self.window.contentView addSubview:myButton];
// Insert code here to initialize your application
NSTrackingArea* trackingArea = [[NSTrackingArea alloc]
                                initWithRect:[myButton bounds]
                                options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways
                                owner:self userInfo:nil];
[myButton addTrackingArea:trackingArea];

Step: 2 Implement the following methods

- (void)mouseEntered:(NSEvent *)theEvent{
NSLog(@"entered");
[[myButton cell] setBackgroundColor:[NSColor blueColor]];


}

- (void)mouseExited:(NSEvent *)theEvent{
[[myButton cell] setBackgroundColor:[NSColor redColor]];
NSLog(@"exited");

}

Swift 3:

Create the button with code or just use it's @IBOutlet. Then define the button's tracking area for mouse over (hover):

let area = NSTrackingArea.init(rect: yourButtonName.bounds,
                               options: [.mouseEnteredAndExited, .activeAlways], 
                               owner: self, 
                               userInfo: nil)
yourButtonName.addTrackingArea(area)

Then override mouseEntered and mouseExited, set whatever you want to change (button color, button image, button text,..) in these functions:

override func mouseEntered(with event: NSEvent) {
    print("Entered: \(event)")
}

override func mouseExited(with event: NSEvent) {
    print("Exited: \(event)")
}

If you have multiple buttons (with tracking area added for each) and you need to identify which button triggered the mouseEntered event, you can add some userInfo information for this purpose, so instead of:

userInfo: nil

Add your custom button name in userInfo for each button, for example:

userInfo: ["btnName": "yourButtonName"]

Then you can write a switch-case or if statements in your mouseEntered and mouseExited functions like this:

override func mouseEntered(with event: NSEvent) {
        // Identify which button triggered the mouseEntered event
        if let buttonName = event.trackingArea?.userInfo?.values.first as? String {
            switch (buttonName) {
            case "yourButtonName":
                //do whatever you want for this button..
            case "anotherButtonName":
                //do whatever you want for this button..
            default:
                print("The given button name: \"\(buttonName)\" is unknown!")
            }
        }
    }