UITableView is duplicating/repeating number of rows in section - ios

I am currently developing a Fitness Application and working on Workout View. It has a functionality similar to to-do checklist. So basically the user is marking Sets of a certain exercise that he finished. I know that it is needed to prepare TableViewCells for reuse, and I did that for the state when all the sets of exercise is done and user shouldn't be able to interact whit that TableViewCell anymore. The only thing that keeps getting duplicated is numberOfRowsInSection. Guys please help me find the missing part, I have been trying for two days at this point:(
TableView is inside the collectionViewCell so I am initializing it from there. I am using custom delegate as I have to have an access to tableView from the view that holds collectionView.
protocol TableViewCellDelegate: AnyObject {
func tableView(tableViewCell: WorkoutStartedTVCurrentExerciseCell, index: Int, didTappedInTableViewCell: WorkoutStartedCell)
// other delegate methods that you can define to perform action in viewcontroller
}
class WorkoutStartedCell: UICollectionViewCell {
weak var cellDelegateTV: TableViewCellDelegate?
let scrollView: UIScrollView = {
let view = UIScrollView()
view.backgroundColor = UIColor.clear
view.isScrollEnabled = true
view.contentMode = .center
view.showsHorizontalScrollIndicator = false
view.isMultipleTouchEnabled = true
view.isUserInteractionEnabled = true
return view
}()
let titleLabel: UILabel = {
let label = UILabel()
label.backgroundColor = UIColor.clear
label.textColor = UIColor.black
label.textAlignment = .center
label.text = "Incline Bench Press"
label.font = UIFont.systemFont(ofSize: 23.0, weight: .semibold)
return label
}()
let numberOfExercisesLabel: UILabel = {
let label = UILabel()
label.backgroundColor = UIColor.clear
label.textColor = UIColor.black.withAlphaComponent(0.7)
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 16.5, weight: .medium)
return label
}()
let container: UIView = {
let view = UIView()
view.layer.cornerRadius = 10
view.backgroundColor = UIColor.black
view.layer.shadowOffset = CGSize(width: 0, height: 0)
view.clipsToBounds = false
view.layer.shadowOpacity = 0.35
view.layer.shadowRadius = 10
view.layer.shadowColor = UIColor.black.cgColor
return view
}()
let tableView: UITableView = {
let tableView = UITableView()
tableView.backgroundColor = UIColor.clear
tableView.separatorStyle = .none
tableView.register(WorkoutStartedTVCurrentExerciseCell.self, forCellReuseIdentifier: "currentExerciseCellID")
tableView.layer.cornerRadius = 0
tableView.scrollIndicatorInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
tableView.showsHorizontalScrollIndicator = false
tableView.showsVerticalScrollIndicator = true
tableView.isScrollEnabled = true
return tableView
}()
var number_of_sets : Int!
var number_of_reps : Int!
var completed_sets = [Int]()
var remaining_sets = [Int]()
//var current_set: IndexPath!
//var completedSets: [Int]!
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.white
contentView.isUserInteractionEnabled = true
isMultipleTouchEnabled = true
//tableView.estimatedRowHeight = 0
//tableView.estimatedSectionHeaderHeight = 0
//tableView.estimatedSectionFooterHeight = 0
//tableView.delegate = self
//tableView.dataSource = self
tableView.isScrollEnabled = false
contentView.addSubview(scrollView)
scrollView.addSubview(titleLabel)
scrollView.addSubview(numberOfExercisesLabel)
scrollView.addSubview(container)
scrollView.addSubview(tableView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.topAnchor.constraint(equalTo: topAnchor).isActive = true
scrollView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
scrollView.heightAnchor.constraint(equalTo: heightAnchor).isActive = true
scrollView.heightAnchor.constraint(equalTo: heightAnchor).priority = UILayoutPriority.defaultLow
//scrollView.delegate = self
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 25).isActive = true
titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
titleLabel.sizeToFit()
numberOfExercisesLabel.translatesAutoresizingMaskIntoConstraints = false
numberOfExercisesLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 10).isActive = true
numberOfExercisesLabel.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
numberOfExercisesLabel.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
numberOfExercisesLabel.sizeToFit()
container.translatesAutoresizingMaskIntoConstraints = false
container.topAnchor.constraint(equalTo: numberOfExercisesLabel.bottomAnchor, constant: 15).isActive = true
container.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 0).isActive = true
container.widthAnchor.constraint(equalToConstant: self.frame.width - 0).isActive = true
container.heightAnchor.constraint(equalToConstant: self.frame.width - 0).isActive = true
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: container.bottomAnchor, constant: 20).isActive = true
tableView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
}
override func prepareForReuse() {
super.prepareForReuse()
number_of_sets = nil
number_of_reps = nil
remaining_sets.removeAll()
completed_sets.removeAll()
tableView.delegate = nil
tableView.dataSource = nil
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension WorkoutStartedCell: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return remaining_sets.count + completed_sets.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "currentExerciseCellID", for: indexPath) as! WorkoutStartedTVCurrentExerciseCell
cell.selectionStyle = .none
cell.Set.text = "\(Array(1...number_of_sets)[indexPath.row])"
cell.Reps.text = "\(number_of_reps ?? 1)"
if completed_sets.count == number_of_sets {
cell.isUserInteractionEnabled = false
} else {
cell.isUserInteractionEnabled = true
}
if completed_sets.contains(where: {$0 == indexPath.row}) == false, indexPath.row == remaining_sets.first {
//Current Set
cell.Set.textColor = #colorLiteral(red: 0, green: 0.9810667634, blue: 0.5736914277, alpha: 1).withAlphaComponent(0.75)
cell.SetStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.Weight.textColor = #colorLiteral(red: 0, green: 0.9810667634, blue: 0.5736914277, alpha: 1).withAlphaComponent(0.75)
cell.WeightStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.Reps.textColor = #colorLiteral(red: 0, green: 0.9810667634, blue: 0.5736914277, alpha: 1).withAlphaComponent(0.75)
cell.RepsStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.CompletedImage.tintColor = UIColor.white
cell.CompletedImage.backgroundColor = UIColor.white
cell.CompletedImage.layer.borderColor = UIColor.darkGray.withAlphaComponent(0.9).cgColor
} else if completed_sets.contains(indexPath.row) == true, remaining_sets.contains(indexPath.row) == false {
//Completed Set
cell.Set.textColor = UIColor.black.withAlphaComponent(0.7)
cell.SetStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.Weight.textColor = UIColor.black.withAlphaComponent(0.7)
cell.WeightStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.Reps.textColor = UIColor.black.withAlphaComponent(0.7)
cell.RepsStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.CompletedImage.tintColor = UIColor.white
cell.CompletedImage.backgroundColor = UIColor.darkGray.withAlphaComponent(0.9)
cell.CompletedImage.layer.borderColor = UIColor.darkGray.withAlphaComponent(0.9).cgColor
} else if completed_sets.contains(indexPath.row) == false, remaining_sets.contains(indexPath.row) == true, indexPath.row != remaining_sets.first {
//Remaining Sets
cell.Set.textColor = UIColor.black.withAlphaComponent(1.0)
cell.SetStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.Weight.textColor = UIColor.black.withAlphaComponent(1.0)
cell.WeightStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.Reps.textColor = UIColor.black.withAlphaComponent(1.0)
cell.RepsStatic.textColor = UIColor.black.withAlphaComponent(0.7)
cell.CompletedImage.tintColor = UIColor.white
cell.CompletedImage.backgroundColor = UIColor.white
cell.CompletedImage.layer.borderColor = UIColor.darkGray.withAlphaComponent(0.9).cgColor
}
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 75
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return false
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as? WorkoutStartedTVCurrentExerciseCell
self.cellDelegateTV?.tableView(tableViewCell: cell!, index: indexPath.row, didTappedInTableViewCell: self)
}
}
Here is how I pass the data from ViewController and setting CollectionView delegate and data source.
extension workoutStartedView: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return exercise_names.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let exercisesCount = Array(1...exercise_names.count)
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellID, for: indexPath) as! WorkoutStartedCell
cell.number_of_reps = Int(number_of_reps[indexPath.item])!
cell.number_of_sets = Int(number_of_sets[indexPath.item])!
cell.remaining_sets = remainingSets[indexPath.item]
cell.completed_sets = completedSets[indexPath.item]
cell.titleLabel.text = exercise_names[indexPath.item]
cell.numberOfExercisesLabel.text = "Exercise \(exercisesCount[indexPath.item]) of \(exercise_names.count)"
cell.cellDelegateTV = self
cell.tableView.heightAnchor.constraint(equalToConstant: 75 * CGFloat(Int(self.number_of_sets[indexPath.item])!)).isActive = true
cell.scrollView.contentSize = CGSize(width: collectionView.frame.width, height: 100 + (collectionView.frame.width) + (75 * CGFloat(Int(self.number_of_sets[indexPath.item])!)))
cell.scrollView.scrollToTop(animated: false)
cell.tableView.delegate = cell.self
cell.tableView.dataSource = cell.self
cell.tableView.reloadData()
//cell.layoutIfNeeded()
cell.tag = Array(0...exercise_names.count - 1)[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.scrollToItem(at: indexPath, at: .left, animated: true)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return sectionInsets
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.bounds.width - 40, height: collectionView.bounds.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 10
}
}
Here I am handling data from collectionViewCell throw custom delegate
extension workoutStartedView: TableViewCellDelegate {
func tableView(tableViewCell: WorkoutStartedTVCurrentExerciseCell, index: Int, didTappedInTableViewCell: WorkoutStartedCell) {
//if didTappedInTableViewCell.remaining_sets.count > 1 {
didTappedInTableViewCell.completed_sets.append(didTappedInTableViewCell.remaining_sets.first!)
didTappedInTableViewCell.remaining_sets.removeFirst()
if completedSets.count > 0 {
if self.completedSets.count > didTappedInTableViewCell.tag {
self.completedSets[didTappedInTableViewCell.tag] = didTappedInTableViewCell.completed_sets
} else if self.completedSets.count <= didTappedInTableViewCell.tag {
self.completedSets.append(didTappedInTableViewCell.completed_sets)
}
} else if completedSets.count <= 0 {
self.completedSets.append(didTappedInTableViewCell.completed_sets)
}
if self.remainingSets[didTappedInTableViewCell.tag].count > 0 {
self.remainingSets[didTappedInTableViewCell.tag] = didTappedInTableViewCell.remaining_sets
} else if self.remainingSets[didTappedInTableViewCell.tag].count <= 1 {
self.remainingSets.removeFirst()
}
print(didTappedInTableViewCell.completed_sets)
print(didTappedInTableViewCell.remaining_sets)
print(self.completedSets)
print(self.remainingSets)
//collectionView.reloadData()
didTappedInTableViewCell.tableView.reloadData()
}
}
Hey Guys I finally found the solution!:D
The problem was that I wasn't resetting all the cell properties in cellForRowAt function
By adding this lines my problem was solved
cell.titleLabel.text = ""
cell.numberOfExercisesLabel.text = ""
cell.tableView.removeAllConstraints()
cell.scrollView.contentSize = CGSize.zero
I just didn't think that the constraints and scrollView's contentSize should also be reseted:D

