Stop NSView drawRect clearing before drawing? (lockFocus no longer working on macOS 10.14)

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-20 03:52:38

问题


I have an animation using two views where I would call lockFocus and get at the graphics context of the second NSView with [[NSGraphicsContext currentContext] graphicsPort], and draw. That worked fine until macOS 10.14 (Mojave).

Found a reference here: https://developer.apple.com/videos/play/wwdc2018/209/

At 22:40 they talk about the "legacy" backing store that has changed. The above lockFocus and context pattern was big on the screen, saying that that won't work any more. And that is true. lockFocus() still works, and even gets you the correct NSView, but any drawing via the context does not work any more.

Of course the proper way to draw in a view is via Nsview's drawRect. So I rearranged everything to do just that. That works, but, drawRect has already automatically cleared the "dirty" area for you, prior to calling your drawRect. If you used setNeedsDisplayInRect: it will even clear only those areas for you. But, it will also clear areas made up of more than one dirty rectangle. And, it clears rectangular areas, while I draw roundish objects, so I end up with too much cleared away (black area):

Is there a way to prevent drawRect to clear the background?

If not I will have switch to using the NSView's layer instead, and use updateLayer, or something.

Update: I am playing around with using the layers of NSView, returning TRUE for wantsLayer and wantsUpdateLayer, and implementing:

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx

That is only called when I do:

- (BOOL) wantsLayer { return YES; }
- (BOOL) wantsUpdateLayer { return NO; } 

and use setNeedsDisplayInRect: or setNeedsDisplay:

Which indeed makes drawRect no longer called, but the same automatic background erase has already taken place by the time my drawLayer: is called. So I have not made any progress there. It really is the effect of setNeedsDisplayInRect, and not my drawing. Just calling setNeedsDisplayInRect causes these erases.

If you set:

- (BOOL) wantsLayer { return YES; }
- (BOOL) wantsUpdateLayer { return YES; } 

the only thing that is called is:

- (void) updateLayer

which does not provide me with a context to draw.

I had some hope for:

self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawNever;

The NSView doc says:

Leave the layer's contents alone. Never mark the layer as needing display, or draw the view's contents to the layer. This is how developer created layers (layer-hosting views) are treated.

and it does exactly that. It doesn't notify you, or call delegates.

Is there a way to have complete control over the content of an NSView/layer?

UPDATE 2019-JAN-27: NSView has a method makeBackingLayer that is not there for nothing, I guess. Implemented that, and it seems to work, basically, but no output shows on screen. Hence the followup question: nsview-makebackinglayer-with-calayer-subclass-displays-no-output


回答1:


Using NSView lockFocus and unlockFocus, or trying to access the window's graphics contents directly not working in macOS 10.14 anymore.

You can create an NSBitmapImageRep object and update drawing in this context.

Sample code:

- (void)drawRect:(NSRect)rect {
    if (self.cachedDrawingRep) {
        [self.cachedDrawingRep drawInRect:self.bounds];
    }
}

- (void)drawOutsideDrawRect {
     NSBitmapImageRep *cmap = self.cachedDrawingRep;
    if (!cmap) {
        cmap = [self bitmapImageRepForCachingDisplayInRect:self.bounds];
        self.cachedDrawingRep = cmap;
    }
    NSGraphicsContext *ctx = [NSGraphicsContext graphicsContextWithBitmapImageRep:cmap];
    NSAssert(ctx, nil);
    [NSGraphicsContext setCurrentContext:ctx];

    // Draw code here

    self.needsDisplay = YES;
 }


来源:https://stackoverflow.com/questions/53759488/stop-nsview-drawrect-clearing-before-drawing-lockfocus-no-longer-working-on-ma

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!