UICollectionView cell needs to be tapped twice for segue to happen - uicollectionview

I know this will be something simple; however, I have created a UICollectionView that displays just some colours for now. When a cell is tapped I want it to perform a segue with the cell number that was tapped.
At the moment, if I tap a cell nothing happens. If I touch the same cell again nothing happens, but if I touch any other cell the segue occurs successfully and the cell clicked gets passed on, albeit with the first cells touched number.
It is in a navigation stack. Here is my code:
//Everything Collection View
//header text
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "SectionHeader", for: indexPath as IndexPath) as! SectionHeaderPractice
header.headerLabel.text = "SELECT A TOPIC..."
return header
}
//number of cells
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
//height and width of cell
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let cellWidth = (view.frame.width/2)-20
let cellHeight = view.frame.height/4
return CGSize(width: cellWidth, height: cellHeight)
}
//cell content
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let content = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as UICollectionViewCell
//set text
let desc = content.viewWithTag(3) as! UILabel
desc.text = shieldTextArray[(indexPath as NSIndexPath).row]
//set color scale
let score = scoreArray[(indexPath as NSIndexPath).row]
let redC = 2*score
let greenC = 2*(1-score)
content.backgroundColor = UIColor.init(red: CGFloat(redC), green: CGFloat(greenC), blue: 0.45, alpha: 1)
return content
}
override func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
//sets variable to clicked cell
//cellClicked = indexPath.row
//changes background colour on clicking
//let content1 = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as UICollectionViewCell
//content1.backgroundColor = UIColor.init(red: 0, green: 0, blue: 0, alpha: 1)
//Performs segue
//print(cellClicked)
performSegue(withIdentifier: "practiceSegue", sender: self)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(10,10,10,10)
}
//End Everything Collection View
Any pointers appreciated.

Your issue is with this line didDeselectItemAt, make sure you use didSelectItemAt.
didDeselectItemAt is the reason why you have to tap twice for segue, you select the cell then deselect the cell, once the cell is deselected, your code perform segue.

Related

Images are not setting properly to the collectionview cell

I am using a collection view and it contains an imageview. Images are in url format so I have written a function to convert the url into Image but images are not looking properly.
I have tried all the modes like aspect fit, aspect fill, scale to fill.
I have searched a lot on the internet but not come up with answer.
This is my code :
extension HomeDemoViewController : UICollectionViewDelegate,UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return bannerArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeAddCollectionViewCell", for: indexPath)
as! HomeAddCollectionViewCell
cell.imageview.setImageFromURl(stringImageUrl: imageArray[indexPath.row])
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = self.storyboard!.instantiateViewController(withIdentifier: "MenuViewController") as! MenuViewController
self.navigationController!.pushViewController(vc, animated: true)
}
}
func setImageFromURl(stringImageUrl url: String){
if let url = NSURL(string: url) {
DispatchQueue.global(qos: .default).async{
if let data = NSData(contentsOf: url as URL) {
DispatchQueue.main.async {
self.image = UIImage(data: data as Data)
}
}
}
}
}
Describe your problem please, attach screenshot what’s wrong.
Seems like the problem is in the image, try setting the different content mode and if needed — clipsToBounds = true

Increase the height of collectionview cell on button press and scroll to bottom

I have a collection view controller implemented with the following method
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 661)
}
I have hardcoded a height value but when I press a button I want the height of the cell to be 800 and scrolled to bottom of cell.( I just have one cell). Please help
var dynamicHeight = 661
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: dynamicHeight )
}
#IBAction func yourButton(_ sender: Any?)
{
self.dynamicHeight = 800
self.collectionView.reloadData()
}

Select first Item in CollectionView Swift4

