Как перезагрузить collectionview в UIViewRepresentable SwiftUI
## Как перезагрузить представление коллекции в UIViewRepresentable ##
Работая с UIViewRepresentable и представлением коллекции, застрял, когда дело доходит до представления коллекции reload() после итерации, как перезагрузить представление коллекции в UIViewRepresentable при выполнении итерации по данным? func updateUIView не работает.
struct VideoCollectionView: UIViewRepresentable {
var data: VideoViewModel
@Binding var search: String
var dataSearch: [VideoPostModel] {
if search.isEmpty {
return data.postsSearch
}else{
let d = data.postsSearch.filter {$0.artistname.localizedStandardContains(search)}
return d
}
}
var didSelectItem: ((_ indexPath: IndexPath)->()) = {_ in }
var didSelectObject: ((_ boject: VideoPostModel)->()) = {_ in }
func makeUIView(context: Context) -> UICollectionView {
let reuseId = "AlbumPrivateCell"
let collection :UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.sectionHeadersPinToVisibleBounds = true
let collectionV = UICollectionView(frame: .zero, collectionViewLayout: layout)
layout.scrollDirection = .vertical
collectionV.translatesAutoresizingMaskIntoConstraints = false
collectionV.backgroundColor = .clear
collectionV.dataSource = context.coordinator
collectionV.delegate = context.coordinator
collectionV.register(AlbumPrivateCell.self, forCellWithReuseIdentifier: reuseId)
return collectionV
}()
return collection
}
func updateUIView(_ collectionView: UICollectionView, context: UIViewRepresentableContext<VideoCollectionView>) {
print("updateUIView updateUIView")
print(search)
collectionView.reloadData()
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
private var parent: VideoCollectionView
init(_ albumGridView: VideoCollectionView) {
self.parent = albumGridView
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.parent.dataSearch.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "AlbumPrivateCell", for: indexPath) as! AlbumPrivateCell
cell.data = self.parent.dataSearch[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let post = self.parent.dataSearch[indexPath.item]
parent.didSelectItem(indexPath)
parent.didSelectObject(post)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.width
let height = collectionView.frame.height/2
return CGSize(width: width, height: height)
}
}
}
3 ответа
Разбираясь с этим прямо сейчас, я смог создать reloadData только таким образом, чтобы создать ссылку внутри моего класса координатора и передать ее при создании:
context.coordinator.collectionView = collectionView
Оттуда вы можете вызвать reloadData(), хотя есть более элегантные способы сделать это.
РЕДАКТИРОВАТЬ: отвечая на запрос о расширении моего подхода.
Допустим, у вас есть такой координатор:
class CoordinatorItemPicturesView: NSObject, UICollectionViewDataSource, UICollectionViewDelegate {
// MARK: - Properties
var collectionView: UICollectionView!
var elements = [String]()
init(elements:[String]) {
self.elements = elements
}
// MARK: UICollectionViewDataSource
func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int {
return elements.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
return UICollectionViewCell()
}
}
Поэтому, когда вы создаете свой UIViewRepresentable, передайте ссылку на collectionView:
struct ItemPicturesView: UIViewRepresentable {
func makeUIView(context: UIViewRepresentableContext<ItemPicturesView>) -> UICollectionView {
/// Set Context, cells, etc
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
collectionView.backgroundColor = .clear
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.dataSource = context.coordinator
collectionView.delegate = context.coordinator
collectionView.isScrollEnabled = true
// --- Right here
context.coordinator.collectionView = collectionView
return collectionView
}
func updateUIView(_ uiView: UICollectionView, context _: Context) {
UIView.animate(withDuration: 1.0) {
uiView.frame = uiView.frame
uiView.reloadData()
}
}
func makeCoordinator() -> CoordinatorItemPicturesView {
CoordinatorItemPicturesView(elements:["Element One", "Element Two"])
}
}
Прошу прощения, если код не идеален на 100%, пришлось взять его из проекта с NDA и не тестировать с удаленными свойствами.
UIViewRepresentable - это просто оболочка. вы должны сделать модель ur как наблюдаемую. тогда он будет автоматически обновляться при любом изменении данных.
Все, что вам нужно сделать, это сделать свой data
собственность в VideoCollectionView
в качестве:
@Binding var data: VideoViewModel
Теперь, когда вы обновите данные, вы обновите представление, перезагрузите collectionView.
Explanation: Свойство данных (тип значения) должно быть свойством привязки в качествеCoordinator
зависит от этого. Когда вы инициализируете координатор с помощью self, вы передаете старый экземпляр свойства данных. Изменение его на привязку позволяет его мутировать.