Reputation: 9566
I have a UIView
subclass with a custom drawRect:
method which does some expensive calculations to build a path and draws it using CGContextStrokePath()
on the current context.
If my view has a size (x, y)
, I want to do my custom drawing on (0, 0), (x/2, y)
and then fill the (x/2, 0), (x, y)
area with a mirrored image of the first half.
What is the simplest/fastest way of doing this, other than manually duplicating the points to be drawn? Maybe rendering the half view to a bitmap image context and using that one to render on both halves of the current image context? The content is animated, so drawRect:
is roughly executed 60 times per second.
Upvotes: 1
Views: 903
Reputation: 9566
One efficient way of doing this is to do the draw operations on the context of a CGLayer
, and then use the layer to draw on the current UIView
's context.
See Core Graphics Layer Drawing on the Quartz 2D Programming Guide for more details.
Basically you would do this:
- (void)drawRect:(CGRect)rect
{
const CGFloat viewWidth = view.bounds.size.width;
const CGFloat viewHeight = view.bounds.size.height;
CGContextRef viewContext = UIGraphicsGetCurrentContext();
CGLayerRef layer = CGLayerCreateWithContext(viewContext, CGSizeMake(viewWidth/2, viewHeight), 0);
CGContextRef layerContext = CGLayerGetContext(layer);
// Draw to the layerContext
// using CGContextStrokePath() or whatever
CGContextDrawLayerAtPoint(viewContext, CGPointZero, layer);
CGContextTranslateCTM(viewContext, viewWidth, 0);
CGContextScaleCTM(viewContext, -1, 1);
CGContextDrawLayerAtPoint(viewContext, CGPointZero, layer);
CGLayerRelease(layer);
}
Additionally, you can store the CGLayerRef
as an ivar of UIView
so you don't recreate it every frame.
This solution works great in my case, but two caveats:
CGLayers
, as stated here.CGLayers
you have to follow the steps detailed hereUpvotes: 2
Reputation: 4093
You could calculate the CGPath
once, you can either do this by building the whole Path as a CGPath
instead of building it as part of the CGContext
, or you could use the CGContextCopyPath
to get the CGPath
after creating it in the context. Then you could stroke the path once. Then put the CGPath
back into the CGContext
using CGContextAddPath
and change the change the transform on the CGContext
to get your mirror with a transform something like this (-1, 0, 0, 1, width, 0)
, the -1 does the reflection about the x-axis, and the width
should move it back to the the correct position, and stroke the path again.
Upvotes: 0