W jaki sposób korzystasz z automatycznego układu w obrębie UITableViewCell
s w widoku tabeli, aby zawartość i widoki podrzędne każdej komórki określały wysokość wiersza (sama / automatycznie), zachowując płynne przewijanie?
ios
uitableview
autolayout
nsautolayout
row-height
Smileyborg
źródło
źródło
contentSize
i jakpreferredMaxLayoutWidth
pracować. Zobacz tutaj . Biorąc to pod uwagę, jeśli poprawnie skonfigurujesz swoje ograniczenia, nie powinieneś ich potrzebować,preferredMaxLayoutWidth
aw rzeczywistości może stworzyć nieoczekiwane wyniki.Odpowiedzi:
TL; DR: Nie lubisz czytać? Przejdź bezpośrednio do przykładowych projektów na GitHub:
Opis koncepcyjny
Pierwsze 2 kroki poniżej mają zastosowanie niezależnie od tego, dla których wersji iOS opracowujesz.
1. Skonfiguruj i dodaj ograniczenia
W swojej
UITableViewCell
podklasy, dodać ograniczenia tak, że subviews ogniwa mają swoje krawędzie przypięte do krawędzi komórki contentView (najważniejsze na górnej i dolnej krawędzi). UWAGA: nie przypinaj widoków podrzędnych do samej komórki; tylko do komórkicontentView
! Pozwól, aby rzeczywisty rozmiar zawartości tych widoków podrzędnych sterował wysokością widoku zawartości komórki widoku tabeli, upewniając się, że odporność na kompresję treści i ograniczenia przytulania treści w wymiarze pionowym dla każdego widoku podrzędnego nie są zastępowane przez dodane ograniczenia o wyższym priorytecie. ( Huh? Kliknij tutaj. )Pamiętaj, że pomysł polega na tym, aby widoki podrzędne komórki były połączone pionowo z widokiem zawartości komórki, aby mogły one „wywierać presję” i sprawić, że widok zawartości rozszerzy się, aby je dopasować. Korzystając z przykładowej komórki z kilkoma podstronami, oto wizualna ilustracja tego, jak powinny wyglądać niektóre (nie wszystkie!) Ograniczenia:
Można sobie wyobrazić, że w miarę dodawania większej ilości tekstu do wieloliniowej etykiety ciała w powyższej przykładowej komórce, będzie on musiał rosnąć pionowo, aby dopasować się do tekstu, co skutecznie wymusi wzrost komórki. (Oczywiście, musisz poprawnie dopasować ograniczenia, aby działało to poprawnie!)
Poprawienie ograniczeń jest zdecydowanie najtrudniejszą i najważniejszą częścią uzyskania dynamicznych wysokości komórek podczas pracy z Auto Layout. Jeśli popełnisz tutaj błąd, może to uniemożliwić działanie całej reszty - nie spiesz się! Zalecam skonfigurowanie ograniczeń w kodzie, ponieważ dokładnie wiesz, które ograniczenia są dodawane gdzieś, i łatwiej jest debugować, gdy coś pójdzie nie tak. Dodanie ograniczeń w kodzie może być tak samo łatwe i znacznie potężniejsze niż narzędzie do tworzenia interfejsów za pomocą kotwic układu lub jednego z fantastycznych interfejsów API typu open source dostępnych w GitHub.
updateConstraints
metody podklasy UITableViewCell. Należy pamiętać, żeupdateConstraints
można go wywołać więcej niż jeden raz, więc aby uniknąć dodawania tych samych ograniczeń więcej niż jeden raz, należy zawinąć kod dodający ograniczeniaupdateConstraints
w celu sprawdzenia właściwości boolowskiej, takiej jakdidSetupConstraints
(która została ustawiona na TAK po uruchomieniu ograniczenia -dodanie kodu raz). Z drugiej strony, jeśli masz kod, który aktualizuje istniejące ograniczenia (np. Dostosowującconstant
właściwość w przypadku niektórych ograniczeń), umieść to w miejscu,updateConstraints
ale poza sprawdzaniem,didSetupConstraints
aby można go było uruchomić za każdym razem, gdy wywoływana jest metoda.2. Określ unikalne identyfikatory ponownego wykorzystania komórki w widoku tabeli
Dla każdego unikalnego zestawu ograniczeń w komórce użyj unikalnego identyfikatora ponownego użycia komórki. Innymi słowy, jeśli twoje komórki mają więcej niż jeden unikalny układ, każdy unikalny układ powinien otrzymać swój własny identyfikator ponownego wykorzystania. (Dobra wskazówka, że musisz użyć nowego identyfikatora ponownego wykorzystania, to gdy Twój wariant komórki ma inną liczbę widoków podrzędnych lub widoki podrzędne są ułożone w inny sposób).
Na przykład, jeśli wyświetlasz wiadomość e-mail w każdej komórce, możesz mieć 4 unikalne układy: wiadomości z tylko tematem, wiadomości z tematem i treścią, wiadomości z tematem i załącznikiem do zdjęcia oraz wiadomości z tematem, ciało i załącznik do zdjęcia. Każdy układ ma zupełnie inne ograniczenia wymagane do jego osiągnięcia, więc po zainicjowaniu komórki i dodaniu ograniczeń dla jednego z tych typów komórek, komórka powinna otrzymać unikalny identyfikator ponownego wykorzystania specyficzny dla tego typu komórki. Oznacza to, że po usunięciu kolejki z komórki do ponownego użycia ograniczenia zostały już dodane i są gotowe do użycia dla tego typu komórek.
Zauważ, że z powodu różnic w wewnętrznej wielkości zawartości komórki z tymi samymi ograniczeniami (typami) mogą nadal mieć różne wysokości! Nie należy mylić zasadniczo różnych układów (różnych ograniczeń) z różnymi obliczonymi ramkami widoku (rozwiązanymi z identycznych ograniczeń) z powodu różnych rozmiarów treści.
W systemie iOS 8 - komórki samopoziomujące
3. Włącz szacowanie wysokości wiersza
W systemie iOS 8 Apple zinternalizowało większość pracy, którą wcześniej musiałeś wykonać przed iOS 8. Aby zezwolić na działanie mechanizmu komórki samopoziomującej, musisz najpierw ustawić
rowHeight
właściwość w widoku tabeli na stałąUITableViewAutomaticDimension
. Następnie wystarczy włączyć oszacowanie wysokości wiersza, ustawiając właściwość widoku tabeli naestimatedRowHeight
niezerową wartość, na przykład:Zapewnia to widokowi tabeli tymczasowe oszacowanie / symbol zastępczy dla wysokości wierszy komórek, które nie są jeszcze wyświetlane na ekranie. Następnie, gdy komórki te będą przewijać się na ekranie, zostanie obliczona rzeczywista wysokość wiersza. Aby określić rzeczywistą wysokość dla każdego wiersza, widok tabeli automatycznie pyta każdą komórkę, jaka wysokość
contentView
musi być oparta na znanej stałej szerokości widoku treści (która jest oparta na szerokości widoku tabeli, pomniejszonej o wszelkie dodatkowe rzeczy, takie jak indeks sekcji lub widok akcesoriów) oraz ograniczenia automatycznego układu dodane do widoku zawartości i widoków podrzędnych komórki. Po określeniu tej rzeczywistej wysokości komórki stara szacowana wysokość wiersza jest aktualizowana o nową rzeczywistą wysokość (i wszelkie korekty zawartości contentSize / contentOffset widoku tabeli są dokonywane według potrzeb).Ogólnie rzecz biorąc, podane oszacowanie nie musi być bardzo dokładne - służy jedynie do prawidłowego rozmiaru wskaźnika przewijania w widoku tabeli, a widok tabeli dobrze dostosowuje wskaźnik przewijania w celu uzyskania niepoprawnych oszacowań przewiń komórki na ekranie. Powinieneś ustawić
estimatedRowHeight
właściwość w widoku tabeli (wviewDidLoad
lub podobnym) na stałą wartość, która jest „średnią” wysokością wiersza. Tylko jeśli wysokość rzędów jest skrajnie zmienna (np. Różni się o rząd wielkości) i zauważysz, że wskaźnik przewijania „przeskakuje” podczas przewijania, należy zadać sobie trud wykonaniatableView:estimatedHeightForRowAtIndexPath:
minimalnego obliczenia wymaganego w celu uzyskania dokładniejszego oszacowania dla każdego rzędu.Obsługa systemu iOS 7 (samodzielne wdrażanie automatycznego określania rozmiaru komórki)
3. Wykonaj Layout Pass i uzyskaj wysokość komórki
Najpierw utwórz instancję poza ekranem komórki widoku tabeli, po jednej instancji dla każdego identyfikatora ponownego wykorzystania , która jest używana wyłącznie do obliczeń wysokości. (Poza ekranem oznacza, że odwołanie do komórki jest przechowywane we właściwości / ivar na kontrolerze widoku i nigdy nie wraca z
tableView:cellForRowAtIndexPath:
widoku tabeli do rzeczywistego renderowania na ekranie.) Następnie komórkę należy skonfigurować z dokładną zawartością (np. Tekst, obrazy itp.) trzymałby, gdyby miał być wyświetlany w widoku tabeli.Następnie zmuś komórkę do natychmiastowego ułożenia swoich widoków podrzędnych, a następnie użyj
systemLayoutSizeFittingSize:
metody naUITableViewCell
,contentView
aby dowiedzieć się, jaka jest wymagana wysokość komórki. Użyj,UILayoutFittingCompressedSize
aby uzyskać najmniejszy rozmiar wymagany do dopasowania całej zawartości komórki. Wysokość może być następnie zwrócona ztableView:heightForRowAtIndexPath:
metody delegowania.4. Użyj szacunkowych wysokości rzędów
Jeśli widok tabeli zawiera więcej niż kilkadziesiąt wierszy, przekonasz się, że wykonanie funkcji automatycznego wiązania układu może szybko ugrzęznąć w głównym wątku podczas pierwszego ładowania widoku tabeli, tak jak
tableView:heightForRowAtIndexPath:
jest to wywoływane w każdym wierszu przy pierwszym załadowaniu ( w celu obliczenia rozmiaru wskaźnika przewijania).Począwszy od systemu iOS 7, możesz (i absolutnie należy) korzystać z
estimatedRowHeight
właściwości w widoku tabeli. Zapewnia to widokowi tabeli tymczasowe oszacowanie / symbol zastępczy dla wysokości wierszy komórek, które nie są jeszcze wyświetlane na ekranie. Następnie, gdy komórki te będą przewijać się na ekranie, rzeczywista wysokość wiersza zostanie obliczona (przez wywołanietableView:heightForRowAtIndexPath:
), a szacowana wysokość zaktualizowana o rzeczywistą.Ogólnie rzecz biorąc, podane oszacowanie nie musi być bardzo dokładne - służy jedynie do prawidłowego rozmiaru wskaźnika przewijania w widoku tabeli, a widok tabeli dobrze dostosowuje wskaźnik przewijania w celu uzyskania niepoprawnych oszacowań przewiń komórki na ekranie. Powinieneś ustawić
estimatedRowHeight
właściwość w widoku tabeli (wviewDidLoad
lub podobnym) na stałą wartość, która jest „średnią” wysokością wiersza. Tylko jeśli wysokość rzędów jest skrajnie zmienna (np. Różni się o rząd wielkości) i zauważysz, że wskaźnik przewijania „przeskakuje” podczas przewijania, należy zadać sobie trud wykonaniatableView:estimatedHeightForRowAtIndexPath:
minimalnego obliczenia wymaganego w celu uzyskania dokładniejszego oszacowania dla każdego rzędu.5. (W razie potrzeby) Dodaj buforowanie wysokości wiersza
Jeśli wykonałeś wszystkie powyższe czynności i nadal odkrywasz, że wydajność jest niedopuszczalnie niska podczas rozwiązywania ograniczeń
tableView:heightForRowAtIndexPath:
, niestety będziesz musiał zaimplementować buforowanie dla wysokości komórek. (Takie podejście sugerują inżynierowie Apple.) Ogólny pomysł polega na tym, że silnik Autolayout rozwiązuje ograniczenia po raz pierwszy, a następnie buforuje obliczoną wysokość dla tej komórki i używa wartości buforowanej dla wszystkich przyszłych żądań dotyczących wysokości tej komórki. Sztuką jest oczywiście wyczyszczenie pamięci podręcznej wysokości komórki, gdy zdarzy się coś, co może spowodować zmianę wysokości komórki - przede wszystkim, gdy zmieni się zawartość tej komórki lub gdy wystąpią inne ważne zdarzenia (takie jak dostosowanie użytkownika suwak rozmiaru tekstu typu dynamicznego).Ogólny przykładowy kod dla iOS 7 (z dużą ilością soczystych komentarzy)
Przykładowe projekty
Te projekty są w pełni działającymi przykładami widoków tabeli ze zmiennymi wysokościami wierszy ze względu na komórki widoku tabeli zawierające dynamiczną zawartość w UILabels.
Xamarin (C # /. NET)
Jeśli korzystasz z Xamarin, sprawdź ten przykładowy projekt opracowany przez @KentBoogaart .
źródło
heightForRowAtIndexPath
, zatrzymanie komórki i zwrócenie jej przy następnymcellForRowAtIndexPath
wywołaniu.iOS8
wdrożenie jest nadal zalecaneiOS9
iiOS10
czy istnieją nowe podejścia od czasu opublikowania tej odpowiedzi?W przypadku iOS 8 powyżej jest to naprawdę proste:
lub
Ale w iOS 7 kluczem jest obliczyć wysokość po autoukładzie:
Ważny
Jeśli wiele wierszy etykiet, nie zapomnij ustawić
numberOfLines
się0
.Nie zapomnij
label.preferredMaxLayoutWidth = CGRectGetWidth(tableView.bounds)
Pełny przykładowy kod znajduje się tutaj .
źródło
Szybki przykład zmiennej wysokości UITableViewCell
Zaktualizowano dla Swift 3
Szybka odpowiedź Williama Hu jest dobra, ale pomaga mi zrobić kilka prostych, ale szczegółowych kroków podczas nauki robienia czegoś po raz pierwszy. Poniższy przykład to mój projekt testowy podczas nauki tworzenia
UITableView
zmiennej wysokości komórek. Oparłem go na tym prostym przykładzie UITableView dla Swift .Gotowy projekt powinien wyglądać następująco:
Utwórz nowy projekt
Może to być tylko aplikacja z pojedynczym widokiem.
Dodaj kod
Dodaj nowy plik Swift do swojego projektu. Nazwij to MyCustomCell. Ta klasa będzie przechowywać wyloty widoków, które dodajesz do komórki w serii ujęć. W tym podstawowym przykładzie będziemy mieli tylko jedną etykietę w każdej komórce.
Podłączymy to gniazdko później.
Otwórz ViewController.swift i upewnij się, że masz następującą treść:
Ważna uwaga:
Poniższe dwa wiersze kodu (wraz z automatycznym układem) umożliwiają zmienną wysokość komórki:
Skonfiguruj scenorys
Dodaj widok tabeli do kontrolera widoku i użyj automatycznego układu, aby przypiąć go do czterech stron. Następnie przeciągnij komórkę widoku tabeli do widoku tabeli. I do komórki Prototyp przeciągnij etykietę. Użyj automatycznego układu, aby przypiąć etykietę do czterech krawędzi widoku zawartości komórki widoku tabeli.
Ważna uwaga:
Inne ustawienia IB
Niestandardowa nazwa klasy i identyfikator
Wybierz komórkę widoku tabeli i ustaw niestandardową klasę na
MyCustomCell
(nazwa klasy w dodanym pliku Swift). Ustaw także Identyfikator nacell
(ten sam ciąg, którego użyliśmycellReuseIdentifier
w powyższym kodzie.Zero linii dla etykiety
Ustaw liczbę linii
0
w etykiecie. Oznacza to wiele linii i pozwala na zmianę rozmiaru etykiety w zależności od jej zawartości.Podłącz haki
tableView
zmiennej wViewController
kodzie.myCellLabel
zmiennej wMyCustomCell
klasie.Skończone
Powinieneś być teraz w stanie uruchomić swój projekt i uzyskać komórki o zmiennej wysokości.
Notatki
Jeśli nie przypinasz krawędzi początkowej i końcowej (lewej i prawej), konieczne może być również ustawienie etykiety,
preferredMaxLayoutWidth
aby wiedziała, kiedy zawinąć linię. Na przykład, jeśli dodałeś ograniczenie Środek w poziomie do etykiety w powyższym projekcie zamiast przypinać krawędzie początkowe i końcowe, musisz dodać tę linię dotableView:cellForRowAtIndexPath
metody:Zobacz też
źródło
preferredMaxLayoutWidth
przeciw komórcecontentSize
? W ten sposób, jeśli masz widok akcesorium lub został on przesunięty do edycji, to nadal będzie brany pod uwagę?Zawarłem rozwiązanie iOS7 @ smileyborg w jednej kategorii
Postanowiłem zawinąć to sprytne rozwiązanie @smileyborg w
UICollectionViewCell+AutoLayoutDynamicHeightCalculation
kategorię.Kategoria rozwiązuje również problemy przedstawione w odpowiedzi @ wildmonkey (ładowanie komórki ze stalówki i
systemLayoutSizeFittingSize:
zwracanieCGRectZero
)Nie uwzględnia buforowania, ale teraz odpowiada moim potrzebom. Możesz go kopiować, wklejać i hakować.
UICollectionViewCell + AutoLayoutDynamicHeightCalculation.h
UICollectionViewCell + AutoLayoutDynamicHeightCalculation.m
Przykład użycia:
Na szczęście nie będziemy musieli robić tego jazzu na iOS8, ale jest na razie!
źródło
[YourCell new]
i użyć tego jako manekina. Tak długo, jak długo tworzony jest kod budujący kod ograniczenia, a programowo uruchamiasz przejście do układu, powinieneś być gotowy.UICollectionViews
.Oto moje rozwiązanie:
Trzeba powiedzieć zanim załaduje się widokiem. W przeciwnym razie nie będzie mógł zachowywać się zgodnie z oczekiwaniami.
TableView
estimatedHeight
Cel C
Zaktualizuj do Swift 4.2
źródło
estimatedRowHeight
zmienia się rząd po rzędzie? powinienem przekraczać lub niedoszacowywać? użyć minimalnej lub maksymalnej wysokości, w której używamtableView
?estimatedRowHeight
, to głównie wpływa na rozmiar paska przewijania, nigdy na wysokość rzeczywistych komórek. Bądź odważny na wybranej wysokości: wpłynie to na animację wstawiania / usuwania.Rozwiązanie zaproponowane przez @smileyborg jest prawie idealne. Jeśli masz komórkę niestandardową i chcesz mieć jedną lub więcej
UILabel
z dynamicznymi wysokościami, wówczas metoda systemLayoutSizeFittingSize w połączeniu z włączoną funkcją AutoLayout zwraca a,CGSizeZero
chyba że przeniesiesz wszystkie ograniczenia komórki z komórki do jej contentView (zgodnie z sugestią @TomSwift tutaj Jak zmienić rozmiar superview do dopasować wszystkie widoki podrzędne z funkcją autolayout? ).Aby to zrobić, musisz wstawić następujący kod do niestandardowej implementacji UITableViewCell (dzięki @Adrian).
Mieszanie odpowiedzi @smileyborg z tym powinno działać.
źródło
systemLayoutSizeFittingSize
należy wywołać w contentView, a nie w komórceTo wystarczająco ważna sprawa, na którą natknąłem się, aby opublikować jako odpowiedź.
Odpowiedź @ smileyborg jest w większości poprawna. Jeśli jednak masz kod w
layoutSubviews
metodzie niestandardowej klasy komórki, na przykład ustawiającpreferredMaxLayoutWidth
, to nie będzie on uruchamiany z tym kodem:Przez chwilę mnie to zaskoczyło. Potem zdałem sobie sprawę, że to dlatego, że uruchamiają tylko podgląd układu
contentView
na komórce, a nie na samej komórce.Mój działający kod wygląda następująco:
Pamiętaj, że jeśli tworzysz nową komórkę, jestem pewien, że nie musisz dzwonić
setNeedsLayout
tak, jak powinna być już ustawiona. W przypadkach, w których zapisujesz odwołanie do komórki, prawdopodobnie powinieneś to nazwać. Tak czy inaczej, nie powinno to nic zranić.Kolejna wskazówka, jeśli używasz podklas komórek, w których ustawiasz takie rzeczy
preferredMaxLayoutWidth
. Jak wspomniała @smileyborg, „komórka widoku tabeli nie ma jeszcze ustalonej szerokości do szerokości widoku tabeli”. To prawda i kłopoty, jeśli wykonujesz pracę w swojej podklasie, a nie w kontrolerze widoku. Możesz jednak po prostu ustawić ramkę komórki w tym punkcie, używając szerokości tabeli:Na przykład w obliczeniach wysokości:
(Zdarzyło mi się buforować tę konkretną komórkę do ponownego użycia, ale to nie ma znaczenia).
źródło
W przypadku, gdy ludzie nadal mają z tym problem. Napisałem szybki post na blogu o korzystaniu z autolayouta z UITableViews, wykorzystując autolayout do dynamicznych wysokości komórek, a także z komponentem open source, który pomaga uczynić to bardziej abstrakcyjnym i łatwiejszym do wdrożenia. https://github.com/Raizlabs/RZCellSizeManager
źródło
Tak długo, jak układ w komórce jest dobry.
Aktualizacja: należy użyć dynamicznej zmiany rozmiaru wprowadzonej w iOS 8.
źródło
tableView:cellForRowAtIndexPath:
natableView:heightForRowAtIndexPath:
teraz?systemLayoutSizeFittingSize:
siętableView:cellForRowAtIndexPath:
i buforować wynik wtedy, a następnie użyć, żetableView:heightForRowAtIndexPath:
to działa dobrze tak długo, jak ograniczenia są ustawione prawidłowo oczywiście!(dla Xcode 8.x / Xcode 9.x czytaj na dole)
Uważaj na następujący problem w Xcode 7.x, który może być źródłem zamieszania:
Konstruktor interfejsów nie obsługuje poprawnie konfiguracji automatycznego doboru komórek. Nawet jeśli twoje ograniczenia są absolutnie ważne, IB nadal będzie narzekać i da ci mylące sugestie i błędy. Powodem jest to, że IB nie chce zmieniać wysokości wiersza zgodnie z Twoimi ograniczeniami (aby komórka pasowała do Twojej zawartości). Zamiast tego utrzymuje stałą wysokość wiersza i zaczyna sugerować zmianę wiązań, które należy zignorować .
Na przykład wyobraź sobie, że wszystko skonfigurowałeś dobrze, bez ostrzeżeń, bez błędów, wszystko działa.
Teraz, jeśli zmienisz rozmiar czcionki (w tym przykładzie zmieniam rozmiar czcionki etykiety opisu z 17.0 na 18.0).
Ponieważ rozmiar czcionki został zwiększony, etykieta chce teraz zajmować 3 wiersze (wcześniej zajmowała 2 wiersze).
Jeśli Konstruktor interfejsów działał zgodnie z oczekiwaniami, zmieniłby wysokość komórki, aby uwzględnić nową etykietę. Jednak tak naprawdę dzieje się tak, że IB wyświetla czerwoną ikonę błędu automatycznego układu i sugeruje zmianę priorytetów przytulania / kompresji.
Powinieneś zignorować te ostrzeżenia. Zamiast tego możesz * ręcznie zmienić wysokość wiersza w (wybierz Komórka> Inspektor rozmiarów> Wysokość wiersza).
Zmieniłem tę wysokość jedno kliknięcie na raz (używając steppera góra / dół), aż znikną błędy czerwonej strzałki! (faktycznie dostaniesz żółte ostrzeżenia, w tym momencie po prostu idź i zrób „aktualizację ramek”, wszystko powinno działać).
* Pamiętaj, że tak naprawdę nie musisz usuwać tych czerwonych błędów lub żółtych ostrzeżeń w Konstruktorze interfejsów - w czasie wykonywania wszystko będzie działało poprawnie (nawet jeśli IB pokazuje błędy / ostrzeżenia). Upewnij się tylko, że w czasie wykonywania w dzienniku konsoli nie pojawią się żadne błędy AutoLayout.
W rzeczywistości próba zawsze aktualizowania wysokości wiersza w IB jest bardzo irytująca, a czasem prawie niemożliwa (z powodu wartości ułamkowych).
Aby zapobiec irytującym ostrzeżeniom / błędom IB, możesz wybrać związane z tym widoki i wybrać
Size Inspector
właściwośćAmbiguity
Verify Position Only
Xcode 8.x / Xcode 9.x wydaje się (czasami) robić rzeczy inaczej niż Xcode 7.x, ale nadal nieprawidłowo. Na przykład, nawet jeśli
compression resistance priority
/hugging priority
są ustawione na wymagane (1000), Konstruktor interfejsów może rozciągnąć lub przyciąć etykietę, aby dopasować ją do komórki (zamiast zmieniać rozmiar wysokości komórki, aby dopasować ją do etykiety). W takim przypadku może nawet nie wyświetlać żadnych ostrzeżeń lub błędów AutoLayout. Lub czasami robi dokładnie to, co zrobił Xcode 7.x, opisane powyżej.źródło
Aby ustawić automatyczny wymiar dla wysokości wiersza i szacowanej wysokości wiersza, wykonaj następujące kroki, aby automatyczny wymiar był skuteczny dla układu wysokości komórki / wiersza.
UITableViewAutomaticDimension
do rowHeight & oszacowanyRowHeightheightForRowAt
I zwracanie wartościUITableViewAutomaticDimension
do niego)-
Cel C:
Szybki:
Dla instancji etykiety w UITableviewCell
Uwaga : Jeśli masz więcej niż jedną etykietę (UIElements) z dynamiczną długością, którą należy dostosować do rozmiaru zawartości: Dostosuj „Priorytet przytulania zawartości i priorytetu odporności na ściskanie” dla etykiet, które chcesz rozwinąć / skompresować z wyższym priorytetem.
źródło
tableView: heightForRow
źródła danych.tableView: heightForRow
. (dla iOS 10-tableView: heightForRow
jest wymagany)tableView: heightForRow
..if (indexPath.row == 0) { return 100} else { return UITableView.automaticDimension }
Podobnie jak @ Bob-Spryn natknąłem się na wystarczająco ważną gotcha, że publikuję to jako odpowiedź.
Walczyłem z użytkownika @ smileyborg odpowiedź na chwilę. Gotcha, na którą natrafiłem, to jeśli zdefiniowałeś swoją prototypową komórkę w IB z dodatkowymi elementami (
UILabels
,UIButtons
itp.) W IB, gdy tworzysz komórkę za pomocą [[YourTableViewCellClass alloc] init]
nie utworzy instancji wszystkich innych elementów w tej komórce, chyba że masz napisany kod, aby to zrobić. (Miałem podobne doświadczenia zinitWithStyle
.)Aby scenariusz tworzył wszystkie dodatkowe elementy, uzyskaj komórkę za pomocą
[tableView dequeueReusableCellWithIdentifier:@"DoseNeeded"]
(Nie,[tableView dequeueReusableCellWithIdentifier:forIndexPath:]
ponieważ spowoduje to interesujące problemy.) Gdy to zrobisz, wszystkie elementy zdefiniowane w IB zostaną utworzone.źródło
Dynamiczny widok tabeli Wysokość komórki i automatyczny układ
Dobry sposób na rozwiązanie problemu z automatycznym układem scenorysu:
źródło
źródło
Kolejne „rozwiązanie”: pomiń całą tę frustrację i zamiast tego użyj UIScrollView, aby uzyskać wynik, który wygląda identycznie jak UITableView.
To było dla mnie bolesne „rozwiązanie” po tym, jak spędziłem dosłownie ponad 20 bardzo frustrujących godzin, próbując zbudować coś takiego, co sugerował smileyborg, i nie udawało mu się przez wiele miesięcy oraz trzy wersje wydań App Store.
Uważam, że jeśli naprawdę potrzebujesz wsparcia dla systemu iOS 7 (dla nas jest to niezbędne), technologia jest po prostu zbyt krucha i spróbujesz wyciągnąć włosy. I że UITableView jest generalnie całkowitą nadwyżką, chyba że korzystasz z niektórych zaawansowanych funkcji edycji wierszy i / lub naprawdę potrzebujesz obsługiwać ponad 1000 „wierszy” (w naszej aplikacji jest to realistycznie nigdy więcej niż 20 wierszy).
Dodatkową zaletą jest to, że kod staje się niesamowicie prosty w porównaniu do wszystkich bzdur delegowanych i tam iz powrotem, które są dostarczane z UITableView. To tylko jedna pętla kodu w viewOnLoad, która wygląda elegancko i jest łatwa w zarządzaniu.
Oto kilka wskazówek, jak to zrobić:
Używając Storyboard lub pliku stalówki, utwórz ViewController i powiązany widok główny.
Przeciągnij UIScrollView do głównego widoku.
Dodaj ograniczenia górne, dolne, lewe i prawe do widoku najwyższego poziomu, aby UIScrollView wypełniał cały widok główny.
Dodaj UIView wewnątrz UIScrollView i nazwij go „kontener”. Dodaj górne, dolne, lewe i prawe ograniczenia do UIScrollView (jego rodzica). KLUCZOWA sztuczka: dodaj również ograniczenia „Równe szerokości”, aby połączyć UIScrollView i UIView.
UWAGA: Pojawi się błąd „widok przewijania ma niejednoznaczną przewijalną wysokość zawartości” i że UIView kontenera powinien mieć wysokość 0 pikseli. Żaden błąd nie wydaje się mieć znaczenia, gdy aplikacja jest uruchomiona.
Utwórz pliki stalówki i kontrolery dla każdej z „komórek”. Użyj UIView nie UITableViewCell.
W głównym katalogu ViewController zasadniczo dodajesz wszystkie „wiersze” do UIView kontenera i programowo dodajesz ograniczenia łączące ich lewą i prawą krawędź z widokiem kontenera, ich górne krawędzie albo z góry kontenera widoku (dla pierwszego elementu), albo z poprzedniego komórka. Następnie połącz ostatnią komórkę z dnem pojemnika.
Dla nas każdy „wiersz” znajduje się w pliku stalówki. Więc kod wygląda mniej więcej tak:
A oto kod dla UITools.addViewToTop:
Jedyną „gotcha”, jaką do tej pory znalazłem w tym podejściu, jest to, że UITableView ma przyjemną funkcję „pływających” nagłówków sekcji u góry widoku podczas przewijania. Powyższe rozwiązanie tego nie zrobi, chyba że dodasz więcej programowania, ale w naszym konkretnym przypadku ta funkcja nie była w 100% niezbędna i nikt nie zauważył, gdy odszedł.
Jeśli chcesz dzielniki między komórkami, po prostu dodaj UIView o wysokości 1 piksela na dole niestandardowej „komórki”, która wygląda jak dzielnik.
Pamiętaj, aby włączyć „odbijanie” i „odbijanie w pionie”, aby kontrola odświeżania działała, dzięki czemu wygląda bardziej jak widok tabeli.
TableView pokazuje niektóre puste wiersze i przekładki pod twoją treścią, jeśli nie wypełnia pełnego ekranu, w przeciwieństwie do tego rozwiązania. Ale osobiście wolę, żeby te puste rzędy i tak nie były - przy zmiennej wysokości komórki i tak zawsze wydawało mi się to „błędne”, żeby mieć tam puste rzędy.
Mam nadzieję, że jakiś inny programista przeczyta mój post PRZED marnowaniem ponad 20 godzin, próbując to rozgryźć w widoku aplikacji we własnej aplikacji. :)
źródło
Musiałem użyć widoków dynamicznych (widoków konfiguracji i ograniczeń według kodu), a kiedy chciałem ustawić szerokość etykiety preferMaxLayoutWidth, wynosił 0. Więc mam nieprawidłową wysokość komórki.
Potem dodałem
przed wykonaniem
Po tym szerokość etykiety była zgodna z oczekiwaniami, a wysokość dynamiczna obliczała się w prawo.
źródło
Załóżmy, że masz komórkę z widokiem podrzędnym i chcesz, aby wysokość komórki była wystarczająco wysoka, aby obejmowała widok podrzędny + wypełnienie.
1) Ustaw dolne ograniczenie widoku podrzędnego równe cell.contentView minus pożądane wypełnienie. Nie ustawiaj ograniczeń dla samej komórki lub cell.contentView.
2) Ustaw właściwość tableView
rowHeight
lubtableView:heightForRowAtIndexPath:
naUITableViewAutomaticDimension
.3) Ustaw właściwość tableView
estimatedRowHeight
lubtableView:estimatedHeightForRowAtIndexPath:
najlepiej zgadnij wysokość.Otóż to.
źródło
Jeśli układasz programowo, oto, co należy wziąć pod uwagę w systemie iOS 10 za pomocą kotwic w Swift.
Istnieją trzy zasady / kroki
NUMER 1: ustaw te dwie właściwości widoku tabeli w widoku viewDidLoad, pierwsza mówi widokowi tabeli, że powinny oczekiwać dynamicznych rozmiarów w swoich komórkach, druga pozwala aplikacji obliczyć rozmiar wskaźnika paska przewijania, dzięki czemu pomaga wydajność.
NUMER 2: Jest to ważne, że musisz dodać widoki podrzędne do contentView komórki, a nie do widoku, a także użyć jej układu, aby zakotwiczyć widoki do góry i dołu, jest to praktyczny przykład tego, jak to zrobić.
Utwórz metodę, która doda widoki podrzędne i wykona układ, wywołaj ją w metodzie init.
NUMER 3: NIE WZYWAJ METODY:
Jeśli to zrobisz, zastąpisz swoją implementację.
Postępuj zgodnie z tymi 3 zasadami dla dynamicznych komórek w widokach tabel.
tutaj jest działająca implementacja https://github.com/jamesrochabrun/MinimalViewController
źródło
Jeśli masz długi ciąg. np. taki, który nie ma podziału linii. Wtedy możesz napotkać pewne problemy.
O „domniemanej” poprawce wspomina zaakceptowana odpowiedź i kilka innych odpowiedzi. Musisz tylko dodać
Uważam, że odpowiedź Suragha jest najbardziej kompletna i zwięzła , dlatego nie jest myląca.
Chociaż nie wyjaśniam, dlaczego te zmiany są potrzebne. Zróbmy to.
Upuść następujący kod w projekcie.
Pamiętaj, że nie dodałem żadnych ograniczeń rozmiaru . Dodałem tylko ograniczenia centerX, centerY. Ale nadal etykieta będzie miała odpowiedni rozmiar Dlaczego?
Z powodu
contentSize
.Aby to lepiej przetworzyć, najpierw zachowaj krok 0, a następnie skomentuj kroki 1-6. Niech
setupLayout()
pobyt. Obserwuj zachowanie.Następnie odkomentuj krok 1 i obserwuj.
Następnie odkomentuj krok 2 i obserwuj.
Rób to, dopóki nie skomentujesz wszystkich 6 kroków i nie zaobserwujesz ich zachowań.
Co można z tego wywnioskować? Jakie czynniki mogą to zmienić
contenSize
?\n
wówczas szerokość intrinsicContentSize będzie maksymalną szerokością wszystkich linii. Jeśli jeden wiersz ma 25 znaków, inny ma 2 znaki, a drugi 21 znaków, wówczas szerokość zostanie obliczona na podstawie 25 znakównumberOfLines
się0
w przeciwnym wypadku nie będzie mieć wiele wierszy. TwojenumberOfLines
dostosuje swoją wewnętrzną wysokość ContentSizeWprowadzanie korekt: wyobraź sobie, że na podstawie tekstu szerokość
200
i wysokość wewnętrznej wartości była100
, ale chciałeś ograniczyć szerokość do kontenera etykiety, co zamierzasz zrobić? Rozwiązaniem jest ustawienie żądanej szerokości. To zrobić poprzez ustawieniepreferredMaxLayoutWidth
się130
wówczas nowy intrinsicContentSize będzie mieć szerokość w przybliżeniu130
. Wysokość byłaby oczywiście większa niż100
dlatego, że potrzebujesz więcej linii. Biorąc to pod uwagę, jeśli twoje ograniczenia są ustawione poprawnie, nie będziesz musiał tego wcale używać! Więcej informacji na ten temat można znaleźć w tej odpowiedzi i jej komentarzach. Musisz użyćpreferredMaxLayoutWidth
tylko, jeśli nie masz ograniczeń ograniczających szerokość / wysokość, jak można by powiedzieć „nie zawijaj tekstu, chyba że przekracza onpreferredMaxLayoutWidth
”. Ale ze 100% pewnością, jeśli ustawisz wiodącym / spływu inumberOfLines
do0
ówczesnego jesteś dobry!Krótka historia, większość odpowiedzi, które zalecają jej użycie, są NIEPRAWIDŁOWE! Nie potrzebujesz tego. Potrzebowanie go jest znakiem, że twoje ograniczenia nie są ustawione poprawnie lub po prostu nie masz ograniczeńRozmiar czcionki: należy również pamiętać, że jeśli zwiększysz fontSize, wówczas wzrośnie wysokość intrinsicContentSize . Nie pokazałem tego w moim kodzie. Możesz spróbować tego samodzielnie.
Wróćmy do przykładu tableViewCell:
Wszystko, co musisz zrobić, to:
numberOfLines
na0
preferredMaxLayoutWidth
.źródło
W moim przypadku muszę utworzyć niestandardową komórkę z obrazem, który pochodzi z serwera i może mieć dowolną szerokość i wysokość. I dwa etykiety UIL z dynamicznym rozmiarem (zarówno szerokość, jak i wysokość)
osiągnąłem to samo tutaj w mojej odpowiedzi z autolayout i programowo:
Zasadniczo powyżej @smileyBorg odpowiedź pomogła, ale systemLayoutSizeFittingSize nigdy nie działał dla mnie, w moim podejściu:
1. Brak użycia właściwości automatycznego obliczania wysokości wiersza. 2. Bez użycia szacunkowej wysokości 3. Nie ma potrzeby niepotrzebnej aktualizacji Ograniczenia. 4. Brak użycia automatycznej preferowanej maksymalnej szerokości układu. 5. Bez użycia systemLayoutSizeFittingSize (powinien być używany, ale nie działa dla mnie, nie wiem, co robi wewnętrznie), ale zamiast tego moja metoda - (float) getViewHeight działa i wiem, co robi wewnętrznie.
Czy możliwe jest uzyskanie różnych wysokości w komórce UITableView, gdy korzystam z kilku różnych sposobów wyświetlania komórki?
źródło
W moim przypadku dopełnienie było spowodowane wysokościami sectionHeader i sectionFooter, gdzie storyboard pozwolił mi zmienić go na minimum 1. Więc w metodzie viewDidLoad:
źródło
Właśnie zrobiłem jakiś głupi błąd i spróbować z wartościami 2
rowHeight
aestimatedRowHeight
i tak, że może zapewnić pewne wgląd debugowania:Jeśli ustawisz oba oba LUB tylko ustawisz
estimatedRowHeight
, uzyskasz pożądane zachowanie:Sugeruje się, abyś dokładał wszelkich starań, aby uzyskać prawidłowe oszacowanie, ale wynik końcowy nie jest inny. Wpłynie to tylko na twoją wydajność.
Jeśli ustawisz tylko rowHeight tj. Wykonaj tylko:
Twój wynik końcowy nie byłby tak pożądany:
Jeśli ustawisz wartość
estimatedRowHeight
1 lub mniejszą, nastąpi awaria bez względu narowHeight
.Wystąpił błąd z następującym komunikatem o błędzie:
źródło
Jeśli chodzi o zaakceptowaną odpowiedź @smileyborg, znalazłem
być zawodnym w niektórych przypadkach, gdy ograniczenia są niejednoznaczne. Lepiej zmusić silnik układu do obliczenia wysokości w jednym kierunku, używając kategorii pomocnika na UIView poniżej:
Gdzie w: oznacza szerokość widoku tabeli
źródło
Wystarczy dodać te dwie funkcje do kontrolera widoku, aby rozwiązać problem. Tutaj lista jest tablicą zawierającą ciąg każdego wiersza.
źródło
źródło
Jeśli wysokość komórki jest dynamiczna według zawartości, należy ją dokładnie policzyć, a następnie zwrócić wartość wysokości przed renderowaniem komórki. Prostym sposobem jest zdefiniowanie metody liczenia w kodzie komórki widoku tabeli, aby sterownik mógł wywoływać metodę delegowania wysokości komórki tabeli. Nie zapomnij policzyć rzeczywistej szerokości ramki komórki (domyślnie 320), jeśli wysokość zależy od szerokości stołu lub ekranu. Oznacza to, że w metodzie delegowania wysokości komórki tabeli użyj cell.frame, aby najpierw poprawić szerokość komórki, a następnie wywołaj metodę wysokości zliczania zdefiniowaną w komórce, aby uzyskać odpowiednią wartość i zwrócić ją .
PS. Kod do generowania obiektu komórki można zdefiniować w innej metodzie dla innej metody delegowania komórki widoku tabeli do wywołania.
źródło
UITableView.automaticDimension
można ustawić za pomocą Konstruktora interfejsów:Xcode> Storyboard> Inspektor rozmiarów
Komórka widoku tabeli> Wysokość wiersza> Automatyczna
źródło
jeszcze jedno rozwiązanie iOs7 + iOs8 w Swift
źródło
cellForRowAtIndexPath
, w tym momencie komórka nie jest jeszcze ułożona.