objective-c - ratio - objective c documentation
ios10: ancho/alto del marco viewDidLoad no inicializado correctamente (7)
Desde que actualicé a XCode8 GM e ios10, todas mis vistas creadas a través de Interface Builder no se están inicializando correctamente hasta mucho más tarde de lo esperado. Esto significa que en viewDidLoad, cellForRowAtIndexPath, viewWillAppear, etc., el tamaño del marco está establecido en {1000,1000} para cada vista. En algún momento parecen corregir, pero es demasiado tarde.
El primer problema que se encuentra es que el redondeo común de esquinas falla en todos los ámbitos:
view.layer.cornerRadius = view.frame.size.width/2
Se muestran problemas adicionales para cualquier cosa que dependa del tamaño del marco para hacer cálculos en el código.
cellForRowAtIndexPath
Para cellForRowAtIndexPath, el tamaño del fotograma falla en la visualización de la tabla inicial, pero luego funciona bien una vez que lo desplaza. willDisplayCell: forRowAtIndexPath tampoco tiene el tamaño de fotograma correcto.
He codificado algunos valores, pero obviamente esta es una práctica de código muy mala, y bastante numerosa en mis proyectos.
¿Hay alguna forma o lugar para obtener los tamaños de fotogramas correctos?
EDITAR
Descubrí que usar la restricción de altura / ancho en lugar de la altura del ancho del marco es más confiable. Sin embargo, esto puede sumar la sobrecarga de necesitar muchos IBOutlets nuevos para vincular las restricciones de altura / ancho de los elementos.
Por ahora, he creado una categoría UIView que me permite acceder a las restricciones de altura / ancho de una vista directamente sin IBOutlets. Para un uso mínimo, el pequeño lazo no debería ser un gran problema. Los resultados no están garantizados para los ítems del IB sin las restricciones de ancho / altura aún evidentes. Probablemente devuelve 0 en el mejor de los casos para la constante o algo peor. Además, si no tiene una restricción de altura / ancho y su vista se dimensiona de forma dinámica en función de las restricciones de entrada / salida, esto no funcionará.
-viewDidLoad parece tener el tamaño de fotograma correcto, pero a menudo tendrá como resultado un cambio visual en la interfaz de usuario si realiza modificaciones aquí.
UIView + WidthHeightConstraints.h
@interface UIView (WidthHeightConstraints)
-(NSLayoutConstraint*)widthConstraint;
-(NSLayoutConstraint*)heightConstraint;
-(NSLayoutConstraint*)constraintForAttribute:(NSLayoutAttribute)attribute;
@end
UIView + WidthHeightConstraints.m
#import "UIView+WidthHeightConstraints.h"
@implementation UIView (WidthHeightConstraints)
-(NSLayoutConstraint*)widthConstraint{
return [self constraintForAttribute:NSLayoutAttributeWidth];
}
-(NSLayoutConstraint*)heightConstraint {
return [self constraintForAttribute:NSLayoutAttributeHeight];
}
-(NSLayoutConstraint*)constraintForAttribute:(NSLayoutAttribute)attribute {
NSLayoutConstraint *targetConstraint = nil;
for (NSLayoutConstraint *constraint in self.constraints) {
if (constraint.firstAttribute == attribute) {
targetConstraint = constraint;
break;
}
}
return targetConstraint;
}
@end
EDIT 2
La categoría anterior ha demostrado ser solo parcialmente efectiva. Principalmente porque ios parece agregar automáticamente un par de duplicados de restricciones adicionales de altura / ancho, que son del tipo NSContentSizeLayoutConstraint, que en realidad no son del mismo tamaño que la restricción normal. NSContentSizeLayoutConstraint es también una clase privada, así que no puedo hacer isKindOfClass para filtrarlos. No he encontrado otra manera de probar con eficacia para aquellos todavía. Esto es molesto
¿Qué tal hacer esto?
- (NSLayoutConstraint*)widthConstraint{
return [self constraintForAttribute:NSLayoutAttributeWidth];
}
- (NSLayoutConstraint*)heightConstraint {
return [self constraintForAttribute:NSLayoutAttributeHeight];
}
- (NSLayoutConstraint*)constraintForAttribute:(NSLayoutAttribute)attribute {
NSLayoutConstraint *targetConstraint = nil;
for (NSLayoutConstraint *constraint in self.constraints) {
//NSLog(@"constraint: %@", constraint);
if (![constraint isKindOfClass:NSClassFromString(@"NSContentSizeLayoutConstraint")]) {
if (constraint.firstAttribute == attribute) {
targetConstraint = constraint;
break;
}
}
}
return targetConstraint;
}
Creamos un radar (28342777 (marcado como duplicado para 28221021 pero abierto)) para el problema similar y la respuesta que recibimos fue la siguiente:
"Gracias por informar el problema. ¿Podríamos obtener más información sobre la vista de imagen de perfil? En Xcode 8, una vista totalmente restringida y no mal ubicada ya no guarda un marco para minimizar diffs y admite la actualización automática de marcos en IB. , estas vistas se decodifican con un tamaño de marcador de 1000x1000, pero se resuelven después del primer diseño. ¿Se podría asignar la imagen antes del diseño inicial y asignaría la imagen a la vista de imagen después de la primera dirección de diseño en este caso? Envía una muestra para ayudar nosotros más analizamos, ¡gracias! "
En este momento les hemos proporcionado el proyecto de muestra. Mis observaciones:
- El problema que solíamos tener para los XIB convertidos de Xcode 7.x a Xcode 8.x
- Si intencionalmente rompemos la restricción en XIB, viewDidLoad obtendrá la altura y el ancho esperados y no 1000x1000.
- Para nosotros fue un UIImageView en el que aplicamos algunas capas para hacerlo circular y usar masksToBounds. Si establecemos masksToBounds = NO, todo funcionaba bien.
Aunque Apple afirma que va a ser un estándar de Xcode 8 que las vistas se establecerán en 1000x1000, el comportamiento no parece ser consistente.
Espero que esto ayude.
Estaba teniendo exactamente el mismo problema. Tenía subclases personalizadas de UITableViewCell y estaba usando clipsToBounds = YES
y self.iconView.layer.cornerRadius = self.iconView.frame.size.width/2
para darme una imagen circular. Intenté llamar al método de configuración de mi celda desde cellForRowAtIndexPath
y willDisplayCell
y ninguno funcionó.
Esto es lo que funciona:
Mueva su código de estratificación en el método de la -layoutSubviews
de -layoutSubviews
la celda de esta manera:
-(void)layoutSubviews {
[super layoutSubviews];
self.iconView.clipsToBounds = YES;
self.iconView.layer.cornerRadius = self.iconView.frame.size.width/2;
}
Después de esto, las imágenes deberían cargarse correctamente y tu código de capas también debería funcionar.
Los problemas más comunes que describe aparecen solo en iOS 10 y pueden resolverse agregando esta línea (si es necesario):
self.view.layoutIfNeeded()
justo encima del código, que es responsable de cambiar la restricción, layer.cornerRadius, etc.
O
coloque su código relacionado con marcos / capas en el método viewDidLayoutSubviews()
:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
view.layer.cornerRadius = self.myView.frame.size.width/2
view.clipsToBounds = true
... etc
}
Me encontré con el mismo problema e intento resolverlo sin suerte al referirme a las sugerencias anteriores.
Parece que debería ser un error para Apple resolver. Finalmente encuentro una solución al cambiar para guardar mi documento XIB de nuevo en formato Xcode 7.x y mi IU volver a la normalidad.
Hasta que Apple libere una solución, no quiero perder mi tiempo en hackearla.
Nunca debe confiar en el momento en que se visualiza una vista. Si eso funcionó para ti antes, entonces por pura suerte. Hay muy pocas garantías sobre esto en UIKit. Si layoutSubviews
en algo que se layoutSubviews
al tamaño de tu vista, lo correcto es anular el layoutSubviews
las layoutSubviews
en esa vista y ajustar tus cosas allí.
Incluso después de que su vista se represente por completo en la pantalla, todavía hay tantas condiciones que pueden hacer que cambie el tamaño de la vista. Por ejemplo: barra de estado de doble altura, multitarea en iPad, rotación de dispositivos, solo por nombrar algunos. Por lo tanto, nunca es una buena idea hacer cambios de diseño relacionados con el marco en un momento determinado.