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ą:

  1. komórki o niestandardowym stylu i
  2. 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:

Stolik na iPhone

IPad (with TableView width = 1/2 rozmiaru ekranu)

Stolik na iPada

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.

Author: Community, 2014-12-11

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

  1. wybierz komórkę content view in IB
  2. przejdź do Inspektora rozmiaru
  3. W sekcji marginesy układu zaznacz opcję Zachowaj marginesy superwizora (nie klikaj znaku plus)

    Sprawdzanie zachowania marginesów

  4. (i tu jest klucz) zrób to samo dla samej komórki (rodzic widoku zawartości, jeśli chcesz)

    Tym razem widok komórki, a nie zawartości

  5. Ustaw ograniczenia w następujący sposób: Label.Leading = Superview.Marża wiodąca (z stała 0)

    Ustawianie ograniczenia etykiety niestandardowej komórki

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.

Wynik końcowy w symulatorze

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.

 134
Author: Jonas Zaugg,
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

 6
Author: tubtub,
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()
}
 4
Author: Dan Loewenherz,
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:

  1. w obrysie dokumentu wybierz "Widok zawartości" dla komórki z niestandardowy styl.
  2. Przejdź do Inspektora wielkości.
  3. w menu rozwijanym "marginesy układu" naciśnij mały symbol plusa obok "Zachowaj marginesy Superview."
  4. Wybierz klasę rozmiaru iPada, która jest " regularna szerokość x regularna wysokość."
  5. Zaznacz pole wyboru obok "Zachowaj Superview Marginesy."
  6. 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ż.

 1
Author: Becky Hansmeyer,
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ć!

 0
Author: diyaddict,
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