Related

How to pressed a UIButton within a customized TableviewCell?

I have been looking all throughout SO on how to interact with a UIButton within a customized tableview cell. All of the answers I have seen are using IBOutlets, however I have not seen a way to do this fully programmatically. I am use to interacting with buttons via button.addTarget. Here are my two ViewControllers, one being the customized tableviewcell and the other being the ViewController.
Here is my customized. I tried using a protocol delegate route, however this has failed.
import UIKit
#objc protocol TableViewNew {
func onClickCell()
}
class NewMoveTableViewCell: UITableViewCell {
var cellDelegate: TableViewNew?
static let identifier = "NewTableViewCell"
private let myImageView: UIImageView = {
let imageView = UIImageView()
imageView.clipsToBounds = true
imageView.contentMode = .scaleAspectFill
imageView.layer.masksToBounds = true
imageView.backgroundColor = .purple
imageView.layer.cornerRadius = 80/2
return imageView
}()
private let myLabel : UILabel = {
let label = UILabel()
label.text = "test"
label.backgroundColor = .blue
label.textColor = .systemPink
label.adjustsFontSizeToFitWidth = true
label.textAlignment = .center
return label
}()
private let button: UIButton = {
let button = UIButton()
button.setTitle("Invite", for: .normal)
button.backgroundColor = .systemPink
button.layer.cornerRadius = 10
return button
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(myImageView)
addSubview(myLabel)
addSubview(button)
setImageConstratins()
setTitleLabelConstraints()
setButton()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setImageConstratins() {
myImageView.translatesAutoresizingMaskIntoConstraints = false
myImageView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
myImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 12).isActive = true
myImageView.heightAnchor.constraint(equalToConstant: 80).isActive = true
myImageView.widthAnchor.constraint(equalToConstant: 80).isActive = true
}
func setTitleLabelConstraints() {
myLabel.translatesAutoresizingMaskIntoConstraints = false
myLabel.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
myLabel.leadingAnchor.constraint(equalTo: myImageView.trailingAnchor, constant: 5).isActive = true
myLabel.heightAnchor.constraint(equalToConstant: 80).isActive = true
//myLabel.trailingAnchor.constraint(equalTo: button.leadingAnchor, constant: -12).isActive = true
}
func setButton() {
button.translatesAutoresizingMaskIntoConstraints = false
button.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
button.leadingAnchor.constraint(equalTo: myLabel.trailingAnchor, constant: -5).isActive = true
button.heightAnchor.constraint(equalToConstant: 80).isActive = true
button.widthAnchor.constraint(equalToConstant: 150).isActive = true
button.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -12).isActive = true
}
public func configure(with name: String, label: String) {
myLabel.text = label
myImageView.image = UIImage(named: name)
}
override func prepareForReuse() {
super.prepareForReuse()
myLabel.text = nil
myImageView.image = nil
}
#objc func didTapButton(_ sender: Any) {
cellDelegate?.onClickCell()
}
}
Secondly, here is the ViewController that the TableView is within.
import UIKit
class NewMoveViewController: UIViewController {
private let tableView: UITableView = {
let tableView = UITableView()
tableView.rowHeight = 100
return tableView
}()
private var collectionView: UICollectionView?
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(tableView)
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = CGSize(width: 50, height: 50)
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView?.register(NewMoveCollectionViewCell.self, forCellWithReuseIdentifier: NewMoveCollectionViewCell.identifier)
collectionView?.showsHorizontalScrollIndicator = false
title = "Add to Group"
tableView.register(NewMoveTableViewCell.self, forCellReuseIdentifier: NewMoveTableViewCell.identifier)
tableView.delegate = self
tableView.dataSource = self
collectionView?.backgroundColor = .systemBlue
collectionView?.dataSource = self
collectionView?.delegate = self
guard let myCollection = collectionView else {
return
}
view.addSubview(myCollection)
// Do any additional setup after loading the view.
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView?.frame = CGRect(x: 0, y: 100, width: view.frame.size.width, height: 50)
tableView.frame = CGRect(x: 0, y: 200, width: view.frame.size.width, height: view.frame.size.height)
}
}
extension NewMoveViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: NewMoveTableViewCell.identifier, for: indexPath) as! NewMoveTableViewCell
cell.cellDelegate = self
cell.configure(with: "", label: "test")
return cell
}
func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
return false
}
}
extension NewMoveViewController : UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: NewMoveCollectionViewCell.identifier, for: indexPath) as! NewMoveCollectionViewCell
return cell
}
}
extension NewMoveViewController : TableViewNew {
func onClickCell() {
print("Pressed")
}
I conformed this ViewController to the protocol from the customized cell and put the function within the cell's cellForRowAt function. When I use this route, I run my app and everything comes up fine, however when I try to click on the customized tableviewcell within the viewcontroller, nothing happens. Any help would be greatly appreciated.
you need to add the action handler to your button:
button.addTarget(self, action: #selector(didTapButton(sender:)), for: .touchUpInside)

Cells won't show in UICollectionView

I'm trying to create a UICollectionView and display few cells there.
This is my code:
class MainVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var mForecast = [CustomCollectionViewCell]()
let CVCellIdentifier = "forecastCell"
lazy var mCollectionView: UICollectionView = {
var collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: 300, height: 150), collectionViewLayout: UICollectionViewFlowLayout())
collectionView.clipsToBounds = true
collectionView.backgroundColor = .red
collectionView.translatesAutoresizingMaskIntoConstraints = false
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(red: 80/255, green: 135/255, blue: 179/255, alpha: 1.0)
setupNavBar()
self.navigationItem.searchController = mSearchBarController
setupMainWeatherIcon()
fillArrayWithData()
mCollectionView.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: CVCellIdentifier)
mCollectionView.dataSource = self
mCollectionView.delegate = self
}
private func fillArrayWithData(){
for _ in 1...6 {
let forecastCell: ForecastCell = ForecastCell()
forecastCell.mDayLabel = "DAY-TEST"
forecastCell.mWeatherIcon = UIImage(named: "partly-cloudy")
forecastCell.mTempLabel = "TEMP-TEST"
mForecast.append(forecastCell)
}
mCollectionView.reloadData()
}
//MARK: COLLECTION VIEW METHODS
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return mForecast.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = mCollectionView.dequeueReusableCell(withReuseIdentifier: CVCellIdentifier, for: indexPath) as! CustomCollectionViewCell
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: (view.frame.width / 6) - 16 , height: 70)
}
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout, insetForSectionAt
section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 10, left: 8, bottom: 10, right: 8)
}
}
This is the CustomCollectionViewCell class:
import UIKit
class CustomCollectionViewCell: UICollectionViewCell {
var mDayLabel: String?
var mWeatherIcon: UIImage?
var mTempLabel: String?
let dayTV: UILabel = {
var label = UILabel()
label.textAlignment = .center
label.font = UIFont.boldSystemFont(ofSize: 12)
label.textColor = .blue
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let weatherImg: UIImageView = {
var img = UIImageView()
img.translatesAutoresizingMaskIntoConstraints = false
return img
}()
let tempLabel: UILabel = {
var label = UILabel()
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 8)
label.textColor = .blue
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
if let label = mDayLabel{
dayTV.text = label
}
if let image = mWeatherIcon{
weatherImg.image = image
}
if let temp = mTempLabel{
tempLabel.text = temp
}
setupDayTextView()
setupWeatherImage()
setupTempLabel()
}
private func setupDayTextView(){
addSubview(dayTV)
dayTV.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
dayTV.topAnchor.constraint(equalTo: self.topAnchor, constant: 10).isActive = true
}
private func setupWeatherImage(){
addSubview(weatherImg)
weatherImg.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
weatherImg.topAnchor.constraint(equalTo: dayTV.bottomAnchor, constant: 10).isActive = true
}
private func setupTempLabel(){
addSubview(tempLabel)
tempLabel.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
tempLabel.topAnchor.constraint(equalTo: weatherImg.bottomAnchor, constant: 10).isActive = true
}
}
Of course I have a method to fill mForecast array with data, if I add a subview I do see the cell, but I know I shouldn't do that to view the cells inside the collection view.
I tried looking but couldn't find what's wrong here and why the cells won't be displayed.
This is what I get
ORIGINAL:
After setting the delegate and the datasource, you need to call collectionView.reloadData()
REVISED:
You are calling fillArrayWithData, which calls reloadData before you finish configuring the collectionView's datasource and delegate. Thus, when reloadData is called, there is no source that sets the data and loads the cells.
Try calling your fillArrayWithData after you finalize the configuration of your collection view.
I personally recommend configuring your collection view in viewDidLoad or in the didSet property observer of collectionView:
var collectionView: UICollectionView! {
didSet {
collectionView.delegate = self
collectionView.dataSource = self
}
}
And then I initiate the load of the data in my viewWillAppear method.
EXAMPLE:
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(red: 80/255, green: 135/255, blue: 179/255, alpha: 1.0)
setupNavBar()
self.navigationItem.searchController = mSearchBarController
setupMainWeatherIcon()
// This is where you are calling fillArrayWithData right now.
// fillArrayWithData()
mCollectionView.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: CVCellIdentifier)
mCollectionView.dataSource = self
mCollectionView.delegate = self
// This is where you should be calling fillArrayWithData
fillArrayWithData()
}

