didSelectItemAt: not being called (UICollectionView) - swift

I have a UICollectionView in a UIView class because it's implemented in an other class.I set the delegate and dataSource and allowsSelection to true but didSelectItemAt method doesn't work and I can't figure out why.This is the code:
class NewRecipeViewCategoryCV: UIView, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.showsHorizontalScrollIndicator = false
cv.backgroundColor = UIColor.white
cv.translatesAutoresizingMaskIntoConstraints = false
cv.dataSource = self
cv.delegate = self
cv.allowsSelection = true
return cv
}()
let newRecipeModel = NewRecipeModel()
let cellId = "cellId"
override init(frame: CGRect) {
super.init(frame: frame)
collectionView.register(NewRecipeViewCategory.self, forCellWithReuseIdentifier: cellId)
addSubview(collectionView)
collectionView.topAnchor.constraint(equalTo: topAnchor).isActive = true
collectionView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
collectionView.heightAnchor.constraint(equalTo: heightAnchor).isActive = true
collectionView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return newRecipeModel.recipeCategory.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! NewRecipeViewCategory
cell.categoryText.text = newRecipeModel.recipeCategory[indexPath.item].uppercased()
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(123)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let category: UILabel = {
let category = UILabel()
category.text = "BREAKFAST"
category.font = UIFont(name: "SourceSansPro-Regular", size: 13)
category.translatesAutoresizingMaskIntoConstraints = false
category.textColor = UIColor.black
category.sizeToFit()
return category
}()
return CGSize(width: category.frame.width+15, height: category.frame.height+12)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Related

Make UICollectionViewCells with UIImageView height based on image

I want to make a UICollectionView with the cells the width of the screen, but the height is based on the aspect ratio of the UIImageView inside.
In my current implementation all of the UICollectionViewCell instances are squares and this isn't what I want.
I want to use auto layout somehow to make the size of the image the width of the screen, but the relevant height depends on the aspect ratio of the image used.
Everything is done programatically in code.
My code:
class ViewController: UIViewController {
var data = ["1","2","3","4","5","6","7","8","1","2","3","4","5","6","7","8"]
var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.dataSource = self
self.collectionView.delegate = self
self.collectionView.register(SubclassedCollectionViewCell.self, forCellWithReuseIdentifier: "cell")
self.collectionView.alwaysBounceVertical = true
self.collectionView.backgroundColor = .white
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
override func loadView() {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: UIScreen.main.bounds.size.width - 20, height: UIScreen.main.bounds.size.width / 1)
layout.scrollDirection = .vertical
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
self.view = collectionView
}
}
extension ViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
data.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? SubclassedCollectionViewCell {
let data = self.data[indexPath.item]
cell.setupCell(image: data)
return cell
}
fatalError("Could not dequeue cell")
}
}
with the cell
class SubclassedCollectionViewCell: UICollectionViewCell {
var hotelImageView: UIImageView = {
var hotelView = UIImageView()
hotelView.contentMode = .scaleAspectFill
hotelView.clipsToBounds = true
return hotelView
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(hotelImageView)
hotelImageView.translatesAutoresizingMaskIntoConstraints = false
hotelImageView.topAnchor.constraint(equalTo: topAnchor).isActive = true
hotelImageView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
hotelImageView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
hotelImageView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupCell(image: String) {
if let image : UIImage = UIImage(named: image) {
hotelImageView.image = image
}
}
}
First, calculate the ratio based on the width and multiply by collection view width you can get a new height based on width.
Final Code: Remove itemSize from the loadview function. And calculate height and return item size in sizeForItemAt method.
loadView
override func loadView() {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
// layout.itemSize = CGSize(width: UIScreen.main.bounds.size.width - 20, height: UIScreen.main.bounds.size.width / 1) <-- Remove this
layout.scrollDirection = .vertical
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
self.view = collectionView
}
UICollectionViewDelegateFlowLayout
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
data.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as? SubclassedCollectionViewCell {
let data = self.data[indexPath.item]
cell.setupCell(image: data)
return cell
}
fatalError("Could not dequeue cell")
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
guard let iamgeData = UIImage(named: self.data[indexPath.item]) else {
return .zero
}
let width = collectionView.bounds.width
let heightOnWidthRatio = iamgeData.size.height / iamgeData.size.width
let height = width * heightOnWidthRatio
return CGSize(width: width, height: height)
}
}

