How to implement a custom Focus Ring in drawRect for NSTextField or NSTextVew
I want to draw a custom focus ring for my NSTextView
subclass (which doesn't have a focus ring by default). I managed to implement it by overriding the parent NSScrollView
drawRect
and adding this code:
- (void)drawRect:(NSRect)dirt开发者_开发知识库yRect {
if (focused) {
NSSetFocusRingStyle(NSFocusRingOnly);
NSRectFill(dirtyRect);
}
[super drawRect:dirtyRect];
}
However, I want to draw my own, custom focus ring. I have searched and searched for examples of this, and tried messing around and writing it myself, to no avail. The biggest issue I have is the fact that it will get cropped to the NSScrollView
/NSTextView
frame, no matter how I do it.
Thanks.
Updating this answer for 10.7+:
Now you should override drawFocusRingMask
to render (simply drawing a shape; the system will take care of color/style), and override focusRingMaskBounds
to hint at its boundaries. Also, call noteFocusRingMaskChanged
if you change the shape in some way that the system could not figure out on its own.
(Below is the previous answer, requiring older APIs:)
In the Carbon framework there are HIThemeBeginFocus()
and HIThemeEndFocus()
, which allow you to cause any series of drawings (such as a rectangle or shape) to have an automatic "focused" appearance. Requires Mac OS X 10.5 or later.
This uses Core Graphics directly. To find the CG context from a drawRect:
method in Cocoa, you'd do something like:
NSGraphicsContext* contextMgr = [NSGraphicsContext currentContext];
CGContextRef drawingContext = (CGContextRef)[contextMgr graphicsPort];
As far as avoiding clipping, one option is to use a parent view (such as an NSBox
that has no border) to give extra padding. Perform the custom drawing at an inset location in the parent view that won't be clipped; in other words, give the illusion that the view is a bit smaller than its actual rectangle.
精彩评论