Collection view cell, didSelectItem delegate - swift

i have a collectionView with images in cells and by tapping on the item i am deleting it
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5) {
if let cell = collectionView.cellForItem(at: indexPath) as? CollectionViewCell {
cell.image.center.x += 300 }
} completion: { Bool in
ImageModel.images.remove(at: indexPath.row)
collectionView.deleteItems(at: [indexPath])
}
}
I can delete 1,2,3 cells, but if i scroll it downside sometimes i see on cells that they already moved (like the method UIView.animate was used, but without completion of it) Why is it happens?

Related

Deleting cell in collectionView bug. image overlaid on image

I have a collectionView and deleting cells in it seems wrong.
https://giphy.com/gifs/9VIPAbXq8GScmDNiZa
As you can see when i tried to delete first cell, image overlaid on image. it happens randomly
DataSource for Cell
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCell.identifier, for: indexPath) as? CollectionViewCell else { return UICollectionViewCell() }
if let image = ImageModel.images[indexPath.row].image {
cell.configureCell(image: image)
}
return cell
}
Delegate for deleting
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5) {
if let cell = collectionView.cellForItem(at: indexPath) as? CollectionViewCell {
cell.image.center.x += 300 }
} completion: { Bool in
ImageModel.images.remove(at: indexPath.row)
collectionView.deleteItems(at: [indexPath])
collectionView.reloadData()
}
}
Delegate for downloading new Images
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
self.presenter?.fetchData()
}
Also i have cell config with reusable cell
override func prepareForReuse() {
super.prepareForReuse()
self.image.image = nil
self.image.center.x = 0
}
What can be wrong with cell?

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)
}

ReloadData is not working for a UICollectionView

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

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
}

Calling func(didSelectItemAt) while UIcollectionview is on scrolling

Currently I'm using UICollectionView with several cells in it. UICollectionView scrolls horizontally to move between the cells.
My question is : Is there any way to call func(didSelectItemAt) by clicking the cell while its UICollectionView is on scrolling?
Here is gif.
Right after dragging cell to left for scrolling, I click the cell continuously to call func(didSelectItemAt) but it get call only when scrolling is finished. Is it possible to func(didSelectItemAt) to be called instantly right after clicking cell while on scrolling?
Here is my code for collectionView delegate & dataSource.
extension CardViewController : UICollectionViewDelegate,UICollectionViewDataSource {
public func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return cardCount
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = cardCollectionView.dequeueReusableCell(withReuseIdentifier: "card", for: indexPath) as! CardCell
cell.isFront = cellsSelectedStatus[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = cardCollectionView.cellForItem(at: indexPath) as! CardCell
UIView.transition(with: cell, duration: 0.3, options: [.transitionFlipFromLeft,.allowUserInteraction], animations: nil, completion: nil)
cellsSelectedStatus[indexPath.row] = !(cellsSelectedStatus[indexPath.row])
cell.isFront = cellsSelectedStatus[indexPath.row]
print("did select")
}
Collectionview’s dataSource&delegate are called in viewDidLoad.
I know there is allowUserInteraction from UIViewAnimationOptions which allows to click view while its being animated. Is there smilier code for func(didSelectItemAt)?
There’s no networking & UIGestureRecognizers is attached to the cell or collectionview.
So far I've set
isUserInteractionEnabled,
isMultipleTouchEnabled,
allowsMultipleSelection to true for collectionView,
but it still behaves the same.
I’m using Swift3, Xcode9.
Thanks in advance.