How can I draw as smoothly as CALayer does while zooming?
As seen in the third (tallest) image the white border is drawn with accurate, anti-aliased
rendering.
However neither my labels (even though I set the contentScaleFactor
) nor my hand drawn circles (even though I turn anti aliasing
on) are.
How can I have anti-aliased rendering for either UIKit components or hand-drawn graphics that scale with the zooming factor as smoothly as what CALayer does?
What's the magic?
The white border is drawn using the view's CALayer:
self.layer.cornerRadius = frame.size.width / 2.0f ;
self.layer.borderColor = [UIColor whiteColor].CGColor ;
self.layer.borderWidth = 3.0f ;
The numbers are UILabel's
CGFloat contentScale = self.zoomScale * [UIScreen mainScreen].scale; // Handle retina
label.contentScaleFactor = contentScale;
And given:
typedef struct {
CGRect rect ;
CGColorRef color ;
} EventColor ;
the 4 circles are drawn using CoreGraphics
::CGContextSetAllowsAntialiasing(context, true) ;
::CGContextSetShouldAntialias(context, true) ;
// ...
EventColor ec = ...
// ...
::CGContextSetFillColorWithColor(context, ec.color) ;
::CGContextFillEllipseInRect(context, ec.rect) ;
It turns out that I misunderstood what contentScaleFactor
was meant for, and discovered that what I really was after was CALayer's contentScale
.
The upshot is that the drawRect
method in whatever UIView subclass can go ahead and pretend that the zooming scale is always set to 1.0 provided that the view's layer's contentScale is set to reflect the current zoom level of the scroll view.
- (void) scrollViewDidEndZooming: (UIScrollView *) scrollView
withView: (UIView *) view
atScale: (float) scale {
scale *= [UIScreen mainScreen].scale ;
for (UIView * v in view.subviews) {
v.layer.contentsScale = scale ;
[v setNeedsDisplay] ;
}
}
The example above assumes that the scroll view contains a non opaque container view which in turn contains every actual views whose layer.contentScale
needs adjusting.