¿Puedo usar el diseño automático para proporcionar diferentes restricciones para las orientaciones de paisaje y retrato?


¿Es posible cambiar las restricciones cuando se gira el dispositivo? ¿Cómo podría lograrse esto?

Un ejemplo simple podría ser dos imágenes que, en vertical, se apilan una encima de la otra, pero en horizontal están una al lado de la otra.

Si esto no es posible, ¿de qué otra manera podría lograr este diseño?

Estoy construyendo mis vistas y restricciones en código y no estoy usando interface builder.

Author: Ben Packard, 2013-07-21

5 answers

Editar: Usando el nuevo concepto de Clases de Tamaño introducido en Xcode 6, puede configurar fácilmente diferentes restricciones para clases de tamaño específicas en Interface Builder. La mayoría de los dispositivos (por ejemplo, todos los iPhones actuales) tienen una clase de tamaño vertical Compact en modo horizontal.

Este es un concepto mucho mejor para las decisiones de diseño general que determinar la orientación del dispositivo.

Dicho esto, si realmente necesita saber la orientación, UIDevice.currentDevice().orientation es el camino a seguir.


Mensaje original:

Anula el método updateViewConstraints de UIViewController para proporcionar restricciones de diseño para situaciones específicas. De esta manera, el diseño siempre se configura de la manera correcta según la situación. Asegúrese de que formen un conjunto completo de restricciones con las creadas dentro del guion gráfico. Puede usar IB para configurar sus restricciones generales y marcar aquellas sujetas a cambios que se eliminarán en tiempo de ejecución.

Uso the following implementation to present a different set of constraints for each orientation:

-(void)updateViewConstraints {
    [super updateViewConstraints];

    // constraints for portrait orientation
    // use a property to change a constraint's constant and/or create constraints programmatically, e.g.:
    if (!self.layoutConstraintsPortrait) {
        UIView *image1 = self.image1;
        UIView *image2 = self.image2;
        self.layoutConstraintsPortrait = [[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[image1]-[image2]-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(image1, image2)] mutableCopy];
        [self.layoutConstraintsPortrait addObject:[NSLayoutConstraint constraintWithItem:image1 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem: image1.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
        [self.layoutConstraintsPortrait addObject:[NSLayoutConstraint constraintWithItem:image2 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:image2.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
    }

    // constraints for landscape orientation
    // make sure they don't conflict with and complement the existing constraints
    if (!self.layoutConstraintsLandscape) {
        UIView *image1 = self.image1;
        UIView *image2 = self.image2;
        self.layoutConstraintsLandscape = [[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[image1]-[image2]-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(image1, image2)] mutableCopy];
        [self.layoutConstraintsLandscape addObject:[NSLayoutConstraint constraintWithItem:image1 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:image1.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
        [self.layoutConstraintsLandscape addObject:[NSLayoutConstraint constraintWithItem:image2 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem: image2.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
    }

    BOOL isPortrait = UIInterfaceOrientationIsPortrait(self.interfaceOrientation);
    [self.view removeConstraints:isPortrait ? self.layoutConstraintsLandscape : self.layoutConstraintsPortrait];
    [self.view addConstraints:isPortrait ? self.layoutConstraintsPortrait : self.layoutConstraintsLandscape];        
}

Ahora, todo lo que necesita hacer es activar una actualización de restricción cada vez que cambie la situación. Override willAnimateRotationToInterfaceOrientation:duration: para animar la actualización de la restricción en el cambio de orientación:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];

    [self.view setNeedsUpdateConstraints];

}
 39
Author: knl,
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
2014-10-16 21:51:26

El enfoque que estoy utilizando (para bien o para mal) es definir ambos conjuntos de restricciones (retrato y paisaje) en el editor de storyboard.

Para evitar las advertencias del guion gráfico del infierno, coloco todo un conjunto en una prioridad de 999, solo para que no se muestre rojo en todas partes.

Luego añado todas las restricciones a las colecciones de outlet:

@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *portraitConstraints;
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *landscapeConstraints;

Finalmente, implemento mi ViewControllers's viewWillLayout método:

- (void) viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];
    for (NSLayoutConstraint *constraint in self.portraitConstraints) {
        constraint.active = (UIApplication.sharedApplication.statusBarOrientation == UIDeviceOrientationPortrait);
    }
    for (NSLayoutConstraint *constraint in self.landscapeConstraints) {
        constraint.active = (UIApplication.sharedApplication.statusBarOrientation != UIDeviceOrientationPortrait);
    }
}

Esto parece funcionar. Yo realmente deseo que usted podría establecer la propiedad activa predeterminada en el editor de storyboard.

 17
Author: Travis Griggs,
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-11-17 12:57:22

Estoy siguiendo el mismo enfoque que el suyo (sin archivos ni guiones gráficos). Debe actualizar sus restricciones en el método updateViewConstraints (verificando la orientación del dispositivo). No es necesario llamar a setNeedsUpdateConstraints en updateViewConstraints porque tan pronto como cambie la orientación del dispositivo, el último método se llama automáticamente.

 2
Author: rokridi,
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
2013-12-03 10:43:20

Puede guardar sus restricciones en una propiedad o variable como versiones vertical y horizontal y luego establecerlas y eliminarlas al girar.

He hecho esto haciendo mis restricciones en xib para la vista inicial, asignándolas a outlets en el controlador de vista. Al girar creo las restricciones alternativas, quitar las salidas pero retenerlas, insertar las alternativas.

Invertir el proceso en girar hacia atrás.

 0
Author: Dean Davids,
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
2013-07-21 13:59:42

Mi idea es manejar la orientación cambiando las prioridades de restricción.
Supongamos que las prioridades serán:

  • paisaje: 910 activo / 10 inactivo.
  • retrato: 920 activo / 20 inactivo.

Paso 1: Cree un diseño horizontal (o vertical) en Storyboard con restricciones.
Paso 2: Para las restricciones, que deben estar activas solo para el modo horizontal, establezca la prioridad en 10.
Paso 3: Añadir restricciones para el modo retrato y establecer su prioridad a 920.

En willAnimateRotationToInterfaceOrientation añádase el código:

for (NSLayoutConstraint *constraint in myView.constraints) {
    if (UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication.statusBarOrientation)) {
        if (constraint.priority == 10)  constraint.priority = 910;
        if (constraint.priority == 920) constraint.priority = 20;
    } else {
        if (constraint.priority == 20)  constraint.priority = 920;
        if (constraint.priority == 910) constraint.priority = 10;
    }
}

Ventaja de este enfoque - fácil ajuste en el creador de interfaces. Cuando necesitamos cambiar a cualquier orientación, seleccionamos todas las restricciones por prioridad y las cambiamos simultáneamente (910->10, 20->920):

introduzca la descripción de la imagen aquí

La interfaz se reconstruirá automáticamente.

 -1
Author: Igor,
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-09 17:55:16