I'm trying to select the first Item in CollectionView when the Collectionview loads. I found many solutions for Swift 3 but nothing of that worked for me in Swift4. What I tried(viewDidAppear):
import UIKit
import SDWebImage
class PostsTab_Details: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var PostsSelectRarityCollectionView: UICollectionView!
#IBOutlet weak var RarityTypeLbl: UILabel!
//Center my Collectionview Horizontal
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
let totalCellWidth = 100 * (selectedPosts?.rarity.count)!
let totalSpacingWidth = 10 * (3 - 1)
let leftInset = (PostsSelectRarityCollectionView.frame.width - CGFloat(totalCellWidth + totalSpacingWidth)) / 2
let rightInset = leftInset
return UIEdgeInsetsMake(0, leftInset, 0, rightInset)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return (selectedPosts?.rarity.count)!
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = PostsSelectRarityCollectionView.dequeueReusableCell(withReuseIdentifier: "PostssTab_DetailCollectionCell", for: indexPath) as! PostsTab_DetailsCollectionViewCell
cell.PostssTab_DetailCollectionImage.sd_setImage(with: URL(string: (selectedPosts?.PostsImageURL)!))
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
RarityTypeLbl.text = selectedPosts?.rarity[indexPath.row].rarity
}
//Tried this also with IndexPath(item: 0, section: 0)
override func viewDidAppear(_ animated: Bool) {
let selectedIndexPath = IndexPath(row: 0, section: 0)
PostsSelectRarityCollectionView.selectItem(at: selectedIndexPath, animated: true, scrollPosition: .right)
}
var selectedPosts: Posts?
override func viewDidLoad() {
PostsSelectRarityCollectionView.delegate = self
PostsSelectRarityCollectionView.dataSource = self
}
}
But this is not working... I hope someone knows what I'm doing wrong..
Thanks in advance
Update:
This worked for me now, thanks to Razib's answer:
override func viewWillAppear(_ animated: Bool) {
self.collectionView(PostsSelectRarityCollectionView, didSelectItemAt: IndexPath(row: 0, section: 0))
}
Your code seems okay to me. If you like to trigger the didSelectItemAt method, use the following code.
override func viewDidAppear(_ animated: Bool) {
self.PostsSelectRarityCollectionView(self.PostsSelectRarityCollectionView, didSelectItemAt: IndexPath(row: 0, section: 0))
}
To programmatically select the first Item in CollectionViewCell when the Collectionview loads you should code in viewDidAppear:
override func viewDidAppear(_ animated: Bool) {
let indexPath:IndexPath = IndexPath(row: 0, section: 0)
collectionView?.selectItem(at: indexPath, animated: false, scrollPosition: .top)
}
Try this (Swift 5):
let indexPath:IndexPath = IndexPath(row: 0, section: 0)
collectionView?.selectItem(at: indexPath, animated: false, scrollPosition: .top)

Collection view cell not appear after resize the CollectionView height

I am facing the UICollectionView cell size issue. I am using two collection_view and one table_view 1:- Main CollectionView ,which is use for swipe and only display one cell at one time 2:- Inside Main Collection_View, i use table_view and now further inside table_view I am using Collection view which display 6 cell at one time.
Now the whole process is I am using a layout which is swipable and display 6 item at one page and so on.
The problem is when I set main cell height 200 then inside collectionview cell not appearing as expected.
Outer CollectionView Class
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var collectionMain: UICollectionView!
#IBOutlet weak var tableView: UITableView!
let itemsPerRow: CGFloat = 1
let sectionInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension ViewController:UICollectionViewDataSource,UICollectionViewDelegate {
//1
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
//2
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return 3
}
//3
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:cellCollectionCollectionViewCell! = collectionView.dequeueReusableCell(withReuseIdentifier: "cellSwipe",
for: indexPath) as! cellCollectionCollectionViewCell
switch indexPath.item {
case 0:
cell.backgroundColor = UIColor.black
cell.setupCollectionTableCell(indexPath)
break
case 1: cell.backgroundColor = UIColor.red
cell.setupCollectionTableCell(indexPath)
break
default:
cell.backgroundColor = UIColor.yellow
cell.setupCollectionTableCell(indexPath)
break
}
// Configure the cell
return cell
}
}
extension ViewController : UICollectionViewDelegateFlowLayout {
//1
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
//2
let paddingSpace = sectionInsets.left * (itemsPerRow + 1)
let availableWidth = self.collectionMain.frame.width - paddingSpace
let widthPerItem = availableWidth / itemsPerRow
return CGSize(width: widthPerItem, height: widthPerItem)
}
//3
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAt section: Int) -> UIEdgeInsets {
return sectionInsets
}
// 4
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return sectionInsets.left
}
}
Model Constant class
import UIKit
class Constant {
static let totalItem: CGFloat = 9
static let column: CGFloat = 3
static let minLineSpacing: CGFloat = 1.0
static let minItemSpacing: CGFloat = 1.0
static let offset: CGFloat = 1.0 // TODO: for each side, define its offset
static func getItemWidth(boundWidth: CGFloat) -> CGFloat {
let totalWidth = boundWidth - (offset + offset) - ((column - 1) * minItemSpacing)
return totalWidth / column
}
}
Table Cell Class
import UIKit
class CollectionCell: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.sectionInset = UIEdgeInsetsMake(
Constant.offset, // top
Constant.offset, // left
Constant.offset, // bottom
Constant.offset // right
)
layout.minimumInteritemSpacing = Constant.minItemSpacing
layout.minimumLineSpacing = Constant.minLineSpacing
}
collectionView.isScrollEnabled = false
collectionView.dataSource = self
collectionView.delegate = self
}
}
extension CollectionCell: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return Int(Constant.totalItem)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BoxCell", for: indexPath)
return cell
}
}
extension CollectionCell: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let itemWidth = Constant.getItemWidth(boundWidth: collectionView.bounds.size.width)
return CGSize(width: itemWidth, height: 50)
}
}
Main CollectionCell class
import UIKit
class cellCollectionCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var tblView: UITableView!
var indexPath:IndexPath?
func setupCollectionTableCell(_ row:IndexPath){
self.indexPath = row
self.tblView.delegate = self
self.tblView.dataSource = self
// self.tblView.estimatedRowHeight = 300
self.tblView.reloadData()
}
}
extension cellCollectionCollectionViewCell:UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.row {
case 0:
return 50
case 1:
let itemHeight = Constant.getItemWidth(boundWidth: tableView.bounds.size.width)
let totalRow = ceil(Constant.totalItem / Constant.column)
let totalTopBottomOffset = Constant.offset + Constant.offset
let totalSpacing = CGFloat(totalRow - 1) * Constant.minLineSpacing
let totalHeight = ((itemHeight * CGFloat(totalRow)) + totalTopBottomOffset + totalSpacing)
print("total height \(totalHeight)")
return totalHeight
default:
return UITableViewAutomaticDimension
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// switch indexPath.row {
// case 0:
// let cell = tableView.dequeueReusableCell(withIdentifier: "HeaderCell", for: indexPath)
// return cell
// default:
// let cell = tableView.dequeueReusableCell(withIdentifier: "CollectionCell", for: indexPath) as! CollectionCell
// return cell
// }
let cell = tableView.dequeueReusableCell(withIdentifier: "CollectionCell", for: indexPath) as! CollectionCell
return cell
}
When I set height of Main Collection view 200
Bellow are the link of images
When I set height 300, working fine

