Programowe tworzenie ograniczeń układu

84

Wiem, że wiele osób zadawało już mnóstwo pytań na ten temat, ale nawet z odpowiedziami nie mogę sprawić, by to zadziałało.

Kiedy mam do czynienia z ograniczeniami na storyboardzie, jest to łatwe, ale w kodzie jest mi ciężko. Na przykład staram się mieć widok, który pozostaje po prawej stronie i ma wysokość ekranu odpowiadającą orientacji ekranu. To jest mój kod:

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 748)];
myView.backgroundColor = [UIColor redColor];
[self.view addSubview:myView];
[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:0 metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

Nie spełnia pewnych ograniczeń. Nie wiem, co jest nie tak. Ponadto, dlaczego nie mogę użyć właściwości takiej jak self.myViewzamiast zmiennej lokalnej, takiej jak myView?

pierre23
źródło
Co to jest vivi w powyższym kodzie?
iDev
14
Zmień tytuł na „iOS” zamiast „IOS” - to drugie odnosi się do systemu operacyjnego przełączników / routerów firmy Cisco. Zdezorientował mnie. Dzięki.
armani
1
Kilka pytań na ten temat: (1) Jaki błąd otrzymujesz, gdy „nie spełnia pewnych ograniczeń”? (2) Czy tłumaczysz autorezację na ograniczenia myView? (3) Co vivi(zgodnie z pytaniem ACB)? (4) Czy masz myViewzadeklarowaną nieruchomość self?
Tim
1
ih Tim, przepraszam vivi, stuknąłem za szybko ... to myView. Co masz na myśli mówiąc o tłumaczeniu? Wszystko, co robię, robię na powyższym kodzie. Jeśli chodzi o właściwość, mam kilka innych widoków, które są zadeklarowane jako właściwość, ale kiedy implementuję ten sam kod do tej właściwości, następuje awaria ... komunikat „błąd” jest naprawdę duży, nie mogę go tutaj wkleić
pierre23
Aby tymczasowo usunąć ograniczenia z określonego widoku, zrób to stackoverflow.com/questions/13388104/…
Sam B

Odpowiedzi:

106

Podczas korzystania z automatycznego układu w kodzie ustawienie ramki nic nie daje. Tak więc fakt, że na powyższym widoku określono szerokość 200, nie ma żadnego znaczenia, gdy ustawisz na nim ograniczenia. Aby ograniczenie widoku było jednoznaczne, potrzebne są cztery rzeczy: pozycja x, pozycja y, szerokość i wysokość dla dowolnego stanu.

Obecnie w powyższym kodzie masz tylko dwa (wysokość w stosunku do superview i pozycja y w stosunku do superview). Oprócz tego masz dwa wymagane ograniczenia, które mogą kolidować w zależności od tego, jak są ustawione ograniczenia superview widoku. Jeśli superwiew miałby mieć wymagane ograniczenie, które określa, że ​​jego wysokość będzie mniejsza niż 748, otrzymasz wyjątek „niezaspokojone ograniczenia”.

Fakt, że ustawiłeś szerokość widoku przed ustawieniem ograniczeń, nic nie znaczy. Nie weźmie nawet pod uwagę starej klatki i obliczy nową klatkę na podstawie wszystkich ograniczeń określonych dla tych widoków. Kiedy mam do czynienia z autoukładem w kodzie, zazwyczaj po prostu tworzę nowy widok za pomocą initWithFrame:CGRectZerolub po prostu init.

Aby utworzyć zestaw ograniczeń wymagany dla układu, który ustnie opisałeś w swoim pytaniu, musisz dodać pewne ograniczenia poziome, aby ograniczyć szerokość i pozycję x, aby uzyskać w pełni określony układ:

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
    constraintsWithVisualFormat:@"H:[myView(==200)]-|"
    options:NSLayoutFormatDirectionLeadingToTrailing
    metrics:nil
    views:NSDictionaryOfVariableBindings(myView)]];

Werbalny opis tego układu brzmi następująco, zaczynając od ograniczenia pionowego:

myView wypełni wysokość swojego superviewu dopełnieniem górnym i dolnym równym przestrzeni standardowej. Nadzór myView ma minimalną wysokość 748 punktów. Szerokość myView wynosi 200 punktów i ma prawe wypełnienie równe standardowej przestrzeni względem jego superview.

Jeśli chciałbyś po prostu, aby widok wypełniał całą wysokość nadzoru bez ograniczania wysokości nadzoru, to po prostu pominiesz (>=748)parametr w tekście formatu wizualnego. Jeśli myślisz, że (>=748)parametr jest wymagany do nadania mu wysokości - w tym przypadku tego nie robisz: przypinając widok do krawędzi superwiewu za pomocą składni bar ( |) lub bar ze spacją ( |-, -|), dajesz swojemu widokowi y -pozycja (przypinanie widoku na jednej krawędzi) i pozycja y z wysokością (przypinanie widoku na obu krawędziach), spełniając w ten sposób ograniczenie ustawione dla widoku.

Jeśli chodzi o drugie pytanie:

Używając NSDictionaryOfVariableBindings(self.myView)(jeśli masz ustawioną właściwość dla myView) i wprowadzając ją do swojego VFL w celu użycia self.myVieww tekście VFL, prawdopodobnie otrzymasz wyjątek, gdy autolayout spróbuje przeanalizować twój tekst VFL. Ma to związek z notacją kropkową w kluczach słownika i systemem próbującym użyć valueForKeyPath:. Zobacz tutaj podobne pytanie i odpowiedź .

larsacus
źródło
Nie zapominaj, że niektóre obiekty, takie jak UILabel, mają wewnętrzny rozmiar i nie musisz ustawiać szerokości ani wysokości tego obiektu, tylko jego położenie. Jeśli jednak ustawisz wysokość lub szerokość, uważam, że usunie to jedno i drugie, a następnie musisz podać oba.
Nick Turner,
Chociaż ta odpowiedź nie odpowiedziała na moje pytanie, pomogła mi coś zrozumieć. Dzięki że jesteś! :)
Matej
1
Jak dotąd jedyne zwięzłe i czytelne wprowadzenie do układu automatycznego w Internecie.
Joey Carson
proszę pomóż mi moje pytanie jest takie ... Nie wiem, jak programowo używać ograniczeń stackoverflow.com/questions/36326288/ ...
61

Cześć, często korzystam z tej strony ze względu na ograniczenia i „jak to zrobić”. Zajęło mi wieczność, zanim zdałem sobie sprawę, że potrzebowałem:

myView.translatesAutoresizingMaskIntoConstraints = NO;

aby ten przykład zadziałał. Dziękuję Userxxx, Rob M., a zwłaszcza larsacus za wyjaśnienie i kod, to było bezcenne.

Oto pełny kod, aby uruchomić powyższe przykłady:

UIView *myView = [[UIView alloc] init];
myView.backgroundColor = [UIColor redColor];
myView.translatesAutoresizingMaskIntoConstraints = NO;  //This part hung me up 
[self.view addSubview:myView];
//needed to make smaller for iPhone 4 dev here, so >=200 instead of 748
[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"V:|-[myView(>=200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];

[self.view addConstraints:[NSLayoutConstraint
                           constraintsWithVisualFormat:@"H:[myView(==200)]-|"
                           options:NSLayoutFormatDirectionLeadingToTrailing
                           metrics:nil
                           views:NSDictionaryOfVariableBindings(myView)]];
BriOnH
źródło
11

Szybka wersja

Zaktualizowano dla Swift 3

Ten przykład pokaże dwie metody programowego dodawania następujących ograniczeń, tak samo jak w przypadku robienia tego w programie Interface Builder:

Szerokość i wysokość

wprowadź opis obrazu tutaj

Centrum w pojemniku

wprowadź opis obrazu tutaj

Kod na płycie kotła

override func viewDidLoad() {
    super.viewDidLoad()

    // set up the view
    let myView = UIView()
    myView.backgroundColor = UIColor.blue
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)

    // Add constraints code here (choose one of the methods below)
    // ...
}

Metoda 1: Styl zakotwiczenia

// width and height
myView.widthAnchor.constraint(equalToConstant: 200).isActive = true
myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

// center in container
myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true

Metoda 2: styl NSLayoutConstraint

// width and height
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 200).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.height, relatedBy: NSLayoutRelation.equal, toItem: nil, attribute: NSLayoutAttribute.notAnAttribute, multiplier: 1, constant: 100).isActive = true

// center in container
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: myView, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: view, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0).isActive = true

Uwagi

  • Styl kotwicy jest preferowaną metodą zamiast NSLayoutConstraintstylu, jednak jest dostępny tylko w systemie iOS 9, więc jeśli obsługujesz iOS 8, nadal powinieneś używać NSLayoutConstraintstylu.
  • Zobacz także dokumentację Programowe tworzenie ograniczeń .
  • Zobacz tę odpowiedź, aby zapoznać się z podobnym przykładem dodawania wiązania kołkowego.
Suragch
źródło
5

Jeśli chodzi o drugie pytanie dotyczące właściwości, możesz użyć self.myViewtylko wtedy, gdy zadeklarowałeś je jako właściwość w klasie. Ponieważ myViewjest to zmienna lokalna, nie możesz jej używać w ten sposób. Aby uzyskać więcej informacji na ten temat, polecam zapoznać się z dokumentacją Apple dotyczącą deklarowanych właściwości ,

iDev
źródło
5

dlaczego nie mogę użyć właściwości takiej jak self.myViewzamiast zmiennej lokalnej, takiej jak myView?

spróbuj użyć:

NSDictionaryOfVariableBindings(_view)

zamiast self.view

Megarushing
źródło
To powoduje awarię mojej aplikacji i wyświetla komunikat: „Nie można przeanalizować formatu ograniczenia: polylineImageView nie jest kluczem w słowniku widoków”.
Tai Le,
4

Należy również zauważyć, że od iOS9 możemy programowo definiować ograniczenia „bardziej zwięzłe i łatwiejsze do odczytania” za pomocą podklas nowej klasy pomocniczej NSLayoutAnchor .

Przykład z dokumentu:

[self.cancelButton.leadingAnchor constraintEqualToAnchor:self.saveButton.trailingAnchor constant: 8.0].active = true;
andreacipriani
źródło