При вставке нескольких пользовательских дополнительных представлений в виде коллекции с существующими дополнительными представлениями, используя подкласс UICollectionViewFlowLayout, появится представление коллекции для создания сглаженных анимаций или иначе неправильно обрабатывать вставки.
Вставка одного дополнительного представления ведет себя так, как ожидалось, но вставка двух дополнительных представлений сразу приводит к очевидному визуальному сбою, и вставка множества дополнительных представлений сразу (например, 4+) ухудшает сбой. (iOS 10.2, iOS 9.3, Swift 3, Xcode 8.2.1)
Здесь демонстрация:
Вы можете воспроизвести проблему, используя этот примерный проект. В этом упрощенном примере для каждого элемента есть одно дополнительное представление, а два элемента (с двумя дополнительными представлениями) вставляются во время каждого обновления пакета. В моем реальном проекте у меня меньше дополнительных представлений, чем элементов, и я использую другие возможности компоновки потока.
Мое лучшее предположение заключается в том, что что-то вызывает представление коллекции, путающее пути указателя или атрибуты макета, соответствующие существующим/вставленным дополнительным представлениям. Если это окажется ошибкой в одном из классов Apple, я был бы очень благодарен за ваш самый элегантный способ обхода.
Попытки решения
Я пробовал и дважды проверял каждое из следующих:
-
Внедрение
indexPathsToInsertForSupplementaryView(ofKind:)
- насколько я могу судить, это просто, и мой реализация возвращает правильные пути указателей. Представления всегда вставлены. Для дополнительных представлений заголовка и нижнего колонтитула UICollectionViewFlowLayout, похоже, возвращает отсортированный массив указательных путей, но сортировка массива для меня не меняла. -
Предоставление исходных и окончательных атрибутов макета -calling
super
для этих методов, похоже, возвращает правильные фреймы, поэтому неясно, какие корректировки (если они есть) могут быть сделаны в первоначальные или окончательные атрибуты макета для решения проблемы. Но см. Третье любопытство, указанное ниже. -
Недействительность макета. Кажется, не имеет никакого значения, будет ли макет вручную аннулирован полностью или частично до, во время или после
performBatchUpdates()
или вообще. -
Пользовательские пути указателей. Невозможно, чтобы пути индекса для дополнительных элементов не соответствовали элементам указателей элемента, насколько я могу судить, и, несмотря на документацию об обратном, UICollectionViewFlowLayout выйдет из строя (путем запроса атрибутов компоновки для несуществующих путей указателей), если дополнительные элементы такого же типа не будут последовательно пронумерованы из 0. Я предполагаю, что представление коллекции и/или объект макета могут вычислять новые пути индекса при вставке элементов или удаляется (т.е. путем увеличения или уменьшения свойства
item
указательного пути). Поэтому создание произвольных путей индекса не является вариантом.
При отладке заметили курьезы
-
Визуальные сбои специфичны для дополнительных представлений и не встречаются для вставленных элементов, даже если указательные пути и фреймы одинаковы для обоих.
-
Отладка иерархии представлений показывает, что, хотя фреймы вставленных дополнительных представлений верны, фреймы некоторых существующих дополнительных представлений неверны. Это так, несмотря на то, что кадры, возвращаемые объектом макета для существующих представлений на этих указательных путях, выглядят правильно.
-
При вставке нескольких дополнительных представлений вызовы, сделанные представлением коллекции для первоначальных и окончательных атрибутов макета, выглядят неуравновешенными. То есть атрибуты первоначальной компоновки запрашиваются несколько раз для одного и того же пути указателя (и, естественно, одни и те же атрибуты возвращаются каждый раз), а запросов конечного макета меньше. Кроме того, для некоторых существующих дополнительных представлений первоначальные и окончательные атрибуты макета никогда не запрашиваются вообще. Я нахожу это подозрительным. Это заставляет меня думать, что представление коллекции каким-то образом путает дополнительные представления и/или пути индекса до и после обновления.
-
Адреса памяти для экземпляров IndexPath, созданных моим кодом Swift, поразительно отличаются от экземпляров NSIndexPath, созданных внутри UICollectionView и UICollectionViewFlowLayout. Первые всегда разные (как и ожидалось), в то время как последние кажутся одинаковыми между запусками (например, [0, 0], [0, 1] и [0, 2] всегда находятся в
0xc000000000000016
,0xc000000000200016
и0xc000000000400016
). В Swift IndexPath подключается к NSIndexPath, но первый тип значения, тогда как последний является ссылочным типом. NSIndexPath также использует тегированные указатели. Существует отдаленная возможность того, что эти два были несовершенно мосты и/или что классы представления коллекции полагаются внутренне на поведение NSIndexPath каким-то образом, что приводит к путанице в указателе, очевидной здесь. Я не знаю, как проверить это или принять это дальше.
Похожие вопросы
Следующие вопросы могут быть связаны, хотя ни один из ответов не работал у меня:
-
Как можно добавить или удалить дополнительные представления UICollectionView
-
layoutAttributesForSupplementaryViewOfKind: atIndexPath: пропускает неправильную indexPath
-
Дополнительные представления UICollectionView не будут отображаться "в" или "вне"
-
UICollectionView Украшение и дополнительные виды не могут быть перемещены
Проблема также может быть связана с этот отчет об ошибках в Open Radar. Примерный проект, сопровождающий этот отчет, слишком сложный, чтобы принести много пользы.
Техническая поддержка Apple
После публикации этого вопроса я отправил Apple сообщение о технической поддержке. Поддержка Apple Developer ответила следующим образом:
Наши инженеры рассмотрели ваш запрос и определили, что это лучше всего будет обрабатывать как отчет об ошибке.
Пожалуйста, отправьте полный отчет об ошибке, касающийся этой проблемы, используя инструмент "Отчет об ошибках" в https://developer.apple.com/bug-reporting/.
...
Мы провели некоторое время, исследуя возможность обходного пути и, к сожалению, пришли с пустыми руками. Пожалуйста, следуйте за своей ошибкой. Если мы найдем возможность какого-то обходного пути в будущем, мы продолжим. Извините, у меня нет новостей.
Если у вас возникла эта проблема, дублируйте rdar://30510010.