【问题标题】:UILabel layer cornerRadius negatively impacting performanceUILabel 层cornerRadius 对性能产生负面影响
【发布时间】:2011-06-11 18:14:45
【问题描述】:

我创建了一个文档视图,它在角落显示页码。页码是一个带有半透明背景颜色的 uilabel,并且有一个圆角半径(使用viewlayercornerRadius 属性)。我已将其置于UIScrollView 上方。然而,这使得滚动生涩。如果我删除cornerRadius,性能很好。对此我能做些什么吗?什么是更好的解决方案?在UIWebView 中似乎已经实现了,没有任何性能问题。

【问题讨论】:

    标签: ios uiview uilabel calayer


    【解决方案1】:

    对于标签或带有圆角的视图和/或滚动视图上的背景颜色和阴影,解决方案非常简单:

    最大的问题来自于 maskToBounds 图层选项。这似乎对性能产生了显着影响,但是标签似乎需要此 ON 以将背景颜色掩盖为圆角。因此,要解决这个问题,您需要设置标签层背景颜色并关闭 maskToBounds。

    第二个问题是默认行为是尽可能重绘视图,这对于滚动视图上的静态或缓慢变化的项目是完全没有必要的。这里我们简单地设置 layer.shouldRasterize = YES。这将允许 CA “缓存”视图的光栅化版本,以便在滚动时快速绘制(可能使用硬件加速)。

    您需要确保您的图层具有 Alpha 通道,否则光栅化会影响圆角的绘制。我从来没有遇到过问题,因为我为背景颜色设置了 alpha,但您可能需要检查您的情况。

    这是一个示例 UILabel 设置,可以在 scollview 上很好地工作:

    UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(4, 4, 40.0, 24.0)];
    lbl.font = [UIFont fontWithName:@"Helvetica" size:14.0];
    lbl.textAlignment = UITextAlignmentRight;
    lbl.text = @"Hello World";
    // Must set the label background to clear so the layer background shows
    lbl.backgroundColor = [UIColor clearColor];        
    // Set UILabel.layer.backgroundColor not UILabel.backgroundColor otherwise the background is not masked to the rounded border.
    lbl.layer.backgroundColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.5].CGColor;
    
    lbl.layer.cornerRadius = 8;
    lbl.layer.borderColor = [UIColor blackColor].CGColor;
    lbl.layer.borderWidth = 1;
    // Huge change in performance by explicitly setting the below (even though default is supposedly NO)
    lbl.layer.masksToBounds = NO;
    // Performance improvement here depends on the size of your view
    lbl.layer.shouldRasterize = YES;
    lbl.layer.rasterizationScale = [UIScreen mainScreen].scale;
    // self here is the child view in the scroll view
    [self addSubview:lbl];
    [lbl release];
    

    我可以用这样的视图填充 iPad 1 屏幕,并且仍然可以流畅地滚动:)

    【讨论】:

    • 谢谢。对我也很好。
    • 顺便说一句,如果使用.shouldRasterize = YES,UILabel 的内容在视网膜设备上看起来会被弄脏。
    • @bioffe:这可以通过设置光栅化比例轻松解决:lbl.layer.rasterizationScale = [UIScreen mainScreen].scale;
    • 完美!但是 UIImageView 呢?
    • 这太完美了!谢谢!我认为@DanielRinser 关于 rasterizationScale 的评论应该是这个答案的一部分,因为现在基本上每个设备都是 Retina Display
    【解决方案2】:

    我也偶然发现了这个。 cornerRadius(用于 UIButton 和 UIImageView)正在扼杀我的应用程序性能。我没有找到用背景图像环绕 UIButton 的有效解决方案,所以我不得不编写自己的一段代码 - 第一种方法。其次为 UIImageView 添加圆角和边框。我认为代码不言自明。

    +(void)setBackgroundImage:(UIImage*)image forButton:(UIButton*)button withCornerRadius:(float)cornerRadius borderColor:(CGColorRef)borderColor andBorderWith:(float)borderWidth
    {
        UIImageView *tempImageView = [[UIImageView alloc] initWithFrame:button.frame];
        UIGraphicsBeginImageContextWithOptions(tempImageView.bounds.size, NO, 1.0);
        [[UIBezierPath bezierPathWithRoundedRect:tempImageView.bounds
                                    cornerRadius:cornerRadius] addClip];
        [image drawInRect:tempImageView.bounds];
        tempImageView.image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        [button setBackgroundImage:tempImageView.image forState:UIControlStateNormal];
        button.layer.shouldRasterize = YES;
        button.layer.borderColor = borderColor;
        button.layer.borderWidth = borderWidth;
        button.layer.cornerRadius = cornerRadius;
    }
    
    +(void)makeRoundedCornersForImageView:(UIImageView*)imgV withCornerRadius:(float)cornerRadius borderColor:(CGColorRef)borderColor andBorderWith:(float)borderWidth
    {
        UIImageView *tempImageView = [[UIImageView alloc] initWithFrame:imgV.frame];
        UIGraphicsBeginImageContextWithOptions(tempImageView.bounds.size, NO, 1.0);
        [[UIBezierPath bezierPathWithRoundedRect:tempImageView.bounds
                                    cornerRadius:cornerRadius] addClip];
        [imgV.image drawInRect:tempImageView.bounds];
        tempImageView.image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        imgV.image = tempImageView.image;
        imgV.layer.shouldRasterize = YES;
        imgV.layer.borderColor = borderColor;
        imgV.layer.borderWidth = borderWidth;
        imgV.layer.cornerRadius = cornerRadius;
    }
    

    【讨论】:

      【解决方案3】:

      就像彼得建议的那样,在看到侧栏中的“相关”帖子后,我决定创建自己的图像。我对 UIView 进行了子类化,并在 init 上添加了一个背景图像(用于具有圆边的背景)和一个标准文本标签。为了创建背景图像,我使用 CG 绘图功能制作了可拉伸的图像。

          // create background image
          CGFloat radius = frame.size.height / 2;
          CGFloat imgSize = (radius*2)+1; // 1 pixel for stretching
          UIGraphicsBeginImageContext(CGSizeMake(imgSize, imgSize));
          CGContextRef context = UIGraphicsGetCurrentContext();
      
          CGContextSetAlpha(context, 0.5f);
          CGContextSetLineWidth(context, 0);
          CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
      
          CGFloat minx = 0;
          CGFloat midx = imgSize/2;
          CGFloat maxx = imgSize;
          CGFloat miny = 0;
          CGFloat midy = imgSize/2;
          CGFloat maxy = imgSize;
      
          CGContextMoveToPoint(context, minx, midy);
          CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
          CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
          CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
          CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius);
          CGContextClosePath(context);
          CGContextDrawPath(context, kCGPathFillStroke);
      
          UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
          UIGraphicsEndImageContext();
      
          UIImage *stretchImage = [viewImage stretchableImageWithLeftCapWidth:radius topCapHeight:radius];
      
          UIImageView *stretch = [[UIImageView alloc] initWithImage:stretchImage];
          stretch.frame = self.bounds;
          stretch.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
          [self addSubview:stretch];
          [self sendSubviewToBack:stretch];
          [stretch release];
      

      【讨论】:

        【解决方案4】:

        我在带有圆角的自定义 UITableViewCell 中遇到了与 UILabel 类似的问题。为了获得流畅的性能,我“制作”了带有圆角的图像来解决这个问题 (see)。

        许多其他帖子,包括 thisthis 可能会有所帮助。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-15
          • 1970-01-01
          • 2017-06-12
          • 2011-01-15
          • 1970-01-01
          • 2014-07-02
          相关资源
          最近更新 更多