ios10: viewDidLoad frame width / height no inicializado correctamente


Desde la actualización a XCode8 GM e ios10, todas mis vistas creadas a través de Interface Builder no se inicializan correctamente hasta mucho más tarde de lo esperado. Esto significa que en viewDidLoad, cellForRowAtIndexPath, viewWillAppear, etc, el tamaño del marco se establece en {1000,1000} para cada vista. En algún momento parecen corregir, pero es demasiado tarde.

El primer problema encontrado es con el redondeo común de esquinas fallando en todos los ámbitos:

view.layer.cornerRadius = view.frame.size.width/2

Otros problemas son mostrar 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 marco falla en la visualización inicial de la tabla, pero luego funciona bien una vez que se 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, así como bastante numerosa en mis proyectos.

¿Hay una manera o lugar para obtener el marco correcto ¿tallas?

EDITAR

He descubierto que usar la restricción height/width en lugar de frame width height es más confiable. Sin embargo, esto puede agregar la sobrecarga de necesitar muchos IBOutlets nuevos para vincular las restricciones de altura/ancho en los elementos.

Por ahora he creado una categoría UIView que me permite acceder a las restricciones de altura/anchura de una vista directamente sin los IBOutlets. Para un uso mínimo, el bucle pequeño no debería ser un gran problema. Resultados no garantizados para artículos IB sin las restricciones de ancho/alto creadas sin embargo, obviamente. Probablemente devuelve 0 en el mejor de los casos para la constante, o peor. Además, si no tiene una restricción de altura/anchura y su vista tiene un tamaño dinámico basado en restricciones iniciales/finales, esto no funcionará.

- viewDidLoad parece tener el tamaño de fotograma correcto, pero a menudo resultará en un cambio visual en la interfaz de usuario si realiza modificaciones aqui.

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

EDITAR 2

La categoría anterior solo ha demostrado ser parcialmente efectiva. Principalmente porque ios parece agregar automáticamente un par de duplicados adicionales de restricción de altura/ancho, que son de tipo NSContentSizeLayoutConstraint, que en realidad no son del mismo tamaño que la restricción normal. El NSContentSizeLayoutConstraint es también un clase privada así que no puedo hacer isKindOfClass para filtrar esos. Todavía no he encontrado otra manera de probarlos de manera efectiva. Esto es molesto.

Author: pedrouan, 2016-09-13

7 answers

Los problemas más comunes que describe aparecen solo en iOS 10 y se pueden resolver agregando esta línea (si es necesario):

self.view.layoutIfNeeded()

Justo encima del código, que es responsable de cambiar la restricción, capa.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
}
 29
Author: pedrouan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-28 08:55:57

Creamos un radar (28342777 (marcado como duplicado para 28221021 pero Abierto)) para el problema similar y la respuesta que obtuvimos fue la siguiente:

"Gracias por reportar el problema. ¿Podríamos obtener más información sobre la vista de imagen de perfil? En Xcode 8, una vista completamente restringida y no fuera de lugar ya no guarda un fotograma para minimizar las diferencias y admitir la actualización automática de fotogramas en IB. En tiempo de ejecución, estas vistas se decodifican con un tamaño de marcador de posición de 1000x1000, pero se resuelven después primer plano. ¿Se podría asignar la imagen antes del diseño inicial, y asignar la imagen a la vista de imagen después del primer diseño abordaría este caso? Envíe una muestra para ayudarnos a analizar más a fondo. ¡Gracias!"

En la actualidad les hemos proporcionado el proyecto de muestra. Mis observaciones:

  • El problema que solíamos ocurrir para XIBs que se convierten desde Xcode 7.x a Xcode 8.x
  • Si rompemos intencionalmente la restricción en XIB, se espera que viewDidLoad altura y anchura y no 1000x1000.
  • Para nosotros era un UIImageView en el que aplicábamos algunas capas para hacerlo circular y usar masksToBounds. Si establecemos masksToBounds = NO, entonces todo estaba funcionando 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.

 16
Author: Bhavik Bhagat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-27 17:35:54

Me encontré con el mismo problema y tratar de resolverlo sin suerte haciendo referencia a las sugerencias anteriores.

Parece que debería ser un error para que Apple lo solucione. Finalmente encuentro una solución cambiando para guardar mi documento XIB de nuevo a Xcode 7.formato x y mi interfaz de usuario a la normalidad.

Hasta que Apple publique una corrección, no quiero gastar mi tiempo en hackearla.

introduzca la descripción de la imagen aquí introduzca la descripción de la imagen aquí

 6
Author: allen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-25 04:15:02

Qué hay de 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;
}
 2
Author: 942v,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-17 20:46:28

Nunca debe confiar en el momento en que se presenta una vista. Si eso funcionó para ti antes, entonces por pura suerte. Hay muy pocas garantías sobre esto en UIKit. Si confías en algo que adopta el tamaño de tu vista, lo correcto es anular layoutSubviews en esa vista y ajustar tus cosas allí.

Incluso después de que su vista esté completamente renderizada en la pantalla, todavía hay muchas condiciones que podrían hacer que el tamaño de la vista cambie. Por ejemplo: Doble altura barra de estado, 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.

 2
Author: Michael Ochs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-22 09:57:26

Estaba teniendo exactamente el mismo problema. Tenía subclases UITableViewCell personalizadas y estaba usando clipsToBounds = YES y self.iconView.layer.cornerRadius = self.iconView.frame.size.width/2 para darme una imagen circular. Intenté llamar a mi método de configuración de celda desde cellForRowAtIndexPath y willDisplayCell y ninguno funcionó.

Esto es lo que funciona:
Mueva su código de capas al método -layoutSubviews de 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 deben cargarse correctamente y su código de capas también debe funcionar.

 1
Author: TylerJames,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-05 17:37:39

Solo Actualiza frame en tu cuadro de diseño automático .introduzca la descripción de la imagen aquí

 0
Author: neha mishra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-01 12:07:39