I've been trying to animate circle drawing using CALayer. It all works well, but the problem is - drawn circle is not antialiased enough. It has a bit too rough borders, (or blurred if rasterize is used). (AntiAliasing is enabled)
Tried also:
edgeAntialiasingMask = kCALayerLeftEdge | kCALayerRightEdge |
kCALayerBottomEdge | kCALayerTopEdge;
to no avail.
Here is an example how it looks like without rasterization:
And here is an example with rasterization: (tried values from 1.0 till 4.0 (just to be sure. Result - the same.))
And here is the same circle, but drawn inside UIView drawrect:
You can see, that circle drawn using UIView drawrect is looking much better.
The reason I cannot use UIView is because I need to animate circle filling. Using CALayer it is really easy, but to do the same on UIView, I don't really know if it is even possible. (I could try to launch drawrect: every 1/60 seconds, but I think it will get laggy, as it is not intended that way).
So - does anyone have any solution how I could make drawn circles/lines on CALayer look the same as drawn on UIView?
I've had issues with pixelated drawing in a CALayer on retina devices before. (I'm assuming you're seeing the issue on retina devices) Doing the following fixed the issue I was experiencing:
layer.contentsScale = [[UIScreen mainScreen] scale];
You shouldn't need to deal with rasterization or antialiasing. In my own code, I had initially implemented drawing something to a UIView that I later changed to be drawn in a CALayer, and simply setting the contentsScale property made both draw identically.
Related
So I just discovered QuartzCore, and I am now considering to replace a UIImageView containing a bitmap with a UIView subclass doing things like
CGContextFillEllipseInRect(contextRef, rect);
They would look exactly the same: the bitmap is just a little filled circle.
The very view I'm replacing is playing an important role in my app: it's being dragged around a lot.
Question: performance wise: should I bother? I can imagine that the vector circle is being recalculated all of the time, while the bitmap is just buffered. Or that the vector is easier to digest than a bitmap.
Can anyone advise?
thanks ahead
All UIView's on iOS are layer backed. So drawRect will only be called once and you will draw to the CALayer backing the view. You can have it draw again by calling setNeedsDisplay. When you are dragging the view around and drawing it, the view will render from the layer backing. Using a UIImageView is also layer backed and so the end result should be two layer backed views. The one place where you may see a difference is in low memory situations when the view is not visible (though I am not sure).
I've got some card games which use CALayers to draw individual cards. There can easily be 40 or 50 of them on the screen, which usually works fine.
I recently tried to turn on their shadows using the simple properties for CALayers:
theCardLayer.shadowOffset = CGSizeMake(3,2);
theCardLayer.shadowOpacity = 0.7f;
At that point, the program started getting really laggy. Fair enough; some of the docs said that the shadows could be CPU-intensive.
Any ideas for how to efficiently draw shadows on everything? They're all on the same CALayer in the same UIView, so I'm wondering if there might be a way to pull the mask of the layer or its UIView and shadow that, or something ...
Any functionality up to iOS5 is fair game.
At the very least, try setting your layer's shadowPath property. It can make shadow rendering significantly faster.
Kurt offered up the correct solution. Here's an example of how to use a shadowPath:
UIBezierPath *thisCLPath = [UIBezierPath
bezierPathWithRoundedRect:theCardLayer.bounds
cornerRadius:10.0f];
theCardLayer.shadowPath = thisCLPath.CGPath;
Clearly, I'm using rounded corners here. For a straight-edged layer, you can just use bezierPathWithRect:. There are a few other helpful methods in UIBezierPath as well.
The result is just the right side of laggy on older iOS devices (like an iPhone4 or a mid-generation iPod Touch) and blazing on an iPad3.
I've been looking at the CALayer's documentation and it seems like cornerRadius only affects the background of the layer and not the contents.
Is there a way to apply the corner radius to the entire CALayer without taking a big performance hit?
I've seen suggestions about masks, but that sounds costly. I've also seen suggestions about drawing the contents manually, but I don't really know where to start. I know a bit about rendering images in contexts, but I don't know how I'm supposed to draw it onto the CALayer's content view with a corner radius. The best I would know is to subclass CALayer and override the drawInContext method and use CGContextDrawImage.
All help is greatly appreciated, but to reiterate the question: "Is there a way to apply the corner radius to the entire CALayer without taking a big performance hit?"
cornerRadius does apply to the entire CALayer and it does not cause a big performance hit. If you are not seeing the contents with rounded corners, it is because you have forgotten to set masksToBounds to YES.
This isn't in reference to any particular code, but I've noticed that when I have a UIView that has a shadow added to it's layer, the animation when rotating between interface orientations becomes much more laggy/choppy.
Has anyone noticed this issue or found a workaround?
When using shadows, the shadowPath property of CALayer makes a very (!) noticable difference in performance, especially on the New iPad. Although I agree that disabling shadows when changing the display orientation is a good idea, it may be worth a try to just use shadowPath (if you do not use it already). Although the path can be any valid CGPathRef, in most cases this is what you want:
self.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.layer.bounds].CGPath;
There are things which are very expensive in terms of CPU time. Check it out in Instruments some time.
shadows
bezier paths
bezier paths with dashes (really expensive)
Thats not a comprehensive list. I suspect gradients will be there too.
If you find these things are degrading your animation or redraw you will need to toggle them in the UIViewController methods.
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
//disable shadows + expensive drawing
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
//enable shadows + expensive drawing
}
I am developing an iPhone application in which I want set the shadow for the path that I am drawing on UIView's context.
Following is the code snippet:
CGSize shadowSize = CGSizeMake(-4, -4);
CGContextSetShadowWithColor(drawContext, shadowSize, blurRadius,
shadowColor.CGColor);
//Stroke the bezier path
Since I am drawing an UIImage in the same context of UIView, I need to flip the context. All the drawing is fine except that shadow is shown in the bottom and right-side (my expectation was top and right sides).
When I tried this drawing in a context that I created (not the UIView context and hence not flipped), the shadow is appeared properly.
What is the problem here? How do I solve this?
From Apple docs (Drawing and Printing Guide for iOS):
"Flipping the CTM to align an object with the default coordinate system of UIKit does not affect the object’s shadow, and so a shadow does not correctly track its object. To get it to track correctly, you must modify the offset values appropriately for the current coordinate system."