Collection view cell slow detect selected item in swift - ios

I'm putting the collection view into table view cell and I made it can display on the cell but when I want to select the collection cell (to change the color or print cell number), the select function is not working, I need to tap the cell many time to make it selected. Why the cell slow detect the selected item? What code will affect the cell to be selected?
This is the code for select the collection cell
override func awakeFromNib() {
super.awakeFromNib()
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
let width = UIScreen.main.bounds.width
layout.scrollDirection = .vertical
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.itemSize = CGSize(width: width/5, height: width/4)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
collectionView?.collectionViewLayout = layout
collectionView?.delaysContentTouches = false
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CategoryCollectionViewCell
cell.cateImg.image = imageName[indexPath.row]
cell.cateLabel.text! = nameArray[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) as? CategoryCollectionViewCell {
cell.cateImg.image = imageName2[indexPath.row]
print("collectionViewCell selected \(indexPath)")
}
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
if let cell = collectionView.cellForItem(at: indexPath) as? CategoryCollectionViewCell {
cell.cateImg.image = imageName[indexPath.row]
}
}
Project zip link:
https://www.dropbox.com/s/y10dgp3q61pi5n1/Finnciti.zip?dl=0
problem on AddViewCell.swift

Try to deselect this checkmark in Collection View properties

I fixed the problem after delete this code on AddViewController.
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(AddExpenseVC.dismissKeyboard))
view.addGestureRecognizer(tap)
#objc func dismissKeyboard() {
view.endEditing(true)
}

In AddViewController you are adding gesture recognizer to the view, which make every user gesture to be detected by the tap recognizer. You can remove this gesture:
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(AddViewController.dismissKeyboard))
For dismissing keyboard you can implement tebleView delegate method:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
dismissKeyboard()
}

Related

how to convert a collection view to circular icarousel in swift

I want to show cells in collection view like in circular list, means that after the last cell of the collection view, on scrolling the collection view shows the first cell again, like circular linklist
I have tried using icrousel, but as icarosuel deals with views only, I don't want to finish the collection view completely and start again with icarousel, so is there any way I can make me collection view circular
this is my collectionView code
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell =
collectionView.dequeueReusableCell(withReuseIdentifier:
"CellName", for: indexPath as IndexPath) as! CellName
let gigModel = self.datasoruce?[indexPath.row]
cell.lblTitle.text = gigModel?.title
cell.btnPrice.setTitle(gigModel?.getPriceAccordingToGigType(),
for: .normal)
cell.itemImageView.sd_setImage(with: URL(string:
(gigModel?.getPhotoPath())!), placeholderImage:
UIImage.init(named: "place_holder"))
cell.itemImageView.layer.cornerRadius = 10.0
if Utilities.isValidString(object: gigModel?.adminId as
AnyObject) {
cell.btnStar.isHidden = false
}
else {
cell.btnStar.isHidden = true
}
return cell
}
and I want this to be circular list.
I tried to create sample project and it was pretty simple, here is example code how you can implement "infinite" scroll
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var array: [Any] = [0,1,2,3,4,5,6,7,8,9]
override func viewDidLoad() {
super.viewDidLoad()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return Int(Int16.max) // Int.max cause crash
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MyCell
let correctIndex = indexPath.row >= array.count ? indexPath.row % array.count : indexPath.row
cell.nameLabel.text = "\(array[correctIndex])"
return cell
}
}
Hope it will help you
//Use Below code to get next cell.
func scrollToNextCell(){
//get Collection View Instance
let collectionView:UICollectionView;
//get cell size
let cellSize = CGSizeMake(self.view.frame.width, self.view.frame.height);
//get current content Offset of the Collection view
let contentOffset = collectionView.contentOffset;
//scroll to next cell
collectionView.scrollRectToVisible(CGRectMake(contentOffset.x + cellSize.width, contentOffset.y, cellSize.width, cellSize.height), animated: true);
}

How to double tap (instead of a single tap) a collection view cell in swift?

