46 votes

La couche UILabel cornerRadius a un impact négatif sur les performances

J'ai créé un document de la vue qui affiche le numéro de page dans le coin. Le numéro de page est un uilabel avec un fond semi-transparent de couleur, et a un rayon d'angle (à l'aide de l' cornerRadius de la propriété de l' views' layer). Je l'ai placé au-dessus d'un UIScrollView. Cependant, ce qui rend le défilement saccadé. Si je supprime l' cornerRadius, la performance est bonne. Est-ce que je peux faire à ce sujet? Quelle serait une meilleure solution? Il semble avoir été atteint dans l' UIWebView sans les problèmes de performance.

145voto

fknrdcls Points 831

Pour les étiquettes, ou de points de vue avec des coins arrondis et ou les couleurs de fond et les ombres sur le défilement des vues de la solution est assez simple:

Le plus gros problème est de la masksToBounds option de calque. Il semble que cette taxe performances de manière significative, cependant l'étiquette semble avoir besoin de cette SUR pour masquer la couleur d'arrière-plan à coins arrondis. Afin de contourner ce problème, vous devez définir les étiquettes de la couche de couleur d'arrière-plan au lieu et éteindre masksToBounds.

Le deuxième problème est que le comportement par défaut est le rafraîchissement de l'affichage chaque fois que possible, ce qui est totalement inutile de l'électricité statique ou lent, modifier des éléments sur le défilement des vues. Ici, nous avons simplement mis de couche.shouldRasterize = OUI. Ceci permettra à l'autorité de certification pour "cache" un pixellisé version de la vue pour l'élaboration rapide lors du défilement (sans doute avec l'accélération matérielle).

Vous devez vous assurer que votre couche a un canal alpha sinon pixellisation affectera le dessin des angles arrondis. Je n'ai jamais eu un problème comme je l'ai jeu alpha pour mes couleurs d'arrière-plan, mais vous pouvez avoir besoin de vérifier dans votre situation.

Voici un exemple de UILabel mis en place pour travailler en douceur sur un 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;
// self here is the child view in the scroll view
[self addSubview:lbl];
[lbl release];

Je peux remplir l'iPad 1 à l'écran avec une vue comme ça, et encore de défilement en douceur :)

8voto

Szuwar_Jr Points 137

Je suis tombé sur celui-ci aussi. cornerRadius (pour UIButton et UIImageView) était en train de tuer les performances de mon application. Je n’ai trouvé aucune solution efficace pour arrondir UIButton avec une image d’arrière-plan; il a donc fallu écrire mon propre morceau de code - une première méthode. Second ajoute un coin arrondi et une bordure à UIImageView. Je pense que ce code parle pour lui-même.

 +(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;
}
 

6voto

Nick Points 465

Comme l'a suggéré Petert, après avoir vu les messages "liés" dans la barre latérale, j'ai décidé de créer ma propre image. J'ai sous-classé UIView et ajouté une image d'arrière-plan (pour l'arrière-plan aux bords arrondis) et une étiquette de texte standard sur init. Pour créer l'image d'arrière-plan, je crée une image extensible à l'aide des fonctions de dessin en 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];
 

3voto

petert Points 5082

J'ai eu un problème similaire avec UILabel personnalisé dans un UITableViewCell , avec des coins arrondis. Pour obtenir le bon spectacle, j'ai "fait" des images avec des angles arrondis pour contourner ce problème (voir).

Beaucoup d'autres postes, y compris les ce, ou cela pourrait aider.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X