ios UILabel 层cornerRadius 对性能产生负面影响
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4735623/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UILabel layer cornerRadius negatively impacting performance
提问by Nick
I've created a document view which displays the page number in the corner. The page number is a uilabel with a semi-transparent background colour, and has a corner radius (using the cornerRadius
property of the view
's layer
). I've positioned this above a UIScrollView
. However, this makes scrolling jerky. If I remove the cornerRadius
, performance is good. Is there anything I can do about this? What would be a better solution? It seems to have been achieved in the UIWebView
without any performance issues.
我创建了一个文档视图,它在角落显示页码。页码是一个带有半透明背景色的 uilabel,并且有一个圆角半径(使用's的cornerRadius
属性)。我已经把它放在一个. 但是,这会使滚动生涩。如果我删除,性能很好。我能做些什么吗?什么是更好的解决方案?它似乎已经在没有任何性能问题的情况下实现了。view
layer
UIScrollView
cornerRadius
UIWebView
回答by psychoacoustic
For labels, or views with rounded corners and or background colors and shadows on scrolling views the solution is pretty simple:
对于标签或带有圆角的视图和/或滚动视图上的背景颜色和阴影,解决方案非常简单:
The biggest issue is from the masksToBounds layer option. This appears to tax performance significantly, however the label seems to need this ON to mask the background color to rounded corners. So to get around this you need to set the labels layer background color instead and switch off masksToBounds.
最大的问题是来自 maskToBounds 层选项。这似乎会显着影响性能,但是标签似乎需要此 ON 以将背景颜色屏蔽为圆角。因此,要解决这个问题,你需要设置标签层背景颜色来代替,而关掉masksToBounds。
The second issue is that the default behavior is to redraw the view whenever possible which is totally unnecessary with static or slow changing items on scrolling views. Here we simply set layer.shouldRasterize = YES. This will allow CA to 'cache' a rasterized version of the view for quick drawing when scrolling (presumably with hardware acceleration).
第二个问题是默认行为是尽可能重绘视图,这对于滚动视图上的静态或缓慢变化的项目是完全没有必要的。这里我们简单地设置 layer.shouldRasterize = YES。这将允许 CA“缓存”视图的光栅化版本,以便在滚动时快速绘制(大概是硬件加速)。
You need to make sure your layer has an alpha channel otherwise rasterizing will affect the drawing of rounded corners. I've never had a problem as I have alpha set for my background colors, but you may need to check in your situation.
你需要确保你的图层有一个 alpha 通道,否则光栅化会影响圆角的绘制。我从来没有遇到过问题,因为我为我的背景颜色设置了 alpha,但是您可能需要检查您的情况。
Here is a sample UILabel set up to work nicely on a scollview:
这是一个设置为在 scollview 上很好地工作的示例 UILabel:
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];
I can fill the iPad 1 screen with views like this and still scroll smoothly :)
我可以用这样的视图填充 iPad 1 屏幕,并且仍然可以平滑滚动:)
回答by Szuwar_Jr
I stumbled into this one too. cornerRadius (for UIButton and UIImageView) was killing my app performance. I have found no working solution that rounds UIButton with background image, so I had to write my own piece of code - first method. Second adds a round corner and border to a UIImageView. I think that code speaks for itself.
我也偶然发现了这个。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;
}
回答by Nick
Like petert suggested, after seeing the 'related' posts in the side bar I decided to create my own image. I subclassed UIView and added a background image (for the background with rounded edges) and a standard textlabel on init. To create the background image I make a stretchable image using the CG drawing functions.
就像 petert 建议的那样,在看到侧栏中的“相关”帖子后,我决定创建自己的图像。我继承了 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];
回答by petert
I had a similar issue with UILabel
in a custom UITableViewCell
with rounded corners. To get smooth performance I 'made' images with rounded-corners to get around this (see).
我UILabel
在UITableViewCell
带有圆角的自定义中遇到了类似的问题。为了获得流畅的性能,我“制作”了带有圆角的图像来解决这个问题(请参阅 参考资料)。