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?


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

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


14

Swift 3:

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

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

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


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

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.

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.