Mam plik UICollectionView
z FLowLayout. Przez większość czasu będzie działać tak, jak się spodziewam, ale od czasu do czasu jedna z komórek nie owija się prawidłowo. Na przykład komórka, która powinna znajdować się w pierwszej „kolumnie” trzeciego wiersza, jeśli faktycznie znajduje się na końcu drugiego wiersza, aw miejscu jej umieszczenia jest tylko puste miejsce (patrz diagram poniżej). Wszystko, co widzisz w tej komórce różu, to lewa strona (reszta jest odcięta), a miejsce, w którym powinna być, jest puste.
Nie dzieje się to konsekwentnie; nie zawsze jest to ten sam wiersz. Kiedy to się stanie, mogę przewinąć w górę i z powrotem, a komórka się naprawi. Lub, gdy naciskam komórkę (która przenosi mnie do następnego widoku poprzez naciśnięcie), a następnie cofam, zobaczę komórkę w niewłaściwej pozycji, a następnie przeskoczy do właściwej pozycji.
Wydaje się, że szybkość przewijania ułatwia odtworzenie problemu. Kiedy przewijam powoli, nadal widzę od czasu do czasu komórkę w niewłaściwej pozycji, ale wtedy od razu przeskoczy do właściwej pozycji.
Problem zaczął się, gdy dodałem wstawki sekcji. Wcześniej komórki były prawie równe z granicami kolekcji (małe wstawki lub brak wstawek) i nie zauważyłem problemu. Ale to oznaczało, że prawa i lewa część widoku kolekcji były puste. To znaczy, nie można przewijać. Ponadto pasek przewijania nie był wyrównany w prawo.
Mogę rozwiązać problem zarówno w symulatorze, jak i na iPadzie 3.
Wydaje mi się, że problem występuje z powodu wstawek lewej i prawej sekcji ... Ale jeśli wartość jest nieprawidłowa, spodziewałbym się, że zachowanie będzie spójne. Zastanawiam się, czy to może być błąd w Apple? A może jest to spowodowane nagromadzeniem wypustek lub czymś podobnym.
Kontynuacja : od ponad 2 lat korzystam z poniższej odpowiedzi Nicka bez problemu (na wypadek, gdyby ludzie zastanawiali się, czy w tej odpowiedzi są jakieś dziury - jeszcze żadnej nie znalazłem). Dobra robota, Nick.
źródło
Umieść to w viewController, który jest właścicielem widoku kolekcji
- (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; [self.collectionView.collectionViewLayout invalidateLayout]; }
źródło
invalidateLayout
tylko raz.Odkryłem podobne problemy w mojej aplikacji na iPhone'a. Przeszukanie forum deweloperów Apple przyniosło mi to odpowiednie rozwiązanie, które zadziałało w moim przypadku i prawdopodobnie będzie również w twoim:
Podklasa
UICollectionViewFlowLayout
i przesłonięcie,shouldInvalidateLayoutForBoundsChange
aby zwrócićYES
.//.h @interface MainLayout : UICollectionViewFlowLayout @end
i
//.m #import "MainLayout.h" @implementation MainLayout -(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{ return YES; } @end
źródło
Szybka wersja odpowiedzi Nicka Snydera:
class NDCollectionViewFlowLayout : UICollectionViewFlowLayout { override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { let attributes = super.layoutAttributesForElements(in: rect) let contentSize = collectionViewContentSize return attributes?.filter { $0.frame.maxX <= contentSize.width && $0.frame.maxY < contentSize.height } } }
źródło
Miałem również ten problem w przypadku podstawowego układu widoku siatki z wstawkami na marginesy. Ograniczone debugowanie, które zrobiłem na razie, polega na implementacji
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
w mojej podklasie UICollectionViewFlowLayout i przez rejestrowanie tego, co zwraca implementacja superklasy, co wyraźnie pokazuje problem.- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { NSArray *attrsList = [super layoutAttributesForElementsInRect:rect]; for (UICollectionViewLayoutAttributes *attrs in attrsList) { NSLog(@"%f %f", attrs.frame.origin.x, attrs.frame.origin.y); } return attrsList; }
Po wdrożeniu
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
widzę również, że wydaje się zwracać niewłaściwe wartości dla itemIndexPath.item == 30, co stanowi 10 czynnik liczby komórek w moim widoku siatki w wierszu, nie jestem pewien, czy to ma znaczenie.- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath { UICollectionViewLayoutAttributes *attrs = [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath]; NSLog(@"initialAttrs: %f %f atIndexPath: %d", attrs.frame.origin.x, attrs.frame.origin.y, itemIndexPath.item); return attrs; }
Z braku czasu na dalsze debugowanie, obejście, które zrobiłem, polega na zmniejszeniu szerokości moich podglądów kolekcji o kwotę równą lewemu i prawemu marginesowi. Mam nagłówek, który nadal wymaga pełnej szerokości, więc ustawiłem clipsToBounds = NO w moim widoku kolekcji, a następnie usunąłem z niego lewe i prawe wstawki. Wygląda na to, że działa. Aby widok nagłówka pozostał na miejscu, należy zaimplementować przesuwanie klatek i zmianę rozmiaru w metodach układu, które mają za zadanie zwracanie atrybutów layout dla widoku nagłówka.
źródło
Dodałem raport o błędzie do Apple. To, co działa dla mnie, to ustawienie dolnej sekcjiInset na wartość mniejszą niż górna wstawka.
źródło
Miałem ten sam problem ze zubożeniem komórki na iPhonie przy użyciu
UICollectionViewFlowLayout
a, więc byłem zadowolony ze znalezienia twojego postu. Wiem, że masz problem z iPadem, ale publikuję to, ponieważ myślę, że jest to ogólny problem zUICollectionView
. Więc oto, czego się dowiedziałem.Mogę potwierdzić, że
sectionInset
jest to istotne dla tego problemu. Poza tymheaderReferenceSize
ma również wpływ na to, czy komórka jest wyczerpana, czy nie. (Ma to sens, ponieważ jest potrzebne do obliczenia pochodzenia).Niestety, należy wziąć pod uwagę nawet różne rozmiary ekranu. Podczas zabawy z wartościami tych dwóch właściwości zauważyłem, że pewna konfiguracja działała albo na obu (3,5 "i 4"), na żadnej lub tylko na jednym z rozmiarów ekranu. Zwykle żaden z nich. (Ma to również sens, ponieważ granice
UICollectionView
zmian, dlatego nie doświadczyłem żadnej dysproporcji między siatkówką i bez siatkówki).Skończyło się na ustawieniu
sectionInset
i wheaderReferenceSize
zależności od rozmiaru ekranu. Próbowałem około 50 kombinacji, aż znalazłem wartości, pod którymi problem już nie występował, a układ był wizualnie akceptowalny. Bardzo trudno jest znaleźć wartości, które działają na obu rozmiarach ekranu.Podsumowując, mogę po prostu polecić zabawę z wartościami, sprawdzenie ich na różnych rozmiarach ekranu i mam nadzieję, że Apple rozwiąże ten problem.
źródło
Właśnie napotkałem podobny problem ze znikaniem komórek po przewijaniu UICollectionView na iOS 10 (nie mam problemów na iOS 6-9).
Podklasa UICollectionViewFlowLayout i przesłanianie layoutAttributesForElementsInRect metody: nie działa w moim przypadku.
Rozwiązanie było dość proste. Obecnie używam instancji UICollectionViewFlowLayout i ustawiam zarówno itemSize, jak i aestItemSize (wcześniej nie używałem oszacowanego rozmiaru) i ustawiam go na niezerowy rozmiar. Rzeczywisty rozmiar jest obliczany w collectionView: layout: sizeForItemAtIndexPath: metoda.
Usunąłem również wywołanie metody invalidateLayout z layoutSubviews, aby uniknąć niepotrzebnych przeładowań.
źródło
Właśnie doświadczyłem podobnego problemu, ale znalazłem zupełnie inne rozwiązanie.
Używam niestandardowej implementacji UICollectionViewFlowLayout z przewijaniem poziomym. Tworzę również niestandardowe lokalizacje ramek dla każdej komórki.
Problem, jaki miałem, polegał na tym, że [super layoutAttributesForElementsInRect: rect] w rzeczywistości nie zwracał wszystkich atrybutów UICollectionViewLayoutAttributes, które powinny być wyświetlane na ekranie. W przypadku wywołań [self.collectionView reloadData] niektóre komórki byłyby nagle ustawiane jako ukryte.
Skończyło się na utworzeniu NSMutableDictionary, który buforował wszystkie atrybuty UICollectionViewLayoutAttributes, które widziałem do tej pory, a następnie zawierał wszystkie elementy, o których wiem, że powinny zostać wyświetlone.
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { NSArray * originAttrs = [super layoutAttributesForElementsInRect:rect]; NSMutableArray * attrs = [NSMutableArray array]; CGSize calculatedSize = [self calculatedItemSize]; [originAttrs enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes * attr, NSUInteger idx, BOOL *stop) { NSIndexPath * idxPath = attr.indexPath; CGRect itemFrame = [self frameForItemAtIndexPath:idxPath]; if (CGRectIntersectsRect(itemFrame, rect)) { attr = [self layoutAttributesForItemAtIndexPath:idxPath]; [self.savedAttributesDict addAttribute:attr]; } }]; // We have to do this because there is a bug in the collection view where it won't correctly return all of the on screen cells. [self.savedAttributesDict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSArray * cachedAttributes, BOOL *stop) { CGFloat columnX = [key floatValue]; CGFloat leftExtreme = columnX; // This is the left edge of the element (I'm using horizontal scrolling) CGFloat rightExtreme = columnX + calculatedSize.width; // This is the right edge of the element (I'm using horizontal scrolling) if (leftExtreme <= (rect.origin.x + rect.size.width) || rightExtreme >= rect.origin.x) { for (UICollectionViewLayoutAttributes * attr in cachedAttributes) { [attrs addObject:attr]; } } }]; return attrs; }
Oto kategoria dla NSMutableDictionary, w której UICollectionViewLayoutAttributes są zapisywane poprawnie.
#import "NSMutableDictionary+CDBCollectionViewAttributesCache.h" @implementation NSMutableDictionary (CDBCollectionViewAttributesCache) - (void)addAttribute:(UICollectionViewLayoutAttributes*)attribute { NSString *key = [self keyForAttribute:attribute]; if (key) { if (![self objectForKey:key]) { NSMutableArray *array = [NSMutableArray new]; [array addObject:attribute]; [self setObject:array forKey:key]; } else { __block BOOL alreadyExists = NO; NSMutableArray *array = [self objectForKey:key]; [array enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *existingAttr, NSUInteger idx, BOOL *stop) { if ([existingAttr.indexPath compare:attribute.indexPath] == NSOrderedSame) { alreadyExists = YES; *stop = YES; } }]; if (!alreadyExists) { [array addObject:attribute]; } } } else { DDLogError(@"%@", [CDKError errorWithMessage:[NSString stringWithFormat:@"Invalid UICollectionVeiwLayoutAttributes passed to category extension"] code:CDKErrorInvalidParams]); } } - (NSArray*)attributesForColumn:(NSUInteger)column { return [self objectForKey:[NSString stringWithFormat:@"%ld", column]]; } - (void)removeAttributesForColumn:(NSUInteger)column { [self removeObjectForKey:[NSString stringWithFormat:@"%ld", column]]; } - (NSString*)keyForAttribute:(UICollectionViewLayoutAttributes*)attribute { if (attribute) { NSInteger column = (NSInteger)attribute.frame.origin.x; return [NSString stringWithFormat:@"%ld", column]; } return nil; } @end
źródło
Powyższe odpowiedzi u mnie nie działają, ale po pobraniu zdjęć wymieniłem
z
[self.yourCollectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
aby odświeżyć i poprawnie wyświetlać wszystkie komórki, możesz spróbować.
źródło
To może być trochę za późno, ale upewnij się, że ustawiasz atrybuty,
prepare()
jeśli to możliwe.Mój problem polegał na tym, że komórki układały się, a następnie pobierałem aktualizację
layoutAttributesForElements
. Spowodowało to efekt migotania, gdy pojawiły się nowe komórki.Przeniesienie całej logiki atrybutów do
prepare
, a następnie ustawienie ich wUICollectionViewCell.apply()
niej wyeliminowało migotanie i utworzyło gładką komórkę wyświetlającą masło 😊źródło