Question

I'm creating a custom NSButton, and since I'm subviewing it with a gradient view, the default textView disappears. In order to have also custom styling on the textView, I've created a custom one and subviewed that too.

The button now looks like:

enter image description here

Which is perfect. But when I click on it, the NSButtonCell isn't triggering the highlight method (only if I click outside the textView (there's 5px spacing on bottom and top)

How can I (just like in iOS's UIButton add a custom label) and still keeping the whole button clickable.

Any help would be appreciated!

Sjors

Was it helpful?

Solution

An NSTextField is a control and therefore captures input events. You shouldn't use it to display the text in a button. NSButton uses NSCell for its drawing so it's best to subclass NSButtonCell and manually draw the string with NSStringDrawing, but only if you really can't use the standard layout properties of NSButtonCell. This isn't iOS, where there is something like UILabel as a lightweight solution to draw text. Instead, NSTextField provides a lot of overhead and would slow down your application and may provide you with unnecessary bugs, now or in the future.

Tl;dr: Don't use NSTextField, draw the string yourself.

OTHER TIPS

So you want a click event on the NSTextView?

Here is one solution. Subclass the NSTextView

@interface ClickableTextView : NSTextView
@end

@implementation ClickableTextView

- (void)mouseDown:(NSEvent *)theEvent{
    [self sendAction://action of the button that you want
                  to:self
    ];
}

@end

NSButton uses an NSButtonCell to do all its drawing. The best solution that doesn't break Accessibility and doesn't have the label show up as a "Label" separate from the button to VoiceOver is to subclass NSButtonCell and to override its -drawBezelWithFrame:inView: method to draw your own button border there.

That said, if you wanted to make a view "transparent" for clicks, you could do so by overriding the -hitTest: method it inherits from NSView to return nil. However then you'd also have to make sure you set it to be ignored by accessibility to avoid weirdness.

Maybe, instead of using an NSView to draw text, a better approach would be to use a CALayer. Layers are more lightweight than views, and by default don't take part in hit testing. There is even a text layer type that takes care of properly drawing. This is what Apple started using recently (in 10.8, or maybe it was already 10.7) for NSButtons if they use the standard configuration and don't override anything. They use one layer for the bezel (whose middle they stretch), and another for the text, IIRC. That way, only one texture needs to be uploaded to the GPU for all buttons of the same type. Only if you override something in NSButton, Apple will fall back to a compatibility mode that actually uses NSCell.

You can use a NSStackView as the super view of NSTextView. In this case, the NSTextView part of the button is clickable.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top