Jak programowo ustawić ograniczenia współczynnika proporcji w systemie iOS?

85

Użyłem automatycznego układu moich kontrolerów widoku. Ustawiłem pozycje V i H w ograniczeniach, ale chcę wiedzieć, jak mogę zwiększyć rozmiar mojego przycisku, gdy zmieni się na 5s, 6 i 6 Plus. W ten sposób dodałem ograniczenia dla przycisku logowania:

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

Ale moim problemem jest to, że podczas gdy zarządza lewą i prawą szczeliną boczną, w iPhone 6 i 6 Plus jest rozciągany, ponieważ wysokość jest stała. Jak mogę zwiększyć rozmiar w zależności od rozmiaru ekranu? Myślę, że to może być współczynnik proporcji, ale jak mogę ustawić ograniczenie proporcji w kodzie?

IRD
źródło
2
Sprawdź tę odpowiedź: stackoverflow.com/a/12526630/3202193
Ashish Kakkad

Odpowiedzi:

84

Lubię to. Spróbuj raz.

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

lub zamiast (self.yourview.frame.size.height / self.yourview.frame.size.width)ciebie możesz użyć dowolnej wartości typu float. Dzięki.

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
źródło
Wyświetla mi ten błąd Zamykanie aplikacji z powodu nieprzechwyconego wyjątku „NSInternalInconsistencyException”, powód: „Mnożnik nie jest skończony! To jest nielegalne. mnożnik: nan '
IRD
2
oznacza to, że w scenariuszu takim jak wysokość 100 i szerokość 200 i podałeś mnożnik 0.5 z moim kodem, to jeśli twoja wysokość wzrośnie do 150 zmieniając jakiekolwiek inne ograniczenie, szerokość automatycznie wzrośnie do 300. Ale aby to zrobić, potrzebujesz aby zwiększyć jedno ograniczenie widoku, takie jak szerokość lub wysokość.
Mahesh Agrawal
1
zajmie wysokość: szerokość = 1: 2, czyli 0,5.
Mahesh Agrawal
3
Nie zapomnij dodać tego wiersza przed programowym ustawieniem ograniczeń: [self.yourview setTranslatesAutoresizingMaskIntoConstraints:NO];
atulkhatri
1
Podczas korzystania z ograniczeń wszystkie moje rozmiary ramek wynosiły zero. Aby uzyskać współczynnik proporcji, użyłemself.yourview.intrinsicContentSize
Phlippie Bosman,
88

Zakotwiczenia układu to najwygodniejszy sposób programowego ustawiania ograniczeń.

Powiedzmy, że chcesz ustawić współczynnik proporcji 5: 1 dla swojego przycisku, a następnie użyj:

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

Oto pełny kod:

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
    }

}

Oto wyniki uzyskane przy użyciu kodu napisanego powyżej. Możesz zobaczyć, że przycisk zachowuje proporcje 5: 1 na różnych urządzeniach:

Widok wyniku

Eugene Brusov
źródło
14

Swift 3:

yourView.addConstraint(NSLayoutConstraint(item: yourView,
                                          attribute: .height,
                                          relatedBy: .equal,
                                          toItem: yourView,
                                          attribute: .width,
                                          multiplier: 9.0 / 16.0,
                                          constant: 0))
RNHTTR
źródło
1
W przypadku systemu iOS 8 i nowszych należy używać właściwości isActive z NSLayoutConstraint zamiast wywoływać addConstraint (:). aspectRatioConstraint.isActive = true
dvdblk
Dlaczego nie używasz .widthjako pierwszego atrybutu? Wynik jest taki attr2 * multiplier , że współczynnik proporcji to width / height, więc width = height * aspectRatiojeśli umieścimy .heightatrybut na pierwszym atrybucie, a aspectRationa multiplierdrugim, wynik jest całkowicie odwrócony.
Kimi Chiu
12

Możesz ustawić „Ograniczenie wysokości” w czasie projektowania w programie Interface Builder. Po prostu zaznacz „Usuń w czasie kompilacji”, a zostanie ona usunięta, gdy aplikacja będzie działać.

wprowadź opis obrazu tutaj Następnie możesz dodać ograniczenie „Aspect Ratio”, na przykład w metodzie viewDidLoad.

W Xamain.iOS dla „16: 9” wygląda to tak:

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

Lub, jak powiedział 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
źródło
12

Rozszerzenie pomocnika na UIView

extension UIView {

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

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

A użycie to:

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

Michał Ziobro
źródło
i użycie: view.aspectRation (1.0 / 1.0)
Michał Ziobro
1
Jest to rzeczywiście eleganckie rozwiązanie wykluczające kilka typów: 1. Parametr toItem jest ustawiony na .selfzamiast self2. A użycie w komentarzu powinno być view.aspectRation(1.0/1.0).isActive = true przetestowane w Xcode 10.2.1 Swift 5.
Pankaj Kulkarni
3

Wypróbowałem wszystkie powyższe odpowiedzi, ale nie zadziałało, a to jest moje rozwiązanie ze 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
źródło
Zawsze powinieneś dezaktywować (potencjalnie kolidujące) ograniczenia przed dodaniem nowych, aby uniknąć błędów autoukładu
John
0

W przypadku widoków istnieją ograniczenia, a także właściwości.

proporcje są właściwością widoku , więc można je ustawić w trybie zawartości, jak na przykład

imageView.contentMode = .scaleAspectFit

dzięki temu widok nie zmieni współczynników, jeśli na przykład

  • wysokość lub szerokość są większe niż zmieści się na ekranie
  • wysokość została zakodowana na stałe i dlatego nie będzie w stanie dostosować się do różnych rozmiarów ekranów.
valeriana
źródło
Pytanie nie dotyczy ImageView i jego trybu zawartości, chodzi o automatyczny układ i ograniczenia. W Interface Builder można ustawić ograniczenie proporcji, które na końcu tworzy ograniczenie szerokości do wysokości za pomocą mnożnika.
Gunhan
@Gunhan pytanie dotyczy tego, jak ustawić to programowo. Więc możliwość ustawienia go w konstruktorze interfejsów jest miło wiedzieć, ale nie ma to związku z tym pytaniem.
Valeriana
Myślę, że źle zrozumiałeś to, co powiedziałem wcześniej. W tym pytaniu nikt nie mówi o ImageView. IT dotyczy automatycznego układu i ograniczeń, i musi zrobić to programowo. Powiedziałem, że kiedy ustawiasz go w konstruktorze interfejsów, tworzy ograniczenie szerokości do wysokości. Nie mówiłem ci, żebyś stworzył to przez IB. Aby zrobić to samo programowo, musisz stworzyć to w ten view.widthAnchor.constraint(equalTo: view.heightAnchor, multiplier: aspectRatio, constant: 0)sposób
Gunhan