ReloadData is not working for a UICollectionView - swift

I would like to change my entier array used to created all my cells with a button and then reload my collection view, but it is not working. I've tried to reload the collection view into the main thread but it also not working
I've tried to reload the collection view into the main thread, or just using collectionView.reloadData() but it also not working
#IBAction func BicepsBtn(_ sender: Any) {
self.current = "Biceps"
Data = user.getMuscleDataChart(typeMuscle: current)
listMuscle = user.getListMuscle(typeMuscle: current)
collectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return listMuscle.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
let switchView = cell.viewWithTag(1000) as? UISwitch
let titleView = cell.viewWithTag(1001) as? UILabel
if let titleView = titleView, let switchView = switchView {
titleView.text = self.listMuscle[indexPath.row].label
titleView.textColor = self.listMuscle[indexPath.row].color
switchView.tag = indexPath.row
switchView.addTarget(self, action: #selector(yourFunc),
for: UIControl.Event.valueChanged)
}
return cell
}
Here is my current code, when the user is going to click on the Biceps button, the function will fetch all data about this muscle and then trying to reload.
Any idea ?
Thanks in advance

Related

Hero ViewController animation with collectionView - swift

I'm trying to present a view controller whenever I tap on a collection view cellwith the zoom effect.
As far as I know Hero framework works using HeroID's, you set the same id in the fromView and in the toView and the frameworks does the hard work for you.
I have set It up this way:
in viewcontroller1 :
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! CollectionViewCell
cell.heroID = "profheroid"
let viewcontroller2 = ViewController2()
viewcontroller2.configureController(with: arrayOfModels[indexPath.item])
viewcontroller2.heroModalAnimationType = .zoom
viewcontroller2.modalPresentationStyle = .fullScreen
self.navigationController?.present(viewcontroller2, animated: true, completion: nil)
}
and in viewcontroller2:
override func viewDidLoad() {
super.viewDidLoad()
view.heroID = "profheroid"
}
The problem happens whenever I tap on a collectionviewCell the presentation happens correctly but I see so many cells being presented at the same time.
I think this happens because cell.heroID = "profheroid" is applied to more cells at the same time.
How can I make sure that when the cell is presented the heroID's are only in the cell tapped and in the viewcontroller's view??
I think you must clear this heroID when cell is reused and after VC is presented.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
cell.heroID = nil // or empty
}
I think you must reset heroID to nil in cellForItemAt:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: YourCollectionViewCell.description(), for: indexPath) as? YourCollectionViewCell else {
return UICollectionViewCell()
}
cell.heroID = nil
return cell
}
Reset all visible cell's heroID to nil, and only set heroID for cell selected with value before present:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.visibleCells.forEach { cell in
cell.heroID = nil //reset heroID
}
guard let cell = collectionView.cellForItem(at: indexPath) else { return }
cell.heroID = "profheroid"
let viewcontroller2 = ViewController2()
viewcontroller2.configureController(with: arrayOfModels[indexPath.item])
viewcontroller2.heroModalAnimationType = .zoom
viewcontroller2.modalPresentationStyle = .fullScreen
self.navigationController?.present(viewcontroller2, animated: true, completion: nil)
}

UICollectionViewCell is populated with previous cells data before new the cell's data loads, need to implement PrepareForReuse()

I have a problem with my UICollectionView, The problem is that if you scroll fast enough (not even that fast) the data that was in the cell before the reuse gets displayed for a second or two before the new data gets displayed.
This is the video of it happening for more context (youtube video link): https://youtu.be/I63hBuxBGI0
This is the code inside of the cellForItemAt:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let post = feedElements[indexPath.row] as? FeedPost {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! feedCollectionViewCell
cell.delegate = self
cell.post = post
cell.commentButton.tag = indexPath.row
// assigning all of the data
cell.captionLabel.text = post.caption
cell.locationLabel.text = post.location
cell.timeAgoLabel.text = post.timeAgoString
cell.setUpElements()
cell.prepareForReuse()
return cell
}
}
The code for inside of the numberOfRowsInSection:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return feedElements.count
}
I'm pretty sure what I need to implement is prepareForReuse() but I'm not sure exactly how to do that and couldn't find anything helpful online.
Thanks a lot!
You need to add prepareForReuse in feedCollectionViewCell class like this
class feedCollectionViewCell: UITableViewCell {
override func prepareForReuse() {
super.prepareForReuse()
// Reset your values here as you want ...
self.post = nil
self.commentButton.tag = 0
// assigning all of the data
self.captionLabel.text = nil
self.locationLabel.text = nil
self.timeAgoLabel.text = nil
}
}

collectionView cell not working in tapGestureRecognizer function

