Can I use CALayer to speed up view rendering?

后端 未结 1 1383
我在风中等你
我在风中等你 2021-02-10 03:15

I am making a custom NSView object that has some content that changes often, and some that changes much more infrequently. As it would turn out, the parts that change less often

1条回答
  •  庸人自扰
    2021-02-10 04:06

    Your hunch is right, this is actually an excellent way to optimise drawing. I've done it myself where I had some large static backgrounds that I wanted to avoid redrawing when elements moved on top.

    All you need to do is add CALayer objects for each of the content items in your view. To draw the layers, you should set your view as the delegate for each layer and then implement the drawLayer:inContext: method.

    In that method you just draw the content of each layer:

    - (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)ctx
    {
        if(layer == yourBackgroundLayer)
        {   
            //draw your background content in the context
            //you can either use Quartz drawing directly in the CGContextRef,
            //or if you want to use the Cocoa drawing objects you can do this:
            NSGraphicsContext* drawingContext = [NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:YES];
            NSGraphicsContext* previousContext = [NSGraphicsContext currentContext];
            [NSGraphicsContext setCurrentContext:drawingContext];
            [NSGraphicsContext saveGraphicsState];
            //draw some stuff with NSBezierPath etc
            [NSGraphicsContext restoreGraphicsState];
            [NSGraphicsContext setCurrentContext:previousContext];
        }
        else if (layer == someOtherLayer)
        {
            //draw other layer
        }
        //etc etc
    }
    

    When you want to update the content of one of the layers, just call [yourLayer setNeedsDisplay]. This will then call the delegate method above to provide the updated content of the layer.

    Note that by default, when you change the layer content, Core Animation provides a nice fade transition for the new content. However, if you're handling the drawing yourself you probably don't want this, so in order to prevent the default fade in animation when the layer content changes, you also have to implement the actionForLayer:forKey: delegate method and prevent the animation by returning a null action:

    - (id)actionForLayer:(CALayer*)layer forKey:(NSString*)key 
    {
        if(layer == someLayer)
        {
            //we don't want to animate new content in and out
            if([key isEqualToString:@"contents"])
            {
                return (id)[NSNull null];
            }
        }
        //the default action for everything else
        return nil;
    }
    

    0 讨论(0)
提交回复
热议问题