2016-05-21 17 views
6

Wdrażam widok kolekcji, którego elementy mają rozmiar oparty na granicach widoku kolekcji. Dlatego też, gdy zmienia się rozmiar, na przykład z powodu obracania urządzenia, muszę unieważnić układ, aby zmienić rozmiar komórek, aby uwzględnić nowe ograniczenia widoku kolekcji. Zrobiłem to za pośrednictwem interfejsu API viewWillTransitionToSize.Prawidłowy sposób unieważnienia układu widoku kolekcji po zmianie rozmiaru

Działa to dobrze, dopóki użytkownik nie przedstawi kontrolera widoku modalnego nad kontrolerem widoku, który zawiera widok kolekcji, obraca urządzenie, a następnie je odrzuca. W takim przypadku rozmiar elementu nie został zaktualizowany do odpowiedniego rozmiaru. viewWillTransitionToSize jest wywoływane, a układ jest unieważniany zgodnie z oczekiwaniami, ale ograniczenia widoku kolekcji nadal są starymi wartościami. Na przykład podczas obracania z pionowej na poziomą wartość graniczna widoku kolekcji nadal ma wysokość większą niż szerokość. Nie jestem pewien, dlaczego tak jest, ale zastanawiam się, czy to najlepszy sposób na unieważnienie zmiany rozmiaru? Czy istnieje lepszy sposób na zrobienie tego?

Próbowałem również podklasy UICollectionViewFlowLayout i przesłonięcie shouldInvalidateLayoutForBoundsChange, aby zwrócić YES, ale z jakiegoś powodu to nie działa nawet obracanie bez prezentacji modalnej. Nie używa też właściwych granic widoku kolekcji.

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(nonnull id<UIViewControllerTransitionCoordinator>)coordinator 
{ 
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; 

    [self.collectionView.collectionViewLayout invalidateLayout]; 

    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> __nonnull context) { 
     [self.collectionView.collectionViewLayout invalidateLayout]; 
    } completion:^(id<UIViewControllerTransitionCoordinatorContext> __nonnull context) { 
     //finished 
    }]; 
} 

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewFlowLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
    //collectionView.bounds.size is not always correct here after invalidating layout as explained above 
} 

Próbowałem również jego invaliding w bloku zakończenia, ale nadal nie używa prawidłowych granic widoku kolekcji.

Jeśli ponownie unieważnię układ w viewWillAppear, to używa on prawidłowych granic widoku kolekcji, co rozwiązuje problem z obracaniem się z modalnie przedstawionym kontrolerem widoku. Ale to nie powinno być konieczne, być może istnieją inne sytuacje, w których nie zostanie to odpowiednio dobrane.

+0

Czy obejrzałeś http://stackoverflow.com/questions/29023473/uicollectionview-invalidate-layout-on-bounds-changes? – ozgur

+0

@ozgur Już wypróbowałem, co jest w tej odpowiedzi tak, jak wyjaśniono powyżej – Joey

+0

Czy jesteś pewien, że nie aktualizujesz niczego w 'viewWillAppear()'? W opisanym scenariuszu (zmieniasz orientację, gdy kontroler modalny jest zakończony), gdy kontroler widoku modalnego jest odrzucany, możesz otrzymać ramkę z * poprzednim * orientacją w 'viewWillAppear()', i poprawną ramkę w 'viewDidAppear() '. Więc to, co zwykle działa dla mnie, to tylko aktualizacja układu w 'viewWillTransitionToSize'. –

Odpowiedz

13

Wiem, jaki jest problem. Kiedy wywołujesz invalidateLayout wewnątrz animateAlongsideTransition (albo w bloku animacji, albo w bloku kończącym), to w rzeczywistości nie przeliczy on układu, jeśli jest dostępny kontroler widoku modalnego przedstawiony na pełnym ekranie (ale będzie, jeśli jest nad bieżącym kontekstem). Ale unieważni to, jeśli unieważnisz go poza blokiem animacji, tak jak to robiłem. W tym czasie jednak widok kolekcji nie zawierał nowego rozmiaru, co wyjaśnia, dlaczego widziałem dawną wartość dla jego granic. Przyczyną tego zachowania jest invalidateLayout, ponieważ nie powoduje natychmiastowego ponownego obliczenia układu - jest zaplanowane, aby nastąpiło podczas następnego przejścia układu. To przejście układu nie występuje, gdy na pełnym ekranie znajduje się modalnie przedstawiony kontroler widoku. Aby wymusić przejście układu, po prostu wywołaj [self.collectionView layoutIfNeeded]; natychmiast po [self.collectionView.collectionViewLayout invalidateLayout];, nadal w bloku animateAlongsideTransition. Spowoduje to ponowne obliczenie układu zgodnie z oczekiwaniami.

+0

Twoja odpowiedź zrobiła mój dzień. Wielkie dzięki! –

Powiązane problemy