【问题标题】:Antialiasing edges of UIView after transformation using CALayer's transform使用 CALayer 的变换进行变换后 UIView 的抗锯齿边缘
【发布时间】:2012-01-08 23:20:08
【问题描述】:

我有一个使用CALayer 的变换旋转的UIView 对象:

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

旋转后对象的边缘没有抗锯齿。我需要对它们进行抗锯齿处理。 请帮帮我。怎么办?

【问题讨论】:

    标签: iphone objective-c uiview rotation antialiasing


    【解决方案1】:

    执行此操作的一种方法是将图像放在另一个大 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 个像素)。

    最后,旋转父视图而不是图像视图。

    它工作得很好——你也可以将整个东西封装在创建层次结构的类中。

    【讨论】:

    • 您可能需要添加 view.layer.rasterizationScale = [[UIScreen mainScreen] scale]; 以避免 Retina 屏幕上的模糊。
    • 这条评论应该是答案的一部分。设置 'shouldRasterize' 属性是不够的!
    • tounaobun 的回答表现更好。检查我下面的评论。
    【解决方案2】:

    检查CALayerallowsEdgeAntialiasing 属性。

    block.layer.allowsEdgeAntialiasing = YES; // iOS7 and above.
    

    【讨论】:

    • 就像上面的 (Info.plist) 但更精细的控制!太棒了!
    • 接受的答案确实像这个一样工作,但这个表现更好。两者都使用相同的 RAM,但此解决方案为用户提供了更高的 FPS。
    • 此属性的文档说如果 Info.plist 值不存在,则该值为 NO。显然,您不能只设置此属性,而必须将其与 plist 结合使用。我没有测试如果没有设置属性会发生什么,但从 AddisDev 的回答来看,在这种情况下它默认为是。因此,如果性能受到影响并且您不需要抗锯齿,似乎要做的就是将此值设置为 NO。
    【解决方案3】:

    只需将此键值对添加到您的 Info.plistUIViewEdgeAntialiasing 设置为 YES

    【讨论】:

    • 完美而简单的解决方案。
    【解决方案4】:

    我在绕 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 的保证。

    【讨论】:

      猜你喜欢
      • 2014-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-03
      • 1970-01-01
      • 1970-01-01
      • 2014-01-04
      相关资源
      最近更新 更多