¿Cómo puedo establecer restricciones de relación de aspecto mediante programación en iOS?

85

He utilizado el diseño automático para mis controladores de vista. Establecí las posiciones V y H en restricciones, pero quiero saber cómo puedo aumentar el tamaño de mi botón cuando cambia a 5s, 6 y 6 Plus. Esta es la forma en que agregué restricciones para el botón de inicio de sesión:

NSArray *btncon_V=[NSLayoutConstraint constraintsWithVisualFormat:@"V:[btnLogin(40)]" options:0 metrics:nil views:viewsDictionary];
[btnLogin addConstraints:btncon_V];

NSArray *btncon_POS_H=[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-100-[btnLogin]-100-|" options:0 metrics:nil views:viewsDictionary];
[self.view addConstraints:btncon_POS_H];


NSArray *btncon_POS_V=[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-70-[Title]-130-[lblFirst]-0-[lblSecond]-20-[textusername]-10-[txtpassword]-10-[btnLogin]" options:0 metrics:nil views:viewsDictionary];

[self.view addConstraints:btncon_POS_V];

Pero mi problema es que si bien administra la brecha lateral izquierda y derecha, se estira en el iPhone 6 y 6 Plus ya que la altura es fija. ¿Cómo puedo aumentar el tamaño de acuerdo con el tamaño de la pantalla? Creo que esta podría ser la relación de aspecto, pero ¿cómo puedo establecer la restricción de la relación de aspecto en el código?

IRD
fuente
2
Verifique esta respuesta: stackoverflow.com/a/12526630/3202193
Ashish Kakkad

Respuestas:

84

Me gusta esto. Trata una vez.

[self.yourview setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.yourview addConstraint:[NSLayoutConstraint
                                  constraintWithItem:self.yourview
                                  attribute:NSLayoutAttributeHeight
                                  relatedBy:NSLayoutRelationEqual
                                  toItem:self.yourview
                                  attribute:NSLayoutAttributeWidth
                                  multiplier:(self.yourview.frame.size.height / self.yourview.frame.size.width)
                                  constant:0]];

o en lugar de (self.yourview.frame.size.height / self.yourview.frame.size.width)puede usar cualquier valor flotante. Gracias.

Swift 3.0 -

self.yourview!.translatesAutoresizingMaskIntoConstraints = false
self.yourview!.addConstraint(NSLayoutConstraint(item: self.yourview!,
                                          attribute: NSLayoutAttribute.height,
                                          relatedBy: NSLayoutRelation.equal,
                                          toItem: self.yourview!,
                                          attribute: NSLayoutAttribute.width,
                                          multiplier: self.yourview.frame.size.height / self.yourview.frame.size.width,
                                          constant: 0))
Mahesh Agrawal
fuente
Me está dando este error Finalizando la aplicación debido a una excepción no detectada 'NSInternalInconsistencyException', razón: '¡El multiplicador no es finito! Eso es ilegal. multiplicador: nan '
IRD
2
significa en el escenario como si la altura es 100 y el ancho es 200 y le dio un multiplicador 0.5 con mi código, entonces si su altura aumentará a 150 al cambiar cualquier otra restricción, entonces el ancho aumentará automáticamente a 300. Pero para hacer esto, necesita para aumentar una restricción de la vista como ancho o alto.
Mahesh Agrawal
1
tomará altura: ancho = 1: 2 que es 0.5.
Mahesh Agrawal
3
No olvide agregar esta línea antes de establecer cualquier restricción mediante programación: [self.yourview setTranslatesAutoresizingMaskIntoConstraints:NO];
atulkhatri
1
Al usar restricciones, mis tamaños de marco eran todos cero. Para obtener la relación de aspecto, en cambio, utilicéself.yourview.intrinsicContentSize
Phlippie Bosman
88

Layout Anchors es la forma más conveniente de establecer restricciones mediante programación.

Supongamos que desea establecer una relación de aspecto de 5: 1 para su botón, entonces debe usar:

button.heightAnchor.constraint(equalTo: button.widthAnchor, multiplier: 1.0/5.0).isActive = true

Aquí está el código completo:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let button = UIButton(type: .custom)
        button.setTitle("Login", for: .normal)
        button.backgroundColor = UIColor.darkGray

        self.view.addSubview(button)

        button.translatesAutoresizingMaskIntoConstraints = false

        let margins = view.layoutMarginsGuide

        button.leadingAnchor.constraint(equalTo: margins.leadingAnchor, constant: 20.0).isActive = true
        button.trailingAnchor.constraint(equalTo: margins.trailingAnchor, constant: -20.0).isActive = true
        button.bottomAnchor.constraint(equalTo: margins.bottomAnchor, constant: -20.0).isActive = true
        button.heightAnchor.constraint(equalTo: button.widthAnchor, multiplier: 1.0/5.0).isActive = true
    }

}

Estos son los resultados obtenidos con el código escrito anteriormente. Puede ver que el botón mantiene su relación de aspecto de 5: 1 en varios dispositivos:

Vista de resultados

Eugene Brusov
fuente
14

Swift 3:

yourView.addConstraint(NSLayoutConstraint(item: yourView,
                                          attribute: .height,
                                          relatedBy: .equal,
                                          toItem: yourView,
                                          attribute: .width,
                                          multiplier: 9.0 / 16.0,
                                          constant: 0))
RNHTTR
fuente
1
Para iOS 8 y superior, debería utilizar la propiedad isActive de NSLayoutConstraint en lugar de llamar a addConstraint (:). aspectRatioConstraint.isActive = true
dvdblk
¿Por qué no lo usas .widthcomo primer atributo? El resultado es que attr2 * multiplier la relación de aspecto es width / height, por lo tanto width = height * aspectRatio, si ponemos el .heightal primer atributo y el aspectRatioal multiplier, el resultado es totalmente inverso.
Kimi Chiu
12

Puede establecer "Restricción de altura" en tiempo de diseño en Interface Builder. Simplemente marque "Eliminar en el momento de la compilación" y se eliminará cuando la aplicación se ejecute.

ingrese la descripción de la imagen aquí Después de eso, puede agregar la restricción "Relación de aspecto", por ejemplo, en el método viewDidLoad.

En Xamain.iOS para "16: 9" se ve así:

    this.ImageOfTheDay.AddConstraint(NSLayoutConstraint.Create(
            this.ImageOfTheDay,
            NSLayoutAttribute.Height,
            NSLayoutRelation.Equal,
            this.ImageOfTheDay,
            NSLayoutAttribute.Width,
            9.0f / 16.0f,
            0));

O, como dijo Mahesh Agrawal :

    [self.ImageOfTheDay addConstraint:[NSLayoutConstraint
                              constraintWithItem:self.ImageOfTheDay
                              attribute:NSLayoutAttributeHeight
                              relatedBy:NSLayoutRelationEqual
                              toItem:self.ImageOfTheDay
                              attribute:NSLayoutAttributeWidth
                              multiplier:(9.0f / 16.0f)
                              constant:0]];
Zanael
fuente
12

Extensión auxiliar en UIView

extension UIView {

    func aspectRation(_ ratio: CGFloat) -> NSLayoutConstraint {

        return NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: self, attribute: .width, multiplier: ratio, constant: 0)
    }
}

Y el uso es:

view.aspectRation(1.0/1.0).isActive = true

Michał Ziobro
fuente
y uso: view.aspectRation (1.0 / 1.0)
Michał Ziobro
1
De hecho, esta es una solución elegante que excluye un par de tipos: 1. El parámetro toItem se establece en en .selflugar de self2. Y el uso en el comentario debería ser view.aspectRation(1.0/1.0).isActive = true Probé esto en Xcode 10.2.1 Swift 5.
Pankaj Kulkarni
3

Probé todas las respuestas anteriores pero no funcionó, y esta es mi solución con Swift 3:

let newConstraint = NSLayoutConstraint(item: yourView, attribute: .width, relatedBy: .equal, toItem: yourView, attribute: .height, multiplier: 560.0/315.0, constant: 0)
yourView.addConstraint(newConstraint)
NSLayoutConstraint.activate([newConstraint])  
NSLayoutConstraint.deactivate(yourView.constraints)
yourView.layoutIfNeeded()
tuandapen
fuente
Siempre debe desactivar las restricciones (potencialmente conflictivas) antes de agregar nuevas para evitar errores de diseño automático
Juan
0

Para las vistas, hay restricciones y también propiedades.

la relación de aspecto es una propiedad de la vista , por lo que puede configurarla usando el modo de contenido, así

imageView.contentMode = .scaleAspectFit

esto logrará que una vista no cambie las proporciones si, por ejemplo

  • la altura o el ancho son mayores de lo que caben en la pantalla
  • la altura estaba codificada de forma rígida y, por lo tanto, no podrá adaptarse a diferentes tamaños de pantallas.
valeriana
fuente
La pregunta no es sobre ImageView y su modo de contenido, se trata de diseño automático y restricciones. Desde Interface Builder, puede establecer una restricción de relación de aspecto que al final crea una restricción de ancho a alto con un multiplicador.
Gunhan
@Gunhan la pregunta se relaciona con cómo configurarlo programáticamente. Por lo tanto, es bueno saberlo para poder configurarlo en el generador de interfaces, pero es irrelevante para esta pregunta.
valeriana
Creo que entendiste mal lo que dije antes. En esta pregunta, nadie habla de ImageView. TI se trata de diseño automático y restricciones, y debe hacerlo mediante programación. Lo que dije fue que cuando lo configuraste en el generador de interfaces, crea una restricción de ancho a alto. No te dije que lo crearas a través de IB. Para hacer lo mismo programáticamente, debes crearlo view.widthAnchor.constraint(equalTo: view.heightAnchor, multiplier: aspectRatio, constant: 0)así
Gunhan