Swift Add different actions to cells on a UICollectionView

I don't know where to start, I have a UICollectionView with multiple cells filled with a UIImage. I want each cell/UIImage to do a different action on a fingertap. Can someone pinpoint me in the right direction here?
The action that I have is a #IBAction from a UIButton, I know want have that action on a cell in the UICollectionView..
( I Guess I have to do something with the 'let cell = countryCollectionView.dequeueReusableCell' ?
import UIKit
class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
#IBOutlet weak var soundsCollectionView: UICollectionView!
lazy var cv: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
var cc = UICollectionView(frame: .zero, collectionViewLayout: layout)
cc.translatesAutoresizingMaskIntoConstraints = false
cc.register(CustomCell.self, forCellWithReuseIdentifier: "CustomCell")
cc.delegate = self
cc.dataSource = self
cc.backgroundColor = .white
return cc
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.addSubview(cv)
cv.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
cv.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
cv.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
cv.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.tag = indexPath.row
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 100)
}
}
class CustomCell: UICollectionViewCell {
lazy var centerImageView: UIImageView = {
var img = UIImageView()
img.translatesAutoresizingMaskIntoConstraints = false
img.image = UIImage(named: "1")
img.clipsToBounds = true
img.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handler(_:)))
tapGesture.numberOfTapsRequired = 1
img.addGestureRecognizer(tapGesture)
return img
}()
#objc private func handler(_ sender: UITapGestureRecognizer) {
print("tapped tag > ", self.tag)
}
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(centerImageView)
centerImageView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
centerImageView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
centerImageView.heightAnchor.constraint(equalToConstant: 80).isActive = true
centerImageView.widthAnchor.constraint(equalToConstant: 80).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I edit as new programmatically example for your problem solution.
class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
lazy var cv: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
var cc = UICollectionView(frame: .zero, collectionViewLayout: layout)
cc.translatesAutoresizingMaskIntoConstraints = false
cc.register(CustomCell.self, forCellWithReuseIdentifier: "CustomCell")
cc.delegate = self
cc.dataSource = self
cc.backgroundColor = .white
return cc
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(cv)
cv.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
cv.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
cv.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
cv.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.tag = indexPath.row
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 100)
}
}
class CustomCell: UICollectionViewCell {
lazy var centerImageView: UIImageView = {
var img = UIImageView()
img.translatesAutoresizingMaskIntoConstraints = false
img.image = UIImage(named: "1")
img.clipsToBounds = true
img.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handler(_:)))
tapGesture.numberOfTapsRequired = 1
img.addGestureRecognizer(tapGesture)
return img
}()
#objc private func handler(_ sender: UITapGestureRecognizer) {
print("tapped tag > ", self.tag)
}
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(centerImageView)
centerImageView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
centerImageView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
centerImageView.heightAnchor.constraint(equalToConstant: 80).isActive = true
centerImageView.widthAnchor.constraint(equalToConstant: 80).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
In this scenario, I would avoid using buttons on your cells. Instead you should hook into the didSelectItemAt delegate method and just add the necessary information into a data model:
struct Country {
let imageName: String
let sound: Sound // You didn't specify what type the sound1 object is but you get the gist
}
So your countries array will now contain this new struct instead of just raw Strings:
let countries = [
Country("country1", sound1),
Country("country2", sound2),
...
]
Then you can get the exact sound you want to play from the indexPath passed into didSelectItemAt:
let sound = self.countries[indexPath.row].sound
sound.play()
You'll also need to adjust how you're setting the cell's image in cellForItemAt:
let imageName = self.countries[indexPath.row].imageName
cell.countryImageView.image = UIImage(named: imageName)

Swift - Draw lines between several random CGPoints

