2017-01-24 43 views
25

Podczas wstawiania wielu niestandardowych widoków dodatkowych w widoku kolekcji z istniejącymi dodatkowymi widokami, przy użyciu podklasy UICollectionViewFlowLayout, widok kolekcji wydaje się tworzyć animacje z załamaniem lub w inny sposób nie obsługuje poprawnie wstawień.Usterka animacji układu podczas wstawiania wielu niestandardowych widoków dodatkowych

Wstawianie jednego dodatkowego widoku zachowuje się zgodnie z oczekiwaniami, ale wstawienie dwóch dodatkowych widoków od razu powoduje oczywisty błąd wizualny, a wstawienie wielu dodatkowych widoków jednocześnie (na przykład 4+) pogarsza błąd. (10.2 iOS, iOS 9.3, Swift 3, Xcode 8.2.1)

Oto demonstracji:

Animation showing two items and two supplementary views being inserted into a collection view with a simple flow layout.

można odtworzyć problem za pomocą this sample project. W tym uproszczonym przykładzie istnieje jeden dodatkowy widok dla każdej pozycji, a dwie pozycje (z dwoma dodatkowymi widokami) są wstawiane podczas każdej aktualizacji partii. W moim prawdziwym projekcie mam mniej widoków dodatkowych niż elementów i korzystam z innych funkcji układu przepływu.

Moje najlepsze przypuszczenie jest takie, że coś powoduje widok kolekcji w celu wprowadzenia w błąd ścieżek indeksu lub atrybutów układu odpowiadających istniejącym/wstawionym dodatkowym widokom. Jeśli okaże się, że jest to błąd w jednej z klas Apple'a, byłbym bardzo wdzięczny za twoje najbardziej eleganckie obejście.

usiłowania rozwiązania

Próbowałem i dwukrotnie sprawdzane każdy z następujących czynności:

  • Wdrażanie indexPathsToInsertForSupplementaryView(ofKind:) -tak ile mogę powiedzieć, to jest proste i moja implementacja zwraca poprawne ścieżki indeksu. Widoki są zawsze wstawiane. W przypadku dodatkowych widoków nagłówka i stopki wydaje się, że UICollectionViewFlowLayout zwraca uporządkowaną tablicę ścieżek indeksu, ale sortowanie tablicy nie ma dla mnie żadnej różnicy.

  • Zapewnienie układ początkowy i końcowy atrybuty -calling super dla tych metod wydaje się powrót poprawnych ramek, więc to nie jest oczywiste, co korekty (jeśli w ogóle) może być wykonana z układem początkowym lub końcowym atrybuty, aby rozwiązać problem. Ale zobacz trzecią ciekawość zanotowaną poniżej.

  • Unieważnienie układ -to wydaje się mieć żadnego znaczenia w ogóle, czy układ jest ręcznie unieważniony w całości lub w części przed, w trakcie lub po performBatchUpdates(), albo w ogóle.

  • niestandardowe ścieżki indeksowe -Mimo ścieżki indeksu dla elementów uzupełniających nie muszą odpowiadać ścieżek indeks towaru, o ile mogę powiedzieć, a mimo dokumentacji przeciwnego UICollectionViewFlowLayout padnie (poprzez zwrócenie się do atrybutów układ nieistniejące ścieżki indeksu), chyba że dodatkowe elementy tego samego rodzaju są ponumerowane kolejno od 0. Zakładam, że w ten sposób widok kolekcji i/lub obiekt układu jest w stanie obliczyć nowe ścieżki indeksu po wstawieniu lub usunięciu elementów (np. lub dekrementowanie właściwości ścieżki indeksu). Zatem tworzenie dowolnych ścieżek indeksu nie jest opcją.

Ciekawostki zauważył podczas debugowania

  1. usterki wizualne są specyficzne dla dodatkowych poglądów i nie występują na wstawianych elementów, nawet gdy ścieżki i ramki indeksu są takie same dla obu stron.

  2. Po debugowaniu hierarchii widoków okazuje się, że ramki wstawionych widoków dodatkowych są poprawne, ale ramki niektórych istniejących widoków dodatkowych nie są poprawne. Dzieje się tak pomimo faktu, że ramki zwrócone przez obiekt układu dla istniejących widoków na tych ścieżkach indeksu wydają się poprawne.

  3. Podczas wstawiania wielu dodatkowych widoków połączenia wykonane przez widok kolekcji dla początkowych i końcowych atrybutów układu wydają się być niezbalansowane. Oznacza to, że początkowe atrybuty układu są wymagane wiele razy dla tej samej ścieżki indeksu (i, naturalnie, te same atrybuty są zwracane za każdym razem), a liczba zaproszeń do ostatecznych atrybutów układu jest mniejsza. Co więcej, w przypadku niektórych istniejących widoków dodatkowych początkowe i końcowe atrybuty układu nigdy nie są wymagane. Uważam to za podejrzane. Prowadzi mnie to do przekonania, że ​​widok kolekcji jest mylący z dodatkowymi widokami i/lub ścieżkami indeksu przed aktualizacją i po niej.

  4. Adresy pamięci dla instancji IndexPath utworzonej przez mój kod Swift są uderzająco różne od instancji NSIndexPath utworzonej wewnętrznie przez UICollectionView i UICollectionViewFlowLayout. Te pierwsze są zawsze różne (zgodnie z oczekiwaniami), podczas gdy te drugie wydają się identyczne między uruchomieniami (np. [0, 0], [0, 1] i [0, 2] są zawsze pod 0xc000000000000016, 0xc000000000200016 i 0xc000000000400016). W Swift, IndexPath jest zmostkowany do NSIndexPath, ale the former is a value type whereas the latter is a reference type. NSIndexPath również uses tagged pointers. Istnieje odległa możliwość, że oba zostały niedokładnie zmostkowane i/lub że klasy widoku kolekcji polegają wewnętrznie na zachowaniu NSIndexPath w pewien sposób, który powoduje tutaj widoczne zamieszanie ścieżki indeksu. Nie wiem, jak to przetestować lub zrobić to dalej.

Podobne pytania

Poniższe pytania mogą być związane, chociaż żadna z odpowiedzi pracował dla mnie:

Problem może być również związane z this bug report na Open Radar. Przykładowy projekt towarzyszący temu sprawozdaniu jest nieco zbyt skomplikowany, aby mógł być przydatny.

Pomoc techniczna firmy Apple

Po wysłaniu na to pytanie, ja przedstawiła pomocy technicznej incydent Apple.Dział wsparcia dla programistów Apple odpowiedział w następujący sposób:

Nasi inżynierowie sprawdzili Twoją prośbę i stwierdzili, że najlepiej będzie, gdy zostanie to potraktowane jako zgłoszenie błędu.

Prześlij pełny raport o błędzie dotyczący tego problemu, korzystając z narzędzia do zgłaszania błędów pod numerem https://developer.apple.com/bug-reporting/.

...

Spędziliśmy trochę czasu na zbadanie możliwości obejścia i niestety mają pochodzić z pustymi rękami. Proszę uzupełnij swój błąd. Jeśli odkryjemy możliwość obejścia tego problemu w przyszłości, wyciągniemy rękę. Przepraszam, nie mam lepszych wiadomości.

Jeśli wystąpi ten problem, należy zduplikować numer rdar://30510010.

+0

Wygląda na to, że jest to jeden z błędów UICollectionView. –

+0

Spróbuj użyć zależności blokowych (implementacja obietnic) z biblioteki Śruby, aby powiązać jedną wstawkę z kolejną. Powinno to zapobiec jednoczesnemu wprowadzeniu usterki i wyglądać bardziej naturalnie. – jarryd

Odpowiedz

2

Poniżej jest wyjście CustomCollectionViewController plików indexPath pozycji Wiersz jest cellForItemAt indexPath i Row zapasowy jest dla viewForSupplementaryElementOfKind.

enter image description here

Jak widać cellForItemAt jest prawidłowo zwrotu indexpath.item ale w viewForSupplementaryElementOfKind nie wraca oczekiwaną odpowiedź. Nie otrzymałem do tej pory powodu do uaktualnienia, jeśli wkrótce otrzymam aktualizację.

W celu ponownego rozwiązania problemu można sobie poradzić z tablicą, dodając w niej nowe dane i ponownie wczytując metodę collectionView zamiast indeksu IndexPath.

+0

Dziękujemy za zbadanie nieporozumień dotyczących ścieżek indeksu. Niestety, 'reloadData()' nie zapewnia animacji wstawiania. – jamesk

+0

@jamesk Tak, masz prawo doładowania bez animacji, ale może rozwiązać ten błąd. Jak zauważyłem w 3 wstawieniu komórki dodatkowe "0,1,2" zostało wstawione poprawnie, ale zbiegła kolejność, ale w UI pojawiło się w poprawnej formie.Po wstawieniu trzeciej komórki następuje 'viewForSupplementaryElement' i dodaje jeden dodatkowy w indeksie 4, jak pokazano na powyższym rysunku. Nie dostałem powodu od wczoraj. Jeśli wstawię 4 wiersze to samo stanie się na indeksie 6. Nadal szukam. Jeśli dostanę powód, wyzywam się z entuzjazmem. Nadzieja też na odwrót. :) –

1

Nie jestem pewien, czy mam poprawne rozwiązanie początkowego problemu, ale miałem taki sam problem jak w odpowiedzi z @agent_stack.

Jeśli masz układ widoku niestandardowym Collection (podklasa UICollectionViewLayout lub podklasy UICollectionViewFlowLayout) i dodać swój własny pogląd uzupełniającego następnie trzeba zastąpić dodatkową metodę: indexPathsToInsertForSupplementaryView(ofKind elementKind: String)

Widok kolekcja nazywa tę metodę za każdym razem, gdy dodasz komórki lub sekcje do widoku kolekcji. Implementacja tej metody daje Twojemu obiektowi układu możliwość dodania nowych dodatkowych widoków w celu uzupełnienia dodatków.

Zrobiłem własne CollectionViewFlowLayout i dopiero po dodaniu tej metody w połączeniu wszystko jest animowane tak jak powinno!

override func prepare(forCollectionViewUpdates updateItems: [UICollectionViewUpdateItem]) { 
    super.prepare(forCollectionViewUpdates: updateItems) 

    // Prepare update by storing index path to insert 
    // ──────────────────────────────────────────────────────────── 

    // IMPORTANT: Item vs. Section Update 
    // 
    // An instance of UICollectionViewUpdateItem can represent either an item or a section update, 
    // and the only way to tell which is that update items which represent section updates contain 
    // index paths with a valid section index and NSNotFound for the item index, while update items 
    // that represent item updates contain index paths with valid item indexes. 
    // 
    // This appears to be completely undocumented by Apple, but it is absolutely consistent behavior. 

    // https://www.raizlabs.com/blog/2013/10/animating_items_uicollectionview/ 

    var indexPaths = [IndexPath]() 

    for updateItem in updateItems { 

     switch updateItem.updateAction { 

     case .insert: 

      // If it is a section update then convert NSNotFound to zero. 
      // In our case a section update always has only the first item. 

      if var indexPath = updateItem.indexPathAfterUpdate { 
       if indexPath.item == NSNotFound { indexPath.item = 0 } 
       indexPaths.append(indexPath) 
      } 

     default: 
      break 
     } 
    } 

    indexPathsToInsert = indexPaths 
} 

override func indexPathsToInsertForSupplementaryView(ofKind elementKind: String) -> [IndexPath] { 

    // Extra add supplementary index paths 
    // ──────────────────────────────────────────────────────────── 

    // The collection view calls this method whenever you add cells or sections to the collection view. 
    // Implementing this method gives your layout object an opportunity to add new supplementary views 
    // to complement the additions. 

    // http://stackoverflow.com/a/38289843/7441991 

    switch elementKind { 

    case UICollectionElementKindDateSeparator: 
     return indexPathsToInsert 

    case UICollectionElementKindAvatar: 
     return indexPathsToInsert 

    default: 
     // If it is not a custom supplementary view, return attributes from flow layout 
     return super.indexPathsToInsertForSupplementaryView(ofKind: elementKind) 
    } 
} 

Zapraszam do kontaktu ze mną, jeśli masz jakieś pytania! :)