How to define dynamic heights for UICollectionViewCells with a TextView inside

This is a popular question but I'm still not able to find a simple answer of how to define a dynamic height for a UICollectionViewCell with a TextView inside. I found this answer UICollectionView - dynamic cell height? but I'm not using interface and I would like a solution for interfaces built in code.
import UIKit
class ResumeController : UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
let cellId = "cellId"
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
//layout.estimatedItemSize = CGSize(width: 100, height: 100)
layout.minimumLineSpacing = 0
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .white
cv.dataSource = self
cv.delegate = self
cv.translatesAutoresizingMaskIntoConstraints = false
cv.register(FirmCell.self, forCellWithReuseIdentifier: self.cellId)
return cv
}()
override func viewDidLoad() {
view.backgroundColor = .white
setupViews()
}
func setupViews() {
setupCollectionView()
}
func setupCollectionView() {
view.addSubview(collectionView)
collectionView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true
collectionView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
collectionView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: bottomLayoutGuide.topAnchor).isActive = true
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath);
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 100.0)
}
}
class FirmCell : UICollectionViewCell {
let imageView: UIImageView = {
let iv = UIImageView()
iv.backgroundColor = .orange
// iv.image = somelogo
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
lazy var textView: UITextView = {
let tv = UITextView()
tv.isEditable = false
tv.isSelectable = false
tv.isScrollEnabled = false
tv.attributedText = self.attributedText()
tv.translatesAutoresizingMaskIntoConstraints = false
tv.layer.borderWidth = 0.5
tv.layer.borderColor = UIColor.blue.cgColor
return tv
}()
let separatorLine: UIView = {
let view = UIView()
view.backgroundColor = UIColor(white: 0.9, alpha: 1)
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
func attributedText() -> NSAttributedString {
let text = NSMutableAttributedString()
// company
var companyAttr = [String: Any]()
companyAttr[NSFontAttributeName] = UIFont.systemFont(ofSize: 15, weight: UIFontWeightBold)
companyAttr[NSForegroundColorAttributeName] = UIColor.black
text.append(NSAttributedString(string: "line1" , attributes: companyAttr))
// period
var periodAttr = [String: Any]()
periodAttr[NSFontAttributeName] = UIFont.systemFont(ofSize: 14)
periodAttr[NSForegroundColorAttributeName] = UIColor.lightGray
text.append(NSAttributedString(string: " line1" , attributes: periodAttr))
// body
var bodyAttr = [String: Any]()
bodyAttr[NSFontAttributeName] = UIFont.systemFont(ofSize: 14, weight: UIFontWeightThin)
bodyAttr[NSForegroundColorAttributeName] = UIColor.black
text.append(NSAttributedString(string: "\na huge amount of text goes here ... trying to figure out a way to have different collectionview cells row height", attributes: bodyAttr))
return text
}
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupViews() {
setupImageView()
}
func setupImageView() {
addSubview(imageView)
imageView.topAnchor.constraint(equalTo: topAnchor, constant: 9.0).isActive = true
imageView.leftAnchor.constraint(equalTo: leftAnchor, constant: 9.0).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 40.0).isActive = true
setupTextView()
}
func setupTextView() {
addSubview(textView)
textView.topAnchor.constraint(equalTo: imageView.topAnchor, constant: 0).isActive = true
textView.leftAnchor.constraint(equalTo: imageView.rightAnchor, constant: 7.0).isActive = true
textView.rightAnchor.constraint(equalTo: rightAnchor, constant: -9.0).isActive = true
textView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
}
Could someone provide some pointers?

UILabel text not updating even though it has new value, have tried everything

I am using UICollectionView didSelectItemAt to update a UI label that I set up in my HomeController. So basically when I press the cell I want my text to be updated. However the text doesn't update, I have debugged though and the value changes. I have tried everything, both setNeedsDisplay() and running through main thread (which it already does)
I have quite a lot of code in these classes (I don't use storyboard) but this is the label setup (sits in HomeController):
import UIKit
import CoreData
class mainHomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
static let sharedInstance = HomeController()
override func viewDidLoad() {
super.viewDidLoad()
setupBasketBar()
}
let totNumber: UILabel = {
let label = UILabel()
label.text = "0"
label.numberOfLines = 2
return label
}()
func setupBasketBar() {
self.view.addSubview(totNumber)
totNumber.translatesAutoresizingMaskIntoConstraints = false
totNumber.leadingAnchor.constraint(equalTo: view.leadingAnchor,constant: 330).isActive = true
totNumber.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
totNumber.bottomAnchor.constraint(equalTo: view.bottomAnchor,constant: 0).isActive = true
totNumber.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 5).isActive = true
}
}
and this sits in the feed cell:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
HomeController.sharedInstance.totNumber.text = ("234")
HomeController.sharedInstance.totNumber.setNeedsDisplay()
}
I have edited out the relevant parts.
This is the whole code for the HomeController:
import UIKit
import CoreData
class HomeController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
static let sharedInstance = HomeController()
let cellId = "cellId"
let trendingCellId = "trendingCellId"
let subscriptionCellId = "subscriptionCellId"
let titles = ["Home", "Trending", "Subscriptions", "Account"]
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.isTranslucent = false
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 30, height: view.frame.height))
titleLabel.text = "Home"
titleLabel.textColor = UIColor.black
titleLabel.font = UIFont.systemFont(ofSize: 20)
navigationItem.titleView = titleLabel
setupCollectionView()
setupMenuBar()
setupBasketBar()
}
func setupCollectionView() {
if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.scrollDirection = .horizontal
flowLayout.minimumLineSpacing = 0
}
collectionView?.backgroundColor = UIColor.white
collectionView?.register(FeedCell.self, forCellWithReuseIdentifier: cellId)
collectionView?.register(TrendingCell.self, forCellWithReuseIdentifier: trendingCellId)
collectionView?.register(SubscriptionCell.self, forCellWithReuseIdentifier: subscriptionCellId)
collectionView?.contentInset = UIEdgeInsetsMake(50, 0, 0, 0)
collectionView?.scrollIndicatorInsets = UIEdgeInsetsMake(50, 0, 0, 0)
collectionView?.isPagingEnabled = true
}
lazy var settingsLauncher: SettingsLauncher = {
let launcher = SettingsLauncher()
launcher.homeController = self
return launcher
}()
func handleMore() {
//show menu
settingsLauncher.showSettings()
}
func showControllerForSetting(_ setting: Setting) {
let dummySettingsViewController = UIViewController()
dummySettingsViewController.view.backgroundColor = UIColor.white
dummySettingsViewController.navigationItem.title = setting.name.rawValue
navigationController?.navigationBar.tintColor = UIColor.white
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
navigationController?.pushViewController(dummySettingsViewController, animated: true)
}
func handleSearch() {
scrollToMenuIndex(2)
}
func scrollToMenuIndex(_ menuIndex: Int) {
let indexPath = IndexPath(item: menuIndex, section: 0)
collectionView?.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition(), animated: true)
setTitleForIndex(menuIndex)
}
fileprivate func setTitleForIndex(_ index: Int) {
if let titleLabel = navigationItem.titleView as? UILabel {
titleLabel.text = " \(titles[index])"
}
}
lazy var menuBar: MenuBar = {
let mb = MenuBar()
mb.homeController = self
return mb
}()
func buttonAction(sender: UIButton!) {
let btnsendtag: UIButton = sender
if btnsendtag.tag == 1 {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: UINavigationController = storyboard.instantiateViewController(withIdentifier: "NewViewController") as! UINavigationController
self.present(vc, animated: true, completion: nil)
}
}
let totLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 21))
let btn: UIButton = UIButton(frame: CGRect(x: 0, y: 600, width: 500, height: 80))
func setupBasketBar() {
//Checkout button
btn.backgroundColor = UIColor.rgb(36, green: 51, blue: 70)
btn.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
btn.tag = 1
self.view.addSubview(btn)
btn.setTitleColor(UIColor.yellow, for: .normal)
//Button that updates the current amount
totLabel.text = "Total amount"
totLabel.textColor = UIColor.white
self.view.addSubview(totLabel)
//constraints
totLabel.translatesAutoresizingMaskIntoConstraints = false
totLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
totLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
totLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor,constant: 0).isActive = true
totLabel.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 0.1).isActive = true
//oldconstraints
/* self.view.addSubview(totNumber)
totNumber.translatesAutoresizingMaskIntoConstraints = false
totNumber.leadingAnchor.constraint(equalTo: view.leadingAnchor,constant: 330).isActive = true
totNumber.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
totNumber.bottomAnchor.constraint(equalTo: view.bottomAnchor,constant: 0).isActive = true
totNumber.heightAnchor.constraint(equalTo: view.heightAnchor,multiplier: 0.1).isActive = true*/
}
fileprivate func setupMenuBar() {
navigationController?.hidesBarsOnSwipe = false
let redView = UIView()
redView.backgroundColor = UIColor.rgb(36, green: 51, blue: 70)
view.addSubview(redView)
view.addConstraintsWithFormat("H:|[v0]|", views: redView)
view.addConstraintsWithFormat("V:[v0(50)]", views: redView)
view.addSubview(menuBar)
view.addConstraintsWithFormat("H:|[v0]|", views: menuBar)
view.addConstraintsWithFormat("V:[v0(50)]", views: menuBar)
menuBar.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true
}
override func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let index = targetContentOffset.pointee.x / view.frame.width
let indexPath = IndexPath(item: Int(index), section: 0)
menuBar.collectionView.selectItem(at: indexPath, animated: true, scrollPosition: UICollectionViewScrollPosition.centeredHorizontally)
setTitleForIndex(Int(index))
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let identifier: String
if indexPath.item == 1 {
identifier = trendingCellId
} else if indexPath.item == 2 {
identifier = subscriptionCellId
} else {
identifier = cellId
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: view.frame.height - 50)
}
}
Okay! looking at the updated code snippet the sharedInstance singleton is definitely not needed - I'd remove that completely.
The didSelectItemAt method then just needs to be this:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
totNumber.text = "234"
}
I'm guessing your sharedInstance variable is a new instance of the view controller, this is separate from the one that is allocated and displayed from storyboards or segues. You should set sharedInstance equal to self inside viewDidLoad