I am trying to create a simple line graph that should display the average monthly user score. So far I have created a collectionView with a white dot at the top of each cell, but now I would like to have a straight line between each dot. I have added a temporary array for testing purposes.
Since it will be variable server data (the last six months), the location of the dots can be different each time. What should I do to connect the first dot with the second one and the second one with the next one (until all dots are connected)?
User profile data controller
class UserProfileData: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var cellId = "cellId"
let values: [CGFloat] = [4.5, 3.2, 4.8, 5.0, 2.3, 2.9]
init() {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = UICollectionViewScrollDirection.horizontal
super.init(collectionViewLayout: layout)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView?.dataSource = self
self.collectionView?.delegate = self
collectionView?.backgroundColor = Constants.MAIN_THEME_COLOR
collectionView?.isScrollEnabled = false
collectionView?.register(BarCell.self, forCellWithReuseIdentifier: cellId)
}
// MARK: UICollectionViewDataSource
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return values.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 50, height: view.frame.height - 20)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! BarCell
if let max = values.max() {
let value = values[indexPath.item]
let ratio = value / max
cell.barHeightConstraint?.constant = view.frame.height * ratio
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 4, bottom: 0, right: 4)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
}
My custom cell
// Create custom cell(s)
class BarCell: UICollectionViewCell {
let barView: UIView = {
let view = UIView()
view.backgroundColor = .clear
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let barLabel: UILabel = {
let label = UILabel()
label.text = "."
label.textColor = .white
label.font = UIFont.systemFont(ofSize: 70)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
var barHeightConstraint: NSLayoutConstraint?
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(barView)
barView.addSubview(barLabel)
barHeightConstraint = barView.heightAnchor.constraint(equalToConstant: 300)
barHeightConstraint?.isActive = true
barHeightConstraint?.constant = 100
barView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
barView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
barView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
barLabel.centerXAnchor.constraint(equalTo: barView.centerXAnchor).isActive = true
barLabel.topAnchor.constraint(equalTo: barView.topAnchor, constant: 5).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
A UICollectionView has a backgroundView property. You should be able to set the backgroundView of your UICollectionView to a custom UIView that draws the lines between your items.

uicollectionviewcells not showing [duplicate]

I have got this Swift code
`
let cellId="cellId"
class FeedController: UICollectionViewController{
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Centill"
collectionView?.reloadData()
collectionView?.backgroundColor = UIColor(white: 0.95, alpha: 1)
collectionView?.register(FeedCell.self, forCellWithReuseIdentifier: cellId)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell=collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath);
cell.backgroundColor = .yellow
return cell
}
}
class FeedCell: UICollectionViewCell {
override init(frame: CGRect){
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews(){
backgroundColor = .yellow
}
}
`
But unfortunately my cells are not showing.It only shows navigation bar and background color.what may be the problem with my code?
Try This code:
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: 60, height: 60)
let myCollectionView:UICollectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
myCollectionView.dataSource = self
myCollectionView.delegate = self
myCollectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "MyCell")
myCollectionView.backgroundColor = UIColor.whiteColor()
self.view.addSubview(myCollectionView)
You have to provide the size for collection view cell. add the below code snippet
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// calculate and return the height
}
In your cellForItemAt dataSource method you need to give custom UICollectionCell Class
let cell=collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! FeedCell
cell.backgroundColor = .yellow
return cell
Then you will able to see cell.
Try it.
You add in the class
UICollectionViewDataSource and UICollectionVIewDelegate.

Swift collectionViewCells are not showing

I have got this Swift code
`
let cellId="cellId"
class FeedController: UICollectionViewController{
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Centill"
collectionView?.reloadData()
collectionView?.backgroundColor = UIColor(white: 0.95, alpha: 1)
collectionView?.register(FeedCell.self, forCellWithReuseIdentifier: cellId)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell=collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath);
cell.backgroundColor = .yellow
return cell
}
}
class FeedCell: UICollectionViewCell {
override init(frame: CGRect){
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews(){
backgroundColor = .yellow
}
}
`
But unfortunately my cells are not showing.It only shows navigation bar and background color.what may be the problem with my code?
Try This code:
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: 60, height: 60)
let myCollectionView:UICollectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
myCollectionView.dataSource = self
myCollectionView.delegate = self
myCollectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "MyCell")
myCollectionView.backgroundColor = UIColor.whiteColor()
self.view.addSubview(myCollectionView)
You have to provide the size for collection view cell. add the below code snippet
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// calculate and return the height
}
In your cellForItemAt dataSource method you need to give custom UICollectionCell Class
let cell=collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! FeedCell
cell.backgroundColor = .yellow
return cell
Then you will able to see cell.
Try it.
You add in the class
UICollectionViewDataSource and UICollectionVIewDelegate.