Jeden z naszych ekranów aplikacji wymaga od nas umieszczenia UICollectionView
wewnątrz pliku UITableViewCell
. To UICollectionView
będzie mieć numer dynamicznych elementów, w wyniku wzrostu, które muszą być obliczane dynamicznie, jak również. Jednak napotykam problemy podczas próby obliczenia wysokości osadzenia UICollectionView
.
Nasze nadrzędne UIViewController
zostały stworzone w Storyboards i korzystają z automatycznego układu. Ale nie wiem, jak dynamicznie zwiększać wysokość na UITableViewCell
podstawie wysokości UICollectionView
.
Czy ktoś może udzielić wskazówek lub porad, jak to osiągnąć?
ios
uitableview
uicollectionview
Człowiek cień
źródło
źródło
UITableViewCell
różni się od rzeczywistego widoku tabeli? Czy potrzebujesz przewijania w pionie zarówno na, jakUICollectionView
i naUITableView
Odpowiedzi:
Prawidłowa odpowiedź brzmi TAK , MOŻESZ to zrobić.
Z tym problemem natknąłem się kilka tygodni temu. W rzeczywistości jest to łatwiejsze niż myślisz. Umieść swoje komórki w NIB (lub scenorysach) i przypnij je, aby automatyczny układ wykonał całą pracę
Biorąc pod uwagę następującą strukturę:
Rozwiązaniem jest poinformowanie układu automatycznego, aby najpierw obliczył rozmiary collectionViewCell, a następnie contentSize widoku kolekcji i użyć go jako rozmiaru komórki. Oto metoda UIView , która „robi magię”:
Musisz ustawić tutaj rozmiar TableViewCell, który w twoim przypadku jest ContentSize CollectionView.
CollectionViewCell
W CollectionViewCell musisz powiedzieć komórce, aby układała się za każdym razem, gdy zmieniasz model (np .: ustawiasz UILabel z tekstem, a następnie komórka musi być ponownie ułożona).
TableViewCell
TableViewCell czyni magię. To ma wylot do swojego CollectionView umożliwia układ automatycznego dla komórek CollectionView korzystających estimatedItemSize z UICollectionViewFlowLayout .
Następnie sztuczka polega na ustawieniu rozmiaru komórki tableView w metodzie systemLayoutSizeFittingSize ... (UWAGA: iOS8 lub nowszy)
UWAGA: Próbowałem użyć metody wysokości komórki delegata w tableView.,
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
Ale jest już za późno, aby system automatycznego układu obliczył CollectionView contentSize i czasami możesz znaleźć niewłaściwe komórki o zmienionym rozmiarze.TableViewController
Pamiętaj, aby włączyć system automatycznego układu dla komórek tableView w swoim TableViewController :
KREDYT : @rbarbera pomógł rozwiązać ten problem
źródło
cell.bounds = CGRectMake(0, 0, CGRectGetWidth(tableView.bounds), 10000);
to „zasymuluje” długą komórkę z długim collectionView, więc collectionView obliczy rozmiar wszystkich swoich komórek. W przeciwnym razie collectionView oblicza tylko widoczne rozmiary komórek i ustawia nieprawidłowo wysokość talbeViewCell.systemLayoutSizeFittingSize
, szybko napotkałem problem podczas ponownego ładowania komórki, aplikacje wydają się blokować poself.collectionView.layoutIfNeeded()
. Naprawiłem to, ustawiając wysokość ramy na 1 zamiast maksymalnej wysokości. Mam nadzieję, że to pomoże, jeśli ktoś natknie się na ten problem.systemLayoutSizeFitting
, odwróć kolejność tego, co jest obecnie pokazane w odpowiedzi, więc najpierwcollectionView.layoutIfNeeded()
działa, a następniecollectionView.frame = CGRect.init(origin: .zero, size: CGSize.init(width: targetSize.width, height: 1))
Myślę, że moje rozwiązanie jest znacznie prostsze niż to zaproponowane przez @PabloRomeu.
Krok 1. Utwórz gniazdko od
UICollectionView
doUITableViewCell subclass
, w którym sięUICollectionView
znajduje. Niech to będzie imięcollectionView
Krok 2. Dodaj IB dla
UICollectionView
ograniczenia wysokości i utwórz również wylotUITableViewCell subclass
. Niech to będzie imięcollectionViewHeight
.Krok 3. W
tableView:cellForRowAtIndexPath:
dodaniu kodu:źródło
collectionView
wszystkich stronUITableViewCell
i ustawićtableView.estimatedRowHeight = 44;
itableView.rowHeight = UITableViewAutomaticDimension;
Zarówno widoki tabeli, jak i widoki kolekcji są
UIScrollView
podklasami i dlatego nie lubią być osadzane w innym widoku przewijania, gdy próbują obliczyć rozmiary zawartości, ponownie wykorzystać komórki itp.Zalecam używanie tylko widoku kolekcji do wszystkich celów.
Możesz podzielić go na sekcje i „traktować” układ niektórych sekcji jako widok tabeli, a innych jako widok zbioru. W końcu nie ma nic, czego nie można osiągnąć w widoku kolekcji, czego można by uzyskać w widoku tabeli.
Jeśli masz podstawowy układ siatki dla „części” widoku kolekcji, możesz również użyć zwykłych komórek tabeli do ich obsługi. Jeśli jednak nie potrzebujesz obsługi iOS 5, lepiej korzystaj z widoków kolekcji.
źródło
layoutAttributesForItemAtIndexPath
na różne sekcje w mojej własnej podklasieUICollectionViewLayout
?Powyższa odpowiedź Pablo Romeu ( https://stackoverflow.com/a/33364092/2704206 ) bardzo mi pomogła w rozwiązaniu mojego problemu. Musiałem jednak zrobić kilka rzeczy inaczej, aby to zadziałało. Po pierwsze, nie musiałem dzwonić
layoutIfNeeded()
tak często. Musiałem tylko wywołać tocollectionView
wsystemLayoutSizeFitting
funkcji.Po drugie, miałem ograniczenia automatycznego układu w moim widoku kolekcji w komórce widoku tabeli, aby nadać mu pewne wypełnienie. Musiałem więc odjąć wiodący i końcowy margines od
targetSize.width
podczas ustawianiacollectionView.frame
szerokości. Musiałem również dodać górny i dolny margines doCGSize
wysokości zwracanej wartości .Aby uzyskać te stałe ograniczenia, miałem możliwość albo utworzenia wyjść dla ograniczeń, zakodowania ich stałych na stałe, albo wyszukania ich za pomocą identyfikatora. Zdecydowałem się na trzecią opcję, aby moja niestandardowa klasa komórek widoku tabeli była łatwa do ponownego wykorzystania. W końcu to było wszystko, czego potrzebowałem, aby to działało:
Jako funkcję pomocniczą do pobierania ograniczenia według identyfikatora dodaję następujące rozszerzenie:
UWAGA: Będziesz musiał ustawić identyfikator tych ograniczeń w swoim storyboardzie lub gdziekolwiek są tworzone. Jeśli nie mają stałej 0, to nie ma to znaczenia. Ponadto, podobnie jak w odpowiedzi Pablo, będziesz musiał użyć
UICollectionViewFlowLayout
jako układu widoku kolekcji. Na koniec upewnij się, że łączyszcollectionView
IBOutlet ze swoim scenorysem.Dzięki powyższej komórce niestandardowego widoku tabeli mogę teraz podklasować ją w dowolnej innej komórce widoku tabeli, która wymaga widoku kolekcji, i zaimplementować protokoły
UICollectionViewDelegateFlowLayout
iUICollectionViewDataSource
. Mam nadzieję, że to pomoże komuś innemu!źródło
Przeczytałem wszystkie odpowiedzi. Wydaje się, że to służy wszystkim.
źródło
Alternatywą dla rozwiązania Pablo Romeu jest dostosowanie samego UICollectionView zamiast wykonywania pracy w komórce widoku tabeli.
Podstawowy problem polega na tym, że domyślnie widok kolekcji nie ma wewnętrznego rozmiaru i dlatego nie może informować automatycznego układu o wymiarach, które mają być używane. Możesz temu zaradzić, tworząc niestandardową podklasę, która zwraca użyteczny rozmiar wewnętrzny.
Utwórz podklasę UICollectionView i Zastąp następujące metody
(Powinieneś także nadpisać powiązane metody: reloadSections, reloadItemsAtIndexPaths w podobny sposób jak reloadData ())
Wywołanie layoutIfNeeded wymusza na widoku kolekcji ponowne obliczenie rozmiaru zawartości, który może następnie zostać użyty jako nowy rozmiar wewnętrzny.
Ponadto musisz jawnie obsłużyć zmiany rozmiaru widoku (np. Przy obracaniu urządzenia) w kontrolerze widoku tabeli
źródło
Ostatnio miałem do czynienia z tym samym problemem i prawie próbowałem każdego rozwiązania w odpowiedziach, niektóre z nich działały, a inne nie były moim głównym zmartwieniem podejściu @PabloRomeu jest to, że jeśli masz inną zawartość w komórce (poza widokiem kolekcji) będziesz musiał obliczyć ich wysokości i wysokości ich ograniczeń i zwrócić wynik, aby uzyskać prawidłowy układ automatyczny, a ja nie lubię obliczać rzeczy ręcznie w moim kodzie. Oto rozwiązanie, które działało dobrze bez wykonywania żadnych ręcznych obliczeń w moim kodzie.
w
cellForRow:atIndexPath
widoku tabeli wykonuję następujące czynności:Myślę, że to, co się tutaj dzieje, polega na tym, że zmuszam komórkę widoku tabeli do dostosowania jej wysokości po obliczeniu wysokości widoku kolekcji. (po podaniu daty collectionView do źródła danych)
źródło
Umieściłbym statyczną metodę w klasie widoku kolekcji, która zwróci rozmiar na podstawie zawartości, którą będzie miała. Następnie użyj tej metody w,
heightForRowAtIndexPath
aby zwrócić właściwy rozmiar.Zauważ również, że osadzając tego rodzaju kontrolery widoku, możesz uzyskać dziwne zachowanie. Zrobiłem to raz i miałem dziwne problemy z pamięcią, których nigdy nie rozwiązałem.
źródło
Może mój wariant się przyda; decydowałem się na to zadanie w ciągu ostatnich dwóch godzin. Nie udaję, że jest to w 100% poprawne lub optymalne, ale moje umiejętności są jeszcze bardzo małe i chciałbym usłyszeć komentarze ekspertów. Dziękuję Ci. Jedna ważna uwaga: działa to dla tabeli statycznej - jest to określone w mojej bieżącej pracy. Więc wszystko, czego używam, to viewWillLayoutSubviews of tableView . I trochę więcej.
źródło
Najłatwiejsze podejście, jakie do tej pory wymyśliłem, Kredyty na odpowiedź @igor powyżej,
W swojej klasie tableviewcell po prostu wstaw to
i oczywiście zmień punkt odbioru kolekcji na wylot w klasie celi
źródło
Mam pomysł od @Igor post i inwestuję w to swój czas
Po prostu minęło to w twoim
Dodawanie: Jeśli widzisz, że UICollectionView zacina się podczas ładowania komórek.
źródło
Rozwiązanie Pablo nie działało zbyt dobrze dla mnie, miałem dziwne efekty wizualne (widok kolekcji nie dostosowywał się poprawnie).
To, co działało, polegało na dostosowaniu ograniczenia wysokości collectionView (jako NSLayoutConstraint) do contentSize collectionView podczas
layoutSubviews()
. Jest to metoda wywoływana w przypadku zastosowania automatycznego układu do komórki.źródło
W Twoim UITableViewDelegate:
Zastąp itemCount i CollectionViewCellHeight wartościami rzeczywistymi. Jeśli masz tablicę tablic itemCount może wynosić:
Lub cokolwiek.
źródło
collectionViewCellHeight
przed renderowaniem.1. Stwórz atrapę komórki.
2. Użyj metody collectionViewContentSize na UICollectionViewLayout z UICollectionView przy użyciu bieżących danych.
źródło
Można obliczyć wysokość zbiorów na podstawie jego właściwości, takich jak
itemSize
,sectionInset
,minimumLineSpacing
,minimumInteritemSpacing
, jeślicollectionViewCell
ma granicę reguły.źródło