ios - UILabel layer cornerRadius tiene un impacto negativo en el rendimiento
uiview calayer (4)
Creé una vista de documento que muestra el número de página en la esquina. El número de página es un uilabel con un color de fondo semitransparente y tiene un radio de esquina (usando la propiedad cornerRadius
de la layer
de la view
). He colocado esto encima de UIScrollView
. Sin embargo, esto hace que el desplazamiento sea espasmódico. Si cornerRadius
el cornerRadius
, el rendimiento es bueno. ¿Hay algo que pueda hacer al respecto? ¿Cuál sería una mejor solución? Parece que se ha logrado en UIWebView
sin ningún problema de rendimiento.
Al igual que sugirió Petert, después de ver las publicaciones ''relacionadas'' en la barra lateral, decidí crear mi propia imagen. Subclassed UIView y agregué una imagen de fondo (para el fondo con bordes redondeados) y una etiqueta de texto estándar en init. Para crear la imagen de fondo, hago una imagen extensible usando las funciones de dibujo 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];
Me tropecé con este también. cornerRadius (para UIButton y UIImageView) estaba matando el rendimiento de mi aplicación. No he encontrado ninguna solución de trabajo que redondee UIButton con la imagen de fondo, así que tuve que escribir mi propio código: primer método. Segundo agrega una esquina redonda y un borde a UIImageView. Creo que el código habla por sí mismo.
+(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;
}
Para etiquetas, o vistas con esquinas redondeadas y / o colores de fondo y sombras en vistas desplazables, la solución es bastante simple:
El mayor problema es de la opción de capa masksToBounds. Esto parece afectar significativamente el rendimiento del impuesto, sin embargo, la etiqueta parece necesitar este ENCENDIDO para enmascarar el color de fondo en las esquinas redondeadas. Para evitar esto, necesita establecer el color de fondo de la capa de etiquetas en su lugar y desactivar masksToBounds.
El segundo problema es que el comportamiento predeterminado es volver a dibujar la vista siempre que sea posible, lo que es totalmente innecesario con los elementos estáticos o que cambian lentamente en las vistas desplazables. Aquí simplemente establecemos layer.shouldRasterize = YES. Esto permitirá que CA "almacene en caché" una versión rasterizada de la vista para un dibujo rápido al desplazarse (presumiblemente con aceleración de hardware).
Debe asegurarse de que su capa tenga un canal alfa; de lo contrario, rasterizar afectará el dibujo de las esquinas redondeadas. Nunca he tenido un problema ya que tengo un conjunto alfa para mis colores de fondo, pero es posible que deba verificar su situación.
Aquí hay una muestra de UILabel configurada para funcionar bien en 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];
Puedo llenar la pantalla del iPad 1 con vistas como esta y seguir desplazándome sin problemas :)