Come posso impostare i vincoli delle proporzioni a livello di codice in iOS?


85

Ho usato il layout automatico per i miei controller di visualizzazione. Ho impostato le posizioni V e H nei vincoli, ma voglio sapere come posso aumentare la dimensione del mio pulsante quando cambia in 5s, 6 e 6 Plus. Questo è il modo in cui ho aggiunto i vincoli per il pulsante di accesso:

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];

Ma il mio problema è che mentre gestisce lo spazio tra i lati sinistro e destro, viene allungato in iPhone 6 e 6 Plus poiché l'altezza è fissa. Come posso aumentare le dimensioni in base alle dimensioni dello schermo? Penso che questo potrebbe essere il rapporto di aspetto, ma come posso impostare il vincolo del rapporto di aspetto nel codice?


2
Controllare questa risposta: stackoverflow.com/a/12526630/3202193
Ashish Kakkad

Risposte:


84

Come questo. Prova una volta.

[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 al posto di (self.yourview.frame.size.height / self.yourview.frame.size.width)puoi usare qualsiasi valore float. Grazie.

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))

Mi dà questo errore Terminare l'app a causa di un'eccezione non rilevata "NSInternalInconsistencyException", motivo: "Il moltiplicatore non è finito! È illegale. moltiplicatore: nan '
IRD

2
significa che nello scenario come se l'altezza è 100 e la larghezza è 200 e hai dato il moltiplicatore 0,5 con il mio codice, quindi se la tua altezza aumenterà a 150 modificando qualsiasi altro vincolo, la larghezza aumenterà automaticamente a 300. Ma per fare questo è necessario per aumentare un vincolo della vista come larghezza o altezza.
Mahesh Agrawal

1
ci vorrà altezza: larghezza = 1: 2 che è 0,5.
Mahesh Agrawal

3
Non dimenticare di aggiungere questa riga prima di impostare programmaticamente qualsiasi vincolo: [self.yourview setTranslatesAutoresizingMaskIntoConstraints:NO];
atulkhatri

1
Quando si utilizzano i vincoli, le dimensioni del telaio erano tutte pari a zero. Per ottenere le proporzioni, invece, ho usatoself.yourview.intrinsicContentSize
Phlippie Bosman

89

Layout Anchors è il modo più conveniente per impostare vincoli a livello di codice.

Supponi di voler impostare le proporzioni 5: 1 per il tuo pulsante, quindi dovresti usare:

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

Ecco il codice 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
    }

}

Ecco i risultati ottenuti con il codice scritto sopra. Puoi vedere che il pulsante mantiene le sue proporzioni 5: 1 su vari dispositivi:

Visualizzazione dei risultati


14

Swift 3:

yourView.addConstraint(NSLayoutConstraint(item: yourView,
                                          attribute: .height,
                                          relatedBy: .equal,
                                          toItem: yourView,
                                          attribute: .width,
                                          multiplier: 9.0 / 16.0,
                                          constant: 0))

1
Per iOS 8 e versioni successive dovresti usare la proprietà isActive di NSLayoutConstraint invece di chiamare addConstraint (:). aspectRatioConstraint.isActive = true
dvdblk

Perché non usi .widthcome primo attributo? Il risultato è che attr2 * multiplier le proporzioni sono width / height, quindi width = height * aspectRatio, se mettiamo il .heightal primo attributo e il aspectRatioal, multiplieril risultato è totalmente invertito.
Kimi Chiu

13

È possibile impostare "Vincolo di altezza" in fase di progettazione in Interface Builder. Seleziona "Rimuovi in ​​fase di compilazione" e rimuove quando l'app sarà in esecuzione.

inserisci qui la descrizione dell'immagine Dopodiché puoi aggiungere il vincolo "Aspect Ratio", ad esempio, nel metodo viewDidLoad.

In Xamain.iOS per "16: 9" è simile a questo:

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

Oppure, come ha detto 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]];

12

Estensione helper su UIView

extension UIView {

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

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

E l'utilizzo è:

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


e utilizzo: view.aspectRation (1.0 / 1.0)
Michał Ziobro

1
Questa è davvero una soluzione elegante che esclude un paio di tipi: 1. Il parametro toItem è impostato su .selfinvece di self2. E l'uso nel commento dovrebbe essere l' view.aspectRation(1.0/1.0).isActive = true ho testato in Xcode 10.2.1 Swift 5.
Pankaj Kulkarni

3

Ho provato tutte le risposte sopra ma non ha funzionato, e questa è la mia soluzione 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()

Dovresti sempre disattivare i vincoli (potenzialmente in conflitto) prima di aggiungerne di nuovi per evitare errori di layout automatico
John

0

Per le viste, ci sono vincoli e ci sono anche proprietà.

le proporzioni sono una proprietà della vista , quindi puoi impostarle utilizzando la modalità contenuto, in questo modo

imageView.contentMode = .scaleAspectFit

questo farà sì che una vista non cambi i rapporti se, ad esempio

  • l'altezza o la larghezza sono maggiori di quelle che si adattano allo schermo
  • l'altezza è stata hardcoded e quindi non sarà in grado di adattarsi a schermi di diverse dimensioni.

La domanda non riguarda ImageView e la sua modalità di contenuto, ma il layout automatico e i vincoli. Dall'Interface Builder, puoi impostare il vincolo delle proporzioni che alla fine crea un vincolo da larghezza ad altezza con un moltiplicatore.
Gunhan

@Gunhan la domanda riguarda come impostarlo a livello di programmazione. Quindi essere in grado di impostarlo in Interface Builder è bello da sapere, ma irrilevante per questa domanda.
valeriana

Penso che tu abbia frainteso quello che ho detto prima. In questa domanda, nessuno parla di ImageView. Si tratta di layout e vincoli automatici e devono essere programmati. Quello che ho detto è che quando lo imposti in Interface Builder, crea un vincolo da larghezza ad altezza. Non ti ho detto di crearlo tramite IB. Per fare la stessa cosa in modo programmatico, devi crearlo in questo view.widthAnchor.constraint(equalTo: view.heightAnchor, multiplier: aspectRatio, constant: 0)modo
Gunhan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.