Swift CollectionView is selecting multiple cell when is set to false

Im currently have a horizontal collection view. I currently have multiple selection enabled set to off. For some reason when I select the first item the item toward the end of the collectionView also become selected. Thank you for the hep.
protocol customDatePickerDelegate:class {
func dateFromCustomDatePicker(date:Date)
}
class datePickerCollectionViewCell:UICollectionViewCell {
var labelNumber:UILabel = UILabel()
var minuteLabel:UILabel = {
let v = UILabel()
v.text = "Minutes"
return v
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .white
minuteLabel.labelFormCustom(labelType: .dateForm)
labelNumber.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(labelNumber)
labelNumber.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 0).isActive = true
labelNumber.centerXAnchor.constraint(equalTo: self.centerXAnchor, constant: 0).isActive = true
minuteLabel.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(minuteLabel)
minuteLabel.centerXAnchor.constraint(equalTo: self.centerXAnchor, constant: 0).isActive = true
minuteLabel.topAnchor.constraint(equalTo: labelNumber.bottomAnchor, constant: 0).isActive = true
self.layer.cornerRadius = 6
self.layer.borderWidth = 0.5
self.layer.borderColor = UIColor(red:205.0/255.0, green:205.0/255.0, blue:205.0/255.0, alpha: 1.0).cgColor
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class NewRquestDatePickerCollectionViewController: UIViewController,UICollectionViewDelegate {
var collectionView:UICollectionView!
override func viewDidLoad() {
setupCollectionView()
}
lazy var centerView:UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 300).isActive = true
v.backgroundColor = .white
v.addBorderCustom(.bottom)
return v
}()
lazy var durationLabel:UILabel = {
let v = UILabel()
v.translatesAutoresizingMaskIntoConstraints = false
v.textAlignment = .center
v.font = v.font.withSize(17)
return v
}()
lazy var topActionBar:UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.heightAnchor.constraint(equalToConstant: 60).isActive = true
v.backgroundColor = UIColor(hex: "F9F9F9")
v.addBorderCustom(.top)
v.addBorderCustom(.bottom)
return v
}()
lazy var doneButton:UIButton! = {
let v = UIButton(type:.system)
v.translatesAutoresizingMaskIntoConstraints = false
v.setTitle("Done", for: .normal)
v.addTarget(self, action: #selector(doneButtonPressed), for: .touchUpInside)
return v
}()
lazy var cancelButton:UIButton = {
let v = UIButton(type:.system)
v.translatesAutoresizingMaskIntoConstraints = false
v.setTitle("Cancel", for: .normal)
v.addTarget(self, action: #selector(dismissCurrentView), for: .touchUpInside)
return v
}()
lazy var dayLabel:UILabel = {
let v = UILabel()
// v.text = "Monday"
return v
}()
lazy var titleView:UILabel = {
let v = UILabel()
v.text = "Select a deadline"
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
var selectedIndexPath: NSIndexPath?
// var selectedTime:Int!
var timer = Timer()
var timeSeleted:TimeInterval = 10.0
let timeArray:[TimeInterval] = [10,20,30,45,60,140,400,900,1200]
var delegate:customDatePickerDelegate!
var dateSelected:Date!
func setupCollectionView(){
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
//collection view setup
self.view.addSubview(centerView)
centerView.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 0).isActive = true
centerView.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: 0).isActive = true
centerView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0).isActive = true
collectionView = UICollectionView(frame: view.frame, collectionViewLayout: layout)
collectionView.register(datePickerCollectionViewCell.self, forCellWithReuseIdentifier: "imageCell")
collectionView.delegate = self
collectionView.dataSource = self
centerView.addSubview(topActionBar)
topActionBar.heightAnchor.constraint(equalToConstant: 49).isActive = true
topActionBar.leftAnchor.constraint(equalTo: self.centerView.leftAnchor, constant: 0).isActive = true
topActionBar.rightAnchor.constraint(equalTo: self.centerView.rightAnchor, constant: 0).isActive = true
topActionBar.topAnchor.constraint(equalTo: self.centerView.topAnchor, constant: 0).isActive = true
topActionBar.addSubview(cancelButton)
topActionBar.addSubview(titleView)
cancelButton.leftAnchor.constraint(equalTo: topActionBar.leftAnchor, constant: 16).isActive = true
cancelButton.centerYAnchor.constraint(equalTo: topActionBar.centerYAnchor, constant: 0).isActive = true
titleView.centerXAnchor.constraint(equalTo: topActionBar.centerXAnchor, constant: 0).isActive = true
titleView.centerYAnchor.constraint(equalTo: topActionBar.centerYAnchor, constant: 0).isActive = true
centerView.addSubview(doneButton)
centerView.addBorderCustom(.bottom)
doneButton.centerXAnchor.constraint(equalTo: centerView.centerXAnchor, constant: 0).isActive = true
doneButton.bottomAnchor.constraint(equalTo: centerView.bottomAnchor, constant: -20).isActive = true
centerView.addBorderCustom(.bottom)
centerView.addSubview(collectionView)
collectionView.heightAnchor.constraint(equalToConstant: 100).isActive = true
collectionView.leftAnchor.constraint(equalTo: self.centerView.leftAnchor, constant: 0).isActive = true
collectionView.rightAnchor.constraint(equalTo: self.centerView.rightAnchor, constant: 0).isActive = true
collectionView.topAnchor.constraint(equalTo: self.topActionBar.bottomAnchor, constant: 0).isActive = true
dayLabel.translatesAutoresizingMaskIntoConstraints = false
centerView.addSubview(dayLabel)
dayLabel.centerXAnchor.constraint(equalTo: collectionView.centerXAnchor, constant: 0).isActive = true
dayLabel.topAnchor.constraint(equalTo: collectionView.bottomAnchor, constant: 20).isActive = true
centerView.addSubview(durationLabel)
durationLabel.leftAnchor.constraint(equalTo: self.centerView.leftAnchor, constant: 0).isActive = true
durationLabel.rightAnchor.constraint(equalTo: self.centerView.rightAnchor, constant: 0).isActive = true
durationLabel.topAnchor.constraint(equalTo: self.collectionView.bottomAnchor, constant: 0).isActive = true
durationLabel.bottomAnchor.constraint(equalTo: self.doneButton.topAnchor, constant: 20).isActive = true
timerStart()
collectionView.showsHorizontalScrollIndicator = false
collectionView.showsVerticalScrollIndicator = false
collectionView.contentInset = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
collectionView.isPagingEnabled = true
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = UIColor(hex:"EFF3F4")
centerView.addBorderCustom(.bottom)
collectionView.allowsMultipleSelection = false
}
}
extension NewRquestDatePickerCollectionViewController {
func dismissCurrentView(){
self.dismiss(animated: true , completion: nil)
}
func doneButtonPressed(){
delegate.dateFromCustomDatePicker(date: dateSelected)
dismissCurrentView()
}
func tappedDeadlineSelection(){
}
func timerStart(){
if #available(iOS 10.0, *) {
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { (timer) in
let date = Date()
let adjustedDate = date.addingTimeInterval(self.timeSeleted * 60.0)
self.dateSelected = adjustedDate
self.durationLabel.text = String(describing: adjustedDate.string(withFormat: "MM/dd/yy, h:mm a"))
self.dayLabel.text = String(describing: adjustedDate.string(withFormat: "EEEE"))
})
} else {
// Fallback on earlier versions
}
}
}
extension NewRquestDatePickerCollectionViewController:UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return timeArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! datePickerCollectionViewCell
cell.awakeFromNib()
return cell
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
let cellInfo = cell as! datePickerCollectionViewCell
//converTime
cellInfo.labelNumber.text = String(self.timeArray[indexPath.row])
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! datePickerCollectionViewCell
let timeAdded = self.timeArray[indexPath.row]
cell.backgroundColor = UIColor(hex: "F2784B")
// let timeAdded = self.timeArray[indexPath.row]
cell.labelNumber.textColor = .white
cell.minuteLabel.textColor = .white
cell.layer.borderColor = UIColor.white.cgColor
timeSeleted = timeAdded
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizontally)
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! datePickerCollectionViewCell
cell.backgroundColor = .white
cell.labelNumber.textColor = .black
cell.minuteLabel.textColor = UIColor().RquestCustomColors(.fontGray)
// collectionView.performBatchUpdates(nil, completion: nil)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 64, height: 64)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 30.0
}
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 30.0
}
}
Because you are reusing existed cell, you should keep track selected item index and update cell state as below:
var selectedIndex: IndexPath?
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! datePickerCollectionViewCell
let timeAdded = self.timeArray[indexPath.row]
cell.backgroundColor = UIColor(hex: "F2784B")
// let timeAdded = self.timeArray[indexPath.row]
cell.labelNumber.textColor = .white
cell.minuteLabel.textColor = .white
cell.layer.borderColor = UIColor.white.cgColor
timeSeleted = timeAdded
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .centeredHorizontally)
// add the following codes
let lastSelectedIndex = self.selectedIndex
self.selectedIndex = indexPath
// unselect last selected index
collectionView.reloadItems(at: [lastSelectedIndex!])
// reload new selected index
collectionView.reloadItems(at: [self.selectedIndex!])
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
let cellInfo = cell as! datePickerCollectionViewCell
//converTime
cellInfo.labelNumber.text = String(self.timeArray[indexPath.row])
// add this line of code
cell.isSelected = (self.selectedIndex == indexPath)
}
You should make use of the "isSelected" method for the collection view cell. This way you will not have not save any selected indexpath.
So I recommend using this method:
Firstly,
collectionView.allowsMultipleSelection = false
on the UICollectionViewCell you can override the isSelected method
didSet {
if isSelected {
// Change UI for selected state
radioButton.setImage(#imageLiteral(resourceName: "greenTick"), for: .normal)
} else {
// Chage UI for unselected state
radioButton.setImage(#imageLiteral(resourceName: "radioInactive"), for: .normal)
}
}
Finally when you need to find out the indexpath for the selected item.
guard let selectedIndex = self.collectionView.indexPathsForSelectedItems?.first else { return }

Resources