UITableViewCell z autolayout lewy margines inny na iPhone i iPad
Używam zgrupowanego UITableView
ze statycznymi komórkami dla ekranu opcji/sceny. Wszystko odbywa się w Xcode 6.1 / iOS 8.1.x / Storyboard przy użyciu Autolayout. W obrębie grup tabel występują mieszane typy komórek i istnieją dwa typy, które powodują problemy ze mną:
- komórki o niestandardowym stylu i
- komórki ze stylem "Right Detail"
W komórce # 1 Mogę ustawić ograniczenie dla lewego marginesu między etykietą a wiodącym kontenerem. Na komórce # 2 nie mogę ustawić żadnego ograniczenia w Interface Builder z tego co wiem. Ustawiłem lewy margines na etykiecie w komórce # 1, aby wyrównał się z etykietą w komórce # 2. Wszystko wygląda dobrze na iPhonie, ale jeśli pokażę tę samą tabelę na iPadzie, gdzie Rozmiar kontenera widoku tabeli jest o połowę mniejszy niż rozmiar ekranu, komórka #2 otrzymuje większy margines (dynamicznie?) podczas gdy komórka # 1 utrzymuje absolutny margines, który ustawiłem w ograniczeniach. Próbowałem też zmienić lewy margines w komórce # 1 z atrybutem "related to margin" ale na no / align = "left" /
IPhone:
IPad (with TableView width = 1/2 rozmiaru ekranu)
Pytanie brzmi: jak ustawić ograniczenia dla etykiety w komórce # 1, aby wyrównała się tak, jak komórka #2.
Tutaj jest również link do przykładowego projektu Xcode 6.1 demonstrującego problem. Uruchom na iPhonie i iPadzie, aby zobaczyć różnicę:
Https://dl.dropboxusercontent.com/u/5252156/Code/tableViewTest.zip
To pytanie może być związane z układ statycznej komórki tabeli dla iPhone ' a i iPada, ale może się również różnić w przypadku iOS 8, ponieważ wszystko ma być teraz adaptacyjne. Dlatego i tak postanowiłem zamieścić to pytanie.
5 answers
Jak to naprawić
Po walce z zespołem raportowania błędów apple z wieloma przykładowymi projektami i zrzutami ekranu i rozcięciem odpowiedzi , odkryłem, że rozwiązanie, aby twoje komórki w niestandardowym stylu zachowywały się konsekwentnie w odniesieniu do ich marginesów i były takie same jak domyślne UITableViewCells, musisz wykonać następujące czynności (głównie w oparciu o odpowiedź Becky , podkreśliłem, co jest INNE i co sprawiło, że działa dla mnie):
- wybierz komórkę content view in IB
- przejdź do Inspektora rozmiaru
-
W sekcji marginesy układu zaznacz opcję Zachowaj marginesy superwizora (nie klikaj znaku plus)
-
(i tu jest klucz) zrób to samo dla samej komórki (rodzic widoku zawartości, jeśli chcesz)
-
Ustaw ograniczenia w następujący sposób: Label.Leading = Superview.Marża wiodąca (z stała 0)
Teraz wszystkie twoje komórki będą miały Etykietę zgodną z domyślnymi komórkami! To działa dla mnie w Xcode 7 i w górę i zawiera poprawki wymienione w wątku, o którym mówiłem. IB i symulator powinny teraz wyświetlać prawidłowo wyrównane etykiety.
Możesz również wykonać część tego programowo, na przykład w klasie kontrolera widoku:
cell.preservesSuperviewLayoutMargins = true
cell.contentView.preservesSuperviewLayoutMargins = true
Albo można go ustawić przez wywołanie UIAppearance raz przy starcie (znam tylko Swift, sorry):
UITableViewCell.appearance().preservesSuperviewLayoutMargins = true
UITableViewCell.appearance().contentView.preservesSuperviewLayoutMargins = true
Jak i dlaczego to działa
Jak[66]} Ethan uprzejmie zauważył, własna dokumentacja Apple na UIView opisuje preservesSuperviewLayoutMargins
następująco:
Gdy wartość tej właściwości wynosi
true
, marginesy superview są również brane pod uwagę przy układaniu zawartości. Margines ten ma wpływ na układy, w których odległość między krawędzią widoku a jego superwizorem jest mniejsza niż odpowiadający mu margines. Na przykład możesz mieć widok zawartości, którego ramka dokładnie pasuje do granic superview. Jeśli którykolwiek z marginesów superview znajduje się wewnątrz obszaru reprezentowanego przez Widok zawartości i jego własne marginesy, UIKit dostosowuje układ widoku zawartości tak, aby respektował marginesy superview. Kwota korekty jest najmniejszą ilością potrzebną do zapewnienia, że zawartość znajduje się również wewnątrz marginesów superview.
Dlatego, jeśli chcesz, aby zawartość Twojej komórki była zgodna z marginesy TableView ' a (jeśli chcesz), musisz mieć dwa marginesy Twojej zawartości, Content View i samą komórkę tabeli, zachowaj marginesy własnego superview.
Dlaczego nie jest to domyślne zachowanie zaskakuje mnie : czuję, że większość programistów, którzy nie chcą dostosowywać wszystkiego, spodziewałaby się tego" dziedziczenia " domyślnie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:24
Wpadłem w ten sam problem co ty i znalazłem rozwiązanie.
Po pierwsze, trochę tła: od iOS 8 domyślne komórki widoku tabeli respektują layoutMargins
komórki, aby dostosować się do różnych cech (aka ekrany aka urządzenia). Na przykład marginesy układu na wszystkich iPhone ' ach (z wyjątkiem iPhone 6 Plus, gdy są wyświetlane w arkuszu formularza) wynoszą {8, 16, 8, 16}
. Na iPadzie są {8, 20, 8, 20}
. Teraz wiemy, że różnica w pikselach wynosi 4, co najprawdopodobniej nie respektuje twoja niestandardowa komórka widoku tabeli.
Twój widok tabeli podklasa komórek musi dostosować ograniczenie lewego marginesu, gdy zmiana layoutMargins.
Oto odpowiedni fragment kodu:
- (void)layoutMarginsDidChange
{
[super layoutMarginsDidChange];
self.leftLayoutMarginConstraint.constant = self.layoutMargins.left;
self.rightLayoutMarginConstraint.constant = self.layoutMargins.right;
}
Dostosowanie do marginesów układu w kodzie umożliwia uzyskanie zawsze odpowiedniego wypełnienia dla etykiety tytułowej.
Możesz również spojrzeć na jedną z moich podklas UITableViewCell, które już szanują layoutMargins: https://github.com/bhr/BHRExtensions/blob/master/BHRExtensions/Utilities/BHRTitleAndValueTableCell.m
Cheers
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-05 11:27:25
Po zapoznaniu się z istniejącymi odpowiedziami i nie znalezieniu oczywistego rozwiązania programistycznego, trochę poszperałem i teraz mam dobrą odpowiedź dla każdego, kto ma do czynienia z tym problemem.
Po pierwsze, nie jest konieczne ustawianie preservesSuperviewLayoutMargins
do widoku zawartości komórki jako inne odpowiedzi Chociaż domyślną wartością jest false
, zmiana jej na true
nie miała zauważalnego efektu, który mogłem zobaczyć.
Kluczem do tego, aby to faktycznie działało jest właściwość layoutMarginsGuide
na UIView
. Używając tej wartości, możemy po prostu łatwo przypiąć leadingAnchor
dowolnego subview do leadingAnchor
przewodnika. Oto, jak to wygląda w kodzie (i może być bardzo dobrze to, co IB robi za kulisami, jak w odpowiedź Jonasa).
W podklasie UITableViewCell
zrobiłbyś coś takiego:
override func updateConstraints() {
let margins = contentView.layoutMarginsGuide
let leading = margins.leadingAnchor
subview1.leadingAnchor.constraintEqualToAnchor(leading).active = true
subview2.leadingAnchor.constraintEqualToAnchor(leading).active = true
super.updateConstraints()
}
Swift 4.1 update
override func updateConstraints() {
let margins = contentView.layoutMarginsGuide
let leading = margins.leadingAnchor
subview1.leadingAnchor.constraint(equalTo: leading).isActive = true
subview2.leadingAnchor.constraint(equalTo: leading).isActive = true
super.updateConstraints()
}
To wszystko! Jeśli tworzysz dla wersji iOS pre-iOS 9, musisz zastąpić kotwice układu i użyć wstawki layoutMargins
zamiast tego.
Uwaga: napisałem bibliotekę, aby upiększyć kotwicę, jeśli wolisz czystszą składnię. Nazywa się SuperLayout i jest dostępny na Cocoapods. Na górze pliku źródłowego Importuj SuperLayout
:
import SuperLayout
A następnie w bloku układu użyj ~~
, ≤≤
, i ≥≥
do przypięcia:
override func updateConstraints() {
let margins = contentView.layoutMarginsGuide
subview1.leadingAnchor ~~ margins.leadingAnchor
subview2.leadingAnchor ~~ margins.leadingAnchor
super.updateConstraints()
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-09 12:33:11
Udało mi się uzyskać komórki z niestandardowymi stylami wyrównanymi ze standardowymi komórkami, wykonując następujące czynności:
- w obrysie dokumentu wybierz "Widok zawartości" dla komórki z niestandardowy styl.
- Przejdź do Inspektora wielkości.
- w menu rozwijanym "marginesy układu" naciśnij mały symbol plusa obok "Zachowaj marginesy Superview."
- Wybierz klasę rozmiaru iPada, która jest " regularna szerokość x regularna wysokość."
- Zaznacz pole wyboru obok "Zachowaj Superview Marginesy."
- Rozwiąż wszelkie ostrzeżenia o automatycznym układzie poprzez aktualizację ramek.
To działało dla mnie w Xcode 7; mam nadzieję, że będzie działać w Xcode 6, jak również.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-22 22:19:46
Miałem ten problem podczas testowania na iPadzie Air, OS 10.1.1. Nagłówki tabeli były wcięte znacznie dalej, niż powinny być, a było jeszcze gorzej w orientacji poziomej. Ale były w porządku na iPhone ' ach do OS 11.
Zaskakującym rozwiązaniem była następująca linijka kodu, tuż po utworzeniu tabeli (Przepraszam, pracuję tylko w C#, ale łatwo jest wypracować odpowiedniki Obj-C i Swift):
myTableView.SeparatorInset = myTableView.SeparatorInset;
Wtedy wszystko było wcięte tak, jak powinno być!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-26 11:17:22