Когда пользователи добавили или удалили фильтры в первой итерации моего
приложения Filter Chaining , обновленный массив пользовательских фильтров был передан в
экземпляр FiltersCollectionView, где просто вызывается
reloadData () в его
UICollectionView . Это работало нормально, но перехода не было, и новый фильтр внезапно появился.
Было бы лучше анимировать вставку или удалить и указать пользователю, посредством движения, как изменилась их коллекция фильтров. Как это сделать, было не сразу очевидно, и этот пост описывает технику, которую я использовал.
Внутри контроллера представления
методы deleteSelectedFilter () и
addNewFilter () обновляют свой
массив userDefinedFilters :
// deleteSelectedFilter userDefinedFilters = userDefinedFilters.filter({!($0 == previousFilter)}) // addNewFilter userDefinedFilters.insert(newFilter, atIndex: userDefinedFilters.count - 1)
и это, в свою очередь, устанавливает
userDefinedFilters свойство на
FiltersCollectionView через
didSet наблюдателя. При том , что изменения свойств,
FiltersCollectionView собственного «s
didSet наблюдатель на
userDefinedFilters смотрит на новой версии массива , чтобы увидеть , был ли добавлен элемент (т.е. длина
OldValue меньше , что новое значение) или удаляется (т.е. длину
OldValue больше, чем новое значение).
Выбор, добавление и удаление элементов в
UICollectionView использует
NSIndexPaths, а не, например, целочисленные индексы или элементы. Получение
NSIndexPath для определенного элемента требует промежуточного шага. Мое приложение всегда вставляет новые фильтры в предпоследнюю позицию в представлении коллекции, поэтому мне нужно найти
NSIndexPath для последней, кроме одной ячейки, и вызвать
insertItemsAtIndexPath () . Чтобы сделать это, я использую одно из расширений, которые
UICollectionView предоставляет
NSIndexPath — новый
метод init () :
init(forItem item: Int, inSection section: Int) -> NSIndexPath …and the implementation to get the required index path is and insert an item is: let insertIndexPath = NSIndexPath(forItem: oldValue.count - 1, inSection: 0) uiCollectionView.insertItemsAtIndexPaths([insertIndexPath])
Когда пользователь удаляет фильтр, приложение предполагает, что оно удаляет выбранный фильтр (более полная реализация будет сравнивать oldValue и userDefinedFilters, чтобы выяснить, что было удалено). Итак, в этом случае мне нужно вызвать deleteItemsAtSelectedPaths () для индексных путей выбранных элементов:
let deleteIndexPath = uiCollectionView.indexPathsForSelectedItems()[0] as NSIndexPath uiCollectionView.deleteItemsAtIndexPaths([deleteIndexPath])
А также добавление или удаление фильтров, оба эти множества
FilterCollectonView «s
selectedFilter собственности. При добавлении фильтра новый фильтр выбирается, а при удалении фильтра выбирается первый фильтр.
Внутри его
обозревателя didSet я прокручиваю выбранную ячейку, чтобы, если пользователь выбирает ячейку, которая находится за пределами экрана, она становится полностью видимой. В этом случае я хочу найти индекс выбранной ячейки внутри
userDefinedFilters , затем создать
NSIndexPath для этого индекса и, наконец,
selectItemAtIndexPath () в новом
NSIndexPath .
Для этого
наблюдатель didSet на
selectedFilter выглядит так:
var selectedFilter : UserDefinedFilter? { didSet { var selectedIndex : Int = -1 for (i: Int, filter: UserDefinedFilter) in enumerate(userDefinedFilters) { if filter == selectedFilter! { selectedIndex = i } } if selectedIndex != -1 { let selectedIndexPath = NSIndexPath(forItem: selectedIndex, inSection: 0) uiCollectionView.selectItemAtIndexPath(selectedIndexPath, animated: true, scrollPosition: UICollectionViewScrollPosition.CenteredHorizontally) } sendActionsForControlEvents(.ValueChanged) refresh() } }
Там у нас это есть: вместо того, чтобы клетки внезапно появлялись и исчезали, небольшая работа с
NSIndexPath и правильное использование
собственной поддержки вставки и удаления UICollectionView дает плавный переход.