26

I have a UIView object that rotates using CALayer's transform:

// Create uiview object.
UIImageView *block = [[UIImageView alloc] initWithFrame....]

// Apply rotation.
CATransform3D basicTrans = CATransform3DIdentity;
basicTrans.m34 = 1.0/-distance;
blockImage.layer.transform = CATransform3DRotate(basicTrans, rangle, 1.0f, 0.0f, 0.0f);

After rotating the edges of the object are not antialiasing. I need to antialias them. Help me, please. How can it be done?

Rafał Sroka
  • 39,540
  • 23
  • 113
  • 143
Oleg
  • 1,383
  • 4
  • 19
  • 35

4 Answers4

45

One way to do this is by placing the image inside another view that's 5 pixels bigger. The bigger view should have a transparent rasterized border that will smooth the edges of the UIImageView:

view.layer.borderWidth = 3; 
view.layer.borderColor = [UIColor clearColor].CGColor; 
view.layer.shouldRasterize = YES; 
view.layer.rasterizationScale = [[UIScreen mainScreen] scale];

Then, place your UIImageView inside this parent view and center it (With 2.5 pixels around each edge).

Finally, rotate the parent view instead of the image view.

It works very well - you can also encapsulate the whole thing in class that creates the hierarchy.

tarmes
  • 15,366
  • 10
  • 53
  • 87
42

Simply add this key-value pair to your Info.plist: UIViewEdgeAntialiasing set to YES.

s1m0n
  • 7,825
  • 1
  • 32
  • 45
AddisDev
  • 1,791
  • 21
  • 33
32

check allowsEdgeAntialiasing property of CALayer.

block.layer.allowsEdgeAntialiasing = YES; // iOS7 and above.
tounaobun
  • 14,570
  • 9
  • 53
  • 75
  • 1
    just like above (Info.plist) but more granular control! Excellent! – horseshoe7 Oct 08 '15 at 12:59
  • 1
    The accepted answer does work just like this one, but this one performs better. Both spend the same RAM, but this solution offers higher FPS to the user. – Roger Oba Oct 14 '16 at 18:15
  • The documentation for this property says the value is NO if the Info.plist value is absent. Apparently, you can't simply set just this property but have to use it in conjunction with the plist. I've not tested what happens if the property is not set, but judging from the answer by AddisDev, it defaults to yes in that case. So if there is a performance hit and you don't need antialiasing, it seems the thing to do is to set this value to NO. – Victor Engel Oct 15 '17 at 21:45
3

I had a similar issue when rotating around the z-axis. Setting shouldRasterize = YES prevented the jagged edges however it came at a performance cost. In my case I was re-using the views (and its layers) and keeping the shouldRasterize = YES was slowing things down.

The solution was, to turn off rasterization right after I didn't need it anymore. However since animation runs on another thread, there was no way of knowing when the animation was complete...until I found out about an extremely useful CATransaction method. This is an actual code that I used and it should illustrate its use:

// Create a key frame animation
CAKeyframeAnimation *wiggle = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
NSInteger frequency = 5; // Higher value for faster vibration
NSInteger amplitude = 25; // Higher value for lower amplitude
// Create the values it will pass through    
NSMutableArray *valuesArray = [[NSMutableArray alloc] init];
NSInteger direction = 1;

[valuesArray addObject:@0.0];

for (NSInteger i = frequency; i > 0; i--, direction *= -1) {
    [valuesArray addObject:@((direction * M_PI_4 * (CGFloat)i / (CGFloat)amplitude))];
}

[valuesArray addObject:@0.0];
[wiggle setValues:valuesArray];

// Set the duration
[wiggle setAdditive:YES];
[wiggle setValueFunction:[CAValueFunction functionWithName:kCAValueFunctionRotateZ]];
[wiggle setDuration:0.6];

// Turn on rasterization to prevent jagged edges (anti-aliasing issues)
viewToRotate.layer.shouldRasterize = YES;

// ************ Important step **************
// Very usefull method. Block returns after ALL animations have completed.
[CATransaction setCompletionBlock:^{
    viewToRotate.layer.shouldRasterize = NO;
}];
// Animate the layer
[viewToRotate.layer addAnimation:wiggle forKey:@"wiggleAnimation"];

worked like a charm for me.

I have not tried using this with implicit animations (i.e. animations that happen due to value change in animatable property for a non-view associated layer), however I would expect it to work as long as the CATransaction method is called before the property change, just as a guarantee the block is given to CATransaction before an animation starts.

Raz
  • 1,387
  • 12
  • 13