Сглаживание ребер UIView после преобразования с использованием преобразования CALayer
У меня есть 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 ответа
Один из способов сделать это - поместить изображение в другое представление, которое на 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 пикселями вокруг каждого края).
Наконец, поверните родительское представление вместо представления изображения.
Это работает очень хорошо - вы также можете инкапсулировать все это в классе, который создает иерархию.
Просто добавьте эту пару ключ-значение в ваш Info.plist: UIViewEdgeAntialiasing
установлен в YES
,
Проверять allowsEdgeAntialiasing
собственностью CALayer
,
block.layer.allowsEdgeAntialiasing = YES; // iOS7 and above.
У меня была похожая проблема при вращении вокруг оси 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"];
работал как шарм для меня.
Я не пытался использовать это с неявными анимациями (то есть анимациями, которые происходят из-за изменения значения в свойствах анимации для связанного слоя, не являющегося видом), однако я ожидал бы, что это будет работать до тех пор, пока метод CATransaction вызывается до изменения свойства, так же, как гарантия, блок передается CATransaction до запуска анимации.