Swift iOS- How to Add Button to the outside a CollectionView Cell

I want to get a deleteButton that is a delete image to sit on the outside of a collectionViewCell (it can be partially inside).
I looked at other SO answers and they said just play with the button's frame's Rect's x & y values which I did. When I set the x & y values to 0,0 I get:
class CustomCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
var deleteButton: UIButton!
var deleteButtonImg: UIImage!
override func awakeFromNib() {
super.awakeFromNib()
deleteButton = UIButton(frame: CGRect(x: 0, y: 0, width: frame.size.width/4, height: frame.size.width/4))
deleteButtonImg = UIImage(named: "delete-icon")!.withRenderingMode(.alwaysTemplate)
deleteButton.setImage(deleteButtonImg, for: .normal)
deleteButton.tintColor = UIColor.red
contentView.addSubview(deleteButton)
}
When I try to set the the Rect's x & y to -10,-10 the deleteButton gets clipped inside the cell's imageView. I don't have clipsToBounds set.
deleteButton = UIButton(frame: CGRect(x: -10, y: -10, width: frame.size.width/4, height: frame.size.width/4))
I even tried setting clipToBounds to false but I get the same effect as pic # 3.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.imageView.image = myImageArray[indexPath.row]
cell.imageView.clipsToBounds = false
return cell
}
Where am I going wrong?
The problem was inside storyboard I had a:
CollectionView
-CustomCell (type collectionViewCell)
-imageView
Under the Attributes Inspector, in the Drawing section, all 3 of these have the property clipsToBounds.
I overlooked the fact that I had clipsToBounds set to false (unchecked) on the imageView but set to true (checked) on the CustomCell and the CollectionView.
If anyone else has this problem make sure you uncheck clipsToBounds on the collectionView, collectionViewCell, and the imageView.
okay u can do like below, first create a xib file and replace default view with collection view cell and set up like below,
in the above image set the class name to CustomCell (In my case) and place image view (green ) and button (blue).
and in View controller,
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//register the nib to collectionview
self.aColectionView.register(UINib(nibName: "CustomCell", bundle: nil), forCellWithReuseIdentifier: "CUSTOM_CELL")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 40
}
//cell creation as u are doing
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:CustomCell = collectionView.dequeueReusableCell(withReuseIdentifier: "CUSTOM_CELL", for: indexPath) as! CustomCell
//set the image for custom cell
return cell
}
//return the required size
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 200, height: 150)
}
and output like below,
and in custom cell class, u add any other features like action for a button and other views related code
class CustomCell:UICollectionViewCell {
#IBOutlet weak var deleteButton: UIButton!
#IBOutlet weak var imageView: UIImageView!
//other view related code
}