UILabel layer cornerRadius негативно влияет на производительность - PullRequest
45 голосов
/ 19 января 2011

Я создал вид документа, который отображает номер страницы в углу.Номер страницы представляет собой uilabel с полупрозрачным фоновым цветом и имеет угловой радиус (используя свойство cornerRadius view 'layer).Я поместил это выше UIScrollView.Тем не менее, это делает прокрутку рывком.Если я уберу cornerRadius, производительность будет хорошей.Что я могу с этим поделать?Что было бы лучшим решением?Похоже, что было достигнуто в UIWebView без каких-либо проблем с производительностью.

Ответы [ 4 ]

144 голосов
/ 06 июня 2011

Для надписей или видов с закругленными углами и / или цветов фона и теней при прокрутке видов решение довольно простое:

Самая большая проблема связана с параметром слоя masksToBounds.Похоже, что это значительно снижает производительность, однако метка, по-видимому, нуждается в этом включении, чтобы замаскировать цвет фона на закругленные углы.Таким образом, чтобы обойти это, вам нужно вместо этого установить цвет фона слоя надписей и отключить masksToBounds.

Вторая проблема заключается в том, что поведение по умолчанию состоит в том, чтобы по возможности перерисовывать вид, что совершенно не нужно при статических или медленных изменениях.предметы на прокрутке просмотров.Здесь мы просто устанавливаем layer.shouldRasterize = YES.Это позволит CA «кэшировать» растрированную версию вида для быстрого рисования при прокрутке (предположительно с аппаратным ускорением).

Вам необходимо убедиться, что ваш слой имеет альфа-канал, иначе растеризация повлияет на отрисовкузакругленные углы.У меня никогда не было проблем, так как у меня есть альфа-установка для моих цветов фона, но вам, возможно, придется проверить в вашей ситуации.

Вот пример 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 такими же видами и по-прежнему плавно прокручивать:)

8 голосов
/ 01 августа 2013

Я тоже наткнулся на это.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;
}
6 голосов
/ 19 января 2011

Как предположил Питер, после просмотра «связанных» постов на боковой панели я решил создать свой собственный образ. Я создал подкласс 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];
3 голосов
/ 19 января 2011

У меня была похожая проблема с UILabel в пользовательском UITableViewCell с закругленными углами. Чтобы добиться плавной работы, я «сделал» изображения с закругленными углами, чтобы обойти это ( см. ).

Множество других постов, включая this или this , может помочь.

...