Сглаживание ребер UIView после преобразования с использованием преобразования CALayer - PullRequest
24 голосов
/ 29 ноября 2011

У меня есть UIView объект, который вращается с помощью преобразования CALayer:

// 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);

После поворота края объекта не сглаживаются. Мне нужно, чтобы противостоять им. Помоги мне, пожалуйста. Как это можно сделать?

Ответы [ 4 ]

43 голосов
/ 29 ноября 2011

Один из способов сделать это - поместить изображение в другое представление, которое на 5 пикселей больше.Большее представление должно иметь прозрачную растеризованную границу, которая сгладит края UIImageView:

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

Затем поместите ваш UIImageView в это родительское представление и отцентрируйте его (с 2,5 пикселями вокруг каждого края).

Наконец, поверните родительское представление вместо представления изображения.

Это работает очень хорошо - вы также можете инкапсулировать все в классе, который создает иерархию.

37 голосов
/ 22 августа 2012

Просто добавьте эту пару ключ-значение в Info.plist : UIViewEdgeAntialiasing, установленный в YES.

25 голосов
/ 15 сентября 2015

чек allowsEdgeAntialiasing свойство CALayer.

block.layer.allowsEdgeAntialiasing = YES; // iOS7 and above.
3 голосов
/ 01 мая 2013

У меня была похожая проблема при вращении вокруг оси z.Установка shouldRasterize = YES предотвратила зазубренные края, однако это привело к снижению производительности.В моем случае я повторно использовал представления (и их слои), и поддержание shouldRasterize = YES замедляло процесс.

Решение было в том, чтобы отключить растеризацию сразу после того, как она мне больше не нужна.Однако, поскольку анимация выполняется в другом потоке, не было никакого способа узнать, когда анимация была завершена ... пока я не узнал об очень полезном методе CATransaction.Это фактический код, который я использовал, и он должен иллюстрировать его использование:

// 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"];

работал для меня как оберег.

Я не пробовал использовать это с неявными анимациями (т.е. анимациями, которыепроисходит из-за изменения значения в свойстве animatable для связанного слоя, не являющегося видом), однако я ожидаю, что он будет работать до тех пор, пока метод CATransaction вызывается до изменения свойства, просто как гарантия, что блок передается в CATransaction перед анимациейначинается.

...