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.myView
zamiast zmiennej lokalnej, takiej jak myView
?
objective-c
ios
constraints
autolayout
pierre23
źródło
źródło
myView
? (3) Covivi
(zgodnie z pytaniem ACB)? (4) Czy maszmyView
zadeklarowaną nieruchomośćself
?Odpowiedzi:
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:CGRectZero
lub po prostuinit
.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:
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życiaself.myView
w 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ź .źródło
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)]];
źródło
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ść
Centrum w pojemniku
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
NSLayoutConstraint
stylu, jednak jest dostępny tylko w systemie iOS 9, więc jeśli obsługujesz iOS 8, nadal powinieneś używaćNSLayoutConstraint
stylu.źródło
Jeśli chodzi o drugie pytanie dotyczące właściwości, możesz użyć
self.myView
tylko wtedy, gdy zadeklarowałeś je jako właściwość w klasie. PonieważmyView
jest 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 ,źródło
dlaczego nie mogę użyć właściwości takiej jak
self.myView
zamiast zmiennej lokalnej, takiej jak myView?spróbuj użyć:
NSDictionaryOfVariableBindings(_view)
zamiast
self.view
źródło
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;
źródło