Antialiasing edges of UIView after transformation

2019-01-21 09:38发布

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?

4条回答
Ridiculous、
2楼-- · 2019-01-21 10:00

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.

查看更多
放荡不羁爱自由
3楼-- · 2019-01-21 10:01

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.

查看更多
我想做一个坏孩纸
4楼-- · 2019-01-21 10:09

check allowsEdgeAntialiasing property of CALayer.

block.layer.allowsEdgeAntialiasing = YES; // iOS7 and above.
查看更多
forever°为你锁心
5楼-- · 2019-01-21 10:25

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

查看更多
登录 后发表回答