Working with UIViewRepresentable and collection view, got stuck when its comes to reload() collection view after iterating, how to reload collection view in UIViewRepresentable when performing iterate through data? func updateUIView doesn't do the work.
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)
}
}
}
Dealing with this right now, only way i was able to make a reloadData, was creating a reference inside my Coordinator class and pass it on creation:
context.coordinator.collectionView = collectionView
From there you can make the call to reloadData(), pretty sure there are more elegant ways to work this though.
EDIT: Answering Request to expand on my approach.
Let's say you have a coordinator like this:
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()
}
}
So when you create your UIViewRepresentable, pass the collectionView reference:
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"])
}
}
I'm sorry, if the code is not 100% perfect, had to take it from a project with NDA and didn't test with the deleted properties.
UIViewRepresentable is just a wrapper. you have to make ur model as Observable. then it will automatically update whenever any change in data.
All you need to do is, make your data
property in VideoCollectionView
as:
@Binding var data: VideoViewModel
Now once you update data, you update view will reload collectionView. Explanation: Your data property(value type) should be a Binding property as the Coordinator
depends on that. When you init Coordinator with self, you are passing the old instance of data property. Changing it to binding allow it to be mutated.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.