Right now, I have a bunch of messages in a collectionview cell.
My code to single tap the cell right now is
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Which cell: ", indexPath)
}
How do I make it such that this will only print if it is double tapped not single tapped?
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "customCell", for: indexPath) as! customCell
let tapCell = UITapGestureRecognizer(target: self, action: #selector(self.doubleTap(selectedIndex:)))
tapCell.numberOfTapsRequired=2
cell.tag=indexPath.row
cell.addGestureRecognizer(tapCell)
return cell
}
#objc func doubleTap(gesture: UITapGestureRecognizer){
print("Selected Index Is", gesture.view?.tag)
}
You can add UITapGestureRecognizer in collection view.
private var doubleTapGesture: UITapGestureRecognizer!
func setUpDoubleTap() {
doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(didDoubleTapCollectionView))
doubleTapGesture.numberOfTapsRequired = 2
collectionView.addGestureRecognizer(doubleTapGesture)
doubleTapGesture.delaysTouchesBegan = true
}
Call above method from your viewDidLoad as
override func viewDidLoad() {
super.viewDidLoad()
setUpDoubleTap()
}
Then add Gesture selector method in your class
#objc func didDoubleTapCollectionView() {
let pointInCollectionView = doubleTapGesture.location(in: collectionView)
if let selectedIndexPath = collectionView.indexPathForItem(at: pointInCollectionView) {
let selectedCell = collectionView.cellForItem(at: selectedIndexPath)
// Print double tapped cell's path
print("Which cell: ", selectedIndexPath.row)
print(" double tapped")
}
}
didDoubleTapCollectionView method will call only when you will double tap on collection view cell item.
I hope above example will solve your problem.

Change background of specific UICollectionView cells swift

I am trying to change the background of the first two cells in my collection view i have tried this code
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = self.view.frame.width
let height = self.view.frame.height
return CGSize(width: width / 2.2 , height: height / 6)
}
override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
MyCollectionView.reloadData()
}
#IBAction func Back(_ sender: Any) {
performSegue(withIdentifier: "fourtothree", sender: nil)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return ScoreArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
let MyCell = Cell.viewWithTag(1) as! UILabel
MyCell.text = ScoreArray[indexPath.row]
if indexPath.row == 0 {
Cell.backgroundColor = UIColor.gray
MyCell.font = UIFont.boldSystemFont(ofSize: 16.0)
}
if indexPath.row == 1 {
Cell.backgroundColor = UIColor.gray
MyCell.font = UIFont.boldSystemFont(ofSize: 16.0)
}
return Cell
}
It changes the color of the first two cells which is great. however when I rotate to landscape or scroll it changes the background of different cells not just the first two.
Question: How can I change the background of only the first two cells no mater what the user does?
Since your cell get reused, you need to provide the default color for other cell.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
let MyCell = Cell.viewWithTag(1) as! UILabel
MyCell.text = ScoreArray[indexPath.row]
if indexPath.row == 0 || indexPath.row == 1 {
Cell.backgroundColor = UIColor.gray
MyCell.font = UIFont.boldSystemFont(ofSize: 16.0)
} else {
Cell.backgroundColor = UIColor.white //change with your default color
}
return Cell
}
you can change the color of ay cell but as in cellForItemAt indexPath function you are using
let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell that statement reuse the cell to reduce the memory usage , So to overcome this problem use
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let Cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
let MyCell = Cell.viewWithTag(1) as! UILabel
MyCell.text = ScoreArray[indexPath.row]
MyCell.font = UIFont.boldSystemFont(ofSize: 16.0)
if indexPath.row == 0 || indexPath.row == 1 {
Cell.backgroundColor = UIColor.gray
}
else {
Cell.backgroundColor = UIColor.clear
}
return Cell
}

didSelectItemAt not working from SCLAlertView

I am using SCLAlertView to create custom alert view. My alert view contains one text field and collection view of coloured cells
Problem is that UICollectionView's didSelectItemAt method is not working. I think problem is because it is like subview. But I can't fix it.
I have one collection view at UIViewController and that method is working. Here's my code
var collectionViewAlert: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 1, left: 1, bottom: 1, right: 1)
layout.itemSize = CGSize(width: 25, height: 25)
collectionViewAlert = UICollectionView(frame: CGRect(x: 18, y: 10, width: 250, height: 25), collectionViewLayout: layout)
collectionViewAlert.dataSource = self
collectionViewAlert.delegate = self
collectionViewAlert.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "CollCell")
collectionViewAlert.backgroundColor = UIColor.white
}
#IBAction func addCategory(_ sender: Any) {
let alertView = SCLAlertView()
alertView.addTextField("Enter category name")
let subview = UIView(frame: CGRect(x:0,y:0,width:216,height:70))
subview.addSubview(self.collectionViewAlert)
alertView.customSubview = subview
alertView.showEdit("Choose color", subTitle: "This alert view has buttons")
}
let reuseIdentifier = "cell" // also enter this string as the cell identifier in the storyboard
var colors = [UIColor.red, UIColor.yellow, UIColor.green, UIColor.blue, UIColor.cyan]
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.colors.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// get a reference to our storyboard cell
if (collectionView == self.collectionViewAlert) {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollCell", for: indexPath as IndexPath)
cell.backgroundColor = self.colors[indexPath.item]
return cell
}
else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath)
cell.backgroundColor = self.colors[indexPath.item]// make cell more visible in our example project
return cell
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.item)!")
}
}
More screens here: screens
EDIT:
I still not found answer how to solve this problem. I think problem is subview interaction, because delegate method cellForItemAt is invoked on alert show. Someone know how to figure this out? screen from view hierarchy
Thanks for any help.
I have looked into SCLAlertView code. It seems it uses a tap recognizer for dismissing the keyboard.
Tap recognizer can conflict with the tap recognizer used by collection view.
To disable the recognizer in SCLAlertView you can use an appearance object:
let appearance = SCLAlertView.SCLAppearance(
disableTapGesture: true
)
let alertView = SCLAlertView(appearance: appearance)
You can also add extension for CollectionView delegate:
extension ViewController: UICollectionViewDelegate
{
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.item)!")
}
}
If you have added any UIImageView or UILabel inside UICollectionViewCell make sure you have enabled UserIntraction, because for both UIImageView or UILabel default as false.
setUserIntraction for both UIImageView or UILabel as TRUE.
You need to add collectionview delegate in protocol section. And be sure that you have make outlets of your object.
First of all you need to update like:
class YourViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
}
And then in viewDidLoad:
collectionView.delegate = self
collectionView.dataSource = self
collectionView.reloadData()
And make sure that your objects are properly connected.

Strange behavior with UICollectionView cell selection

I currently have this (pseudo)code:
var selectedCell: UICollectionViewCell?
override func viewDidLoad() {
super.viewDidLoad()
...
#initialize all objects and pull data from the server to fill the cells
UIView.animate(withDuration: 0, animations: {
self.dataCollectionView.reloadData()
}, completion: {(finished) in
let indexPath = IndexPath(row: 0, section: 0)
self.dataCollectionView.selectItem(at: indexPath, animated: true, scrollPosition: .top)
self.collectionView(self.dataCollectionView, didSelectItemAt: indexPath)
})
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! DataCollectionViewCell
if !selectedCell {
cell.layer.borderWidth = 1
}
else {
cell.layer.borderWidth = 2
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAtindexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
selectedCell = cell
cell.image = SomeImageFromServer
cell.layer.borderWidth = 2
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
cell.layer.borderWidth = 1
}
My thinking is that this code will select the first cell right after the collection view has been loaded, and it does. The problem is it selects the last cell as well, but didSelectItemAtindexPath is never called for the last cell, and only the first cell.
I've tried selecting the second cell by using let indexPath = IndexPath(row: 1, section: 0) and it does select the second cell once the collectionview has been loaded, and the last cell is not selected as you would think.
And once any cell is selected, the last cell is unselected.
So my hypothesis is that this isn't the code thinking the cell is "selected" but that it's for some reason giving the selected cell a "selected cell border" but only when the first selected cell is the first one. Any thoughts?
Try moving the border setting into cell, UICollectionView will automatically manage the border width:
//Swift3
class TestCollectionViewCell: UICollectionViewCell {
override func awakeFromNib() {
super.awakeFromNib()
self.layer.borderWidth = 1 //Default border width
}
override var isSelected: Bool {
didSet{
if self.isSelected {
self.layer.borderWidth = 2
}
else{
self.layer.borderWidth = 1
}
}
}
}

Resources