Уровень UILabel cornerRadius отрицательно влияет на производительность

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

Ответ 1

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

Самая большая проблема связана с параметром слоя 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 с такими видами и по-прежнему прокручивать гладко:)

Ответ 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

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

Многие другие сообщения, в том числе this, или , могут помочь.