I want to change a cell label text when I click/tap on a collectionView cell.
I tried the following way, but this not working.
#objc func tap(_ sender: UITapGestureRecognizer) {
let location = sender.location(in: self.collectionView)
let indexPath = self.collectionView.indexPathForItem(at: location)
if let index = indexPath {
let subL = zoneDict?.sublevel[index.row]
if (subL?.sublevel.count)! > 0 {
DispatchQueue.main.async {
self.zoneDict = subL!
print("self.zoneDict --\(self.zoneDict!)")
let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "colViewCell", for: index) as! CollectionViewCell
cell.zoneNameLabel.text = self.zoneDict?.name // Cannot update the text label. It show the default value
print("zone name-- \(self.zoneDict?.name)") // Its print the result.
}
self.delegate?.selectedZoneWithCellItems(items: "cell")
}
}
}
I think when you tap collectionViewCell then iOS system default call function didSelectItemAtIndexPath of CollectionView so that you must handle default event selected cell by the way register UITapGestureRecognizer for your cell and after that you must set property of view (isUserInteractionEnabled = true).
For example: self.yourview.isUserInteractionEnabled = true
you can use this in the VC containing the collection view
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = segmentCollectionView.dequeueReusableCell(withReuseIdentifier: SegmentCellId, for: indexPath) as! CollectionViewCell
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(printHello))
cell.addGestureRecognizer(tapGesture)
return cell
}
#objc func printHello(){
print("Hello")
}
You can use its delegate method in this way to change the cell label text when clicked on cell: -> Here I am using two arrays to update the text of the label as an example:
//Variables that are used below.
let nameCapitalArr1 = ["ABC", "DFG", "EFG", "HIJ", "KLM", "NOP", "QRS", "TUV", "WXY", "Z"]
let nameSmallArr2 = ["abc", "dfg", "efg", "hij", "klm", "nop", "qrs", "tuv", "wxy", "z"]
var changeFlag: Bool = false
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return nameCapitalArr1.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "LabelTextCollectionViewCell", for: indexPath) as? LabelTextCollectionViewCell else { return UICollectionViewCell() }
cell.nameTextLabel.text = !changeFlag ? nameCapitalArr1[indexPath.row] : nameSmallArr2[indexPath.row]
return cell
}
/*That method is called when tapping on the cell and reload that particular cell and also change the label text.*/
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
changeFlag = !changeFlag
collectionView.reloadItems(at: [indexPath])
}
Output: -> Its reflect the cell text with capital to small array values while tapping on the cell with toggle effect.

How can we reload header view inside our collection view

I've been looking for a way to reload my collection view header. So I have a collection view header & a CollectionViewCell that only contains an image. Now when the cell is press, I would like to display the image in the header view without calling collectionView.reloadData(). This is how my didSelectItemAt & didDeselectItemAt method looks like.
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedImage = images[indexPath.item]
let imageCell = collectionView.cellForItem(at: indexPath) as! CollectionCell
imageCell.photoBackgroundView.backgroundColor = .red
collectionView.reloadData()
}
override func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let imageCell = collectionView.cellForItem(at: indexPath) as! ImagePickerCell
imageCell.photoBackgroundView.backgroundColor = .black
}
So when I select a cell the view turns red, when I deselect it the view turns black. This video here, shows how the behavior without reloading the collectionView. Now here is were I would like to reload the header view.
If I do use collectionView.reloadData(), this is the outcome. How would I be able to reload the header or the collectionView where the header view displays the selected cell image & turns red.
You can try like global instance for that. Like
class YourClass: UIViewController {
/// Profile imageView
var profileImageview = UIImageView()
}
In CollectionView cellforItem assign a imageview. Like
let imageCell = collectionView.cellForItem(at: indexPath) as! CollectionCell
profileImageview = imageCell.imageView
Then when every you selecting collectionViewCell
You can call a function to change a image of imageView. Like
func updateImage() {
profileImageview.image = UIImage()
}
Well I'm trying to understand why sometimes you cast the cell in CollectionCell and sometimes in ImagePickerCell, anyway try to change your functions in these
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! CollectionCell
cell?.photoBackgroundView.backgroundColor = .red
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! CollectionCell
cell?.photoBackgroundView.backgroundColor = .black
}

CollectionView populate at randomIndex in Swift

I have a colllectionView running successfully which grabs url image content from web link .I am trying to populate collectionView at random index once every time view loads.my try as below...
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.reloadData()
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath as IndexPath) as! Cell
let randomIndex = Int(arc4random_uniform(UInt32(apps.count)))
cell.app = apps[randomIndex] as? AppInfo
return cell
}
Above method reload the collectionView everytime page scrolls. I am trying to achieve reload once only...
Thanks in Advance....