#ios #swift #animation #uicollectionview
#iOS #swift #Анимация #uicollectionview
Вопрос:
У меня есть UISegmentControl, который я использую для переключения источника данных для UICollectionView. Источниками данных являются объекты разных типов.
Например, объекты могут выглядеть следующим образом
struct Student {
let name: String
let year: String
...
}
struct Teacher {
let name: String
let department: String
...
}
И в представлении, содержащем CollectionView, был бы код, подобный этому:
var students = [Student]()
var teachers = [Teachers]()
... // populate these with data via an API
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if(segmentControl.titleForSegment(at: segmentControl.selectedSegmentIndex) == "Students") {
return students?.count ?? 0
} else {
return teachers?.count ?? 0
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "personCell", for: indexPath) as! PersonCell
if(segmentControl.titleForSegment(at: segmentControl.selectedSegmentIndex)! == "Students") {
cell.title = students[indexPath.row].name
cell.subtitle = students[indexPath.row].year
} else {
cell.title = teachers[indexPath.row].name
cell.subtitle = teachers[indexPath.row].subject
}
return cell
}
@IBAction func segmentChanged(_ sender: AnyObject) {
collectionView.reloadData()
}
Это правильно переключает между двумя источниками данных, однако это не анимирует изменение. Я пробовал это:
self.collectionView.performBatchUpdates({
let indexSet = IndexSet(integersIn: 0...0)
self.collectionView.reloadSections(indexSet)
}, completion: nil)
Но это просто сбой (я думаю, это потому, что performBatchUpdates путается в том, что удалять и что добавлять).
Есть ли какой-нибудь простой способ заставить это работать, не имея отдельного массива, хранящего текущие элементы в CollectionView, или это единственный способ заставить это работать плавно?
Заранее большое спасибо!
Ответ №1:
Если пользовательский интерфейс вашей ячейки выглядит одинаково из разных источников данных, вы можете абстрагировать ViewModel от вашего источника данных, например:
struct CellViewModel {
let title: String
let subTitle: String
...
}
Затем каждый раз, когда вы получаете данные из API, динамически генерируйте ViewModel
var students = [Student]()
var teachers = [Teachers]()
... // populate these with data via an API
var viewModel = [CellViewModel]()
... // populate it from data above by checking currently selected segmentBarItem
if(segmentControl.titleForSegment(at: segmentControl.selectedSegmentIndex)! == "Students") {
viewModel = generateViewModelFrom(students)
} else {
viewModel = generateViewModelFrom(teachers)
}
Таким образом, вы всегда сохраняете один массив источников данных в своем UICollectionView.
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return viewModel?.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "personCell", for: indexPath) as! PersonCell
cell.title = viewModel[indexPath.row].title
cell.subtitle = viewModel[indexPath.row].subTitle
return cell
}
@IBAction func segmentChanged(_ sender: AnyObject) {
collectionView.reloadData()
}
Затем попробуйте performBatchUpdates:
self.collectionView.performBatchUpdates({
let indexSet = IndexSet(integersIn: 0...0)
self.collectionView.reloadSections(indexSet)
}, completion: nil)