Reputation: 2890
I have a button embedded in a UICollectionViewCell with the below structure, when I try to tap button, neither the button UI changes nor the associated function gets called, this behaviour is seen in iOS 12 (iPhone 8) and not in iOS 10 (iPhone 5)
UITableView > UITableViewCell > UICollectionView > UICollectionViewCell > UIButton
The following screenshot shows the tableViewCell with collectionViewCells.
Below is the code:
TableView class AppointmentTVC: UITableViewController {
var appointmentTimesCollectionTVCell = AppointmentTimesCollectionTVCell()
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
appointmentTimesCollectionTVCell.appointmentTimesToDisplay = self.appointmentTimesToDisplay
appointmentTimesCollectionTVCell.isUserInteractionEnabled = true
//appointmentTimesCollectionTVCell.selectionStyle = .none
return appointmentTimesCollectionTVCell
}
}
The below is the tableview cell that holds the collectionViewCells
class AppointmentTimesCollectionTVCell: UITableViewCell {
var notificationCenter = NotificationCenter.default
let collectionView:UICollectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: UICollectionViewFlowLayout.init())
var layout:UICollectionViewFlowLayout = UICollectionViewFlowLayout.init()
let collectionViewCellId = "Cell"
var cellDimensionsArray = [CGSize]()
var appointmentTimes = [Date]()
var indexOfSelectedItem : Int?
var appointmentTimesToDisplay : [Date]{
set(appointmentTimesToSet){ // This method is called whenever appointmentTimesToDisplay is set
appointmentTimes = appointmentTimesToSet
print("appointmentTimesBeingSet: \(appointmentTimes)")
collectionView.reloadData() // This is used to reload images
}
get{
return appointmentTimes
}
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
// Configure CollectionView
collectionView.register(ButtonCVCell.self, forCellWithReuseIdentifier: collectionViewCellId)
collectionView.isScrollEnabled = true // To scroll collectionview inside cell
layout.scrollDirection = .horizontal
layout.minimumInteritemSpacing = CGFloat(10.0) // The minimum spacing to use between items in the same row.
layout.minimumLineSpacing = CGFloat(10.0) // The minimum spacing to use between lines of items in the grid.
collectionView.setCollectionViewLayout(layout, animated: true)
collectionView.backgroundColor = Colors.white
collectionView.delegate = self as UICollectionViewDelegate
collectionView.dataSource = self as UICollectionViewDataSource
collectionView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(collectionView)
let viewsDict = [
"collectionView" : collectionView
] as [String : Any]
// collectionView Constraints
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-5-[collectionView]-5-|", options: [], metrics: nil, views: viewsDict))
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-5-[collectionView]-5-|", options: [], metrics: nil, views: viewsDict))
}
}
extension AppointmentTimesCollectionTVCell: UICollectionViewDelegateFlowLayout {
// FOR SETTING FIXED SIZES
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// setting the standard widths of 80 and height 30.0 as default to ensure correct collection view cell size
// These have been obtained by printing intrinsicContent size width in function cellforItem at
if cellDimensionsArray.count == 0 { return CGSize(width:80.0, height: 30.0) }
let _cellDimension = cellDimensionsArray[indexPath.item]
return _cellDimension
}
}
extension AppointmentTimesCollectionTVCell: UICollectionViewDataSource {
// MARK: UICollectionViewDataSource
func numberOfSections(in collectionView: UICollectionView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return appointmentTimes.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let item = indexPath.item
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionViewCellId, for: indexPath) as? ButtonCVCell
let appointmentTimeObject = appointmentTimes[item]
let appointmentTimeString = " " + DateFormatter().standardDateFormatter.string(from: appointmentTimeObject) + " "
print("indexOfSelectedItem: \(indexOfSelectedItem), item: \(item)")
// This is to ensure that only the selected item color stays and remainder are set to default
if indexOfSelectedItem == item{
cell?.button.backgroundColor = Colors.curieBlue
cell?.button.layer.borderColor = Colors.curieBlue.cgColor
cell?.button.setTitleColor(Colors.white, for: .normal)
} else{
cell?.button.layer.borderWidth = 1
cell?.button.layer.borderColor = Colors.lightGrey.cgColor
cell?.button.backgroundColor = Colors.white
cell?.button.setTitleColor(Colors.curieBlue, for: .normal)
}
cell?.button.tag = item
cell?.button.setTitle(appointmentTimeString , for: .normal)
//cell?.button.addTarget(self, action: #selector(setSelectedTime(sender:)), for: .touchUpInside)
cell?.button.addTarget(self, action: #selector(setSelectedTime(sender:)), for: .touchUpInside)
print("buttonTagSetForTheButton: \(cell)")
if let intrinsicContentSize = cell?.button.intrinsicContentSize {
//let intrinsicContentSize = cell?.button.intrinsicContentSize
let cellWidth = intrinsicContentSize.width
let cellHeight = intrinsicContentSize.height
let cellDimension = CGSize(width: cellWidth, height: cellHeight)
if cellDimensionsArray.count <= appointmentTimes.count{ // Setting dimensions for new cells
cellDimensionsArray.append(cellDimension)
}else{ // Replacing dimensions for existing cells
cellDimensionsArray[item] = cellDimension
}
}
return cell ?? UICollectionViewCell()
//return cell
}
func setSelectedTime(sender: UIButton){
print("setSelectedTimeFuncCalled")
let selectedTime = appointmentTimes[sender.tag]
self.indexOfSelectedItem = sender.tag
let timestamp = selectedTime.timeIntervalSince1970 // Get the Unix timestamp
// Posting a local notification
let selectedAppointmentTimeDict = ["selectedAppointmentTime" : Int(timestamp)]
notificationCenter.post(name: Notification.Name(NotificationNames.appointmentTimeSelected), object: nil, userInfo: selectedAppointmentTimeDict)
self.collectionView.reloadData()
}
}
The below code is used to produce collection view cells with buttons.
class ButtonCVCell: UICollectionViewCell {
let button : UIButton = {
let btn = UIButton(type: .system)
btn.tintColor = Colors.curieBlue
btn.frame = CGRect(x: 0, y: 0, width: 20, height: 20)
btn.layer.cornerRadius = 5
btn.sizeToFit()
return btn
}()
var cellWidthConstraint : NSLayoutConstraint!
var cellWidth : CGFloat{
set(width){
self.cellWidthConstraint.constant = width
self.cellWidthConstraint.isActive = true
print("SettingCellsWidth: \(width)")
}
get{
return self.cellWidthConstraint.constant
}
}
override func awakeFromNib() {
super.awakeFromNib()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
fatalError("init(coder:)")
}
override init(frame: CGRect) {
super.init(frame: frame)
self.contentView.translatesAutoresizingMaskIntoConstraints = false
self.cellWidthConstraint = NSLayoutConstraint(item: contentView, attribute: .width, relatedBy: .equal, toItem: nil, attribute:.notAnAttribute, multiplier: 0, constant: 0.0)
button.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(button)
let viewsDict = [
"button" : button
] as [String : Any]
// Button Constraints
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[button(30)]|", options: [], metrics: nil, views: viewsDict))
contentView.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[button]", options: [], metrics: nil, views: viewsDict))
}
}
Upvotes: 0
Views: 979
Reputation: 607
Each collection view cell is button. Use collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) instead
Upvotes: 1
Reputation: 6380
I think the problem is you are trying to use AutoLayout in the CollectionViewCell's ContentView, but CollectionViews use frames.
It is fine if you use AutoLayout for your Button inside the Cell, but the ContentView should resize by itself.
Try removing these lines:
// ButtonCVCell
var cellWidthConstraint : NSLayoutConstraint!
var cellWidth : CGFloat{
set(width){
self.cellWidthConstraint.constant = width
self.cellWidthConstraint.isActive = true
print("SettingCellsWidth: \(width)")
}
get{
return self.cellWidthConstraint.constant
}
}
And these:
// ButtonCVCell override init(frame: CGRect)
self.contentView.translatesAutoresizingMaskIntoConstraints = false
self.cellWidthConstraint = NSLayoutConstraint(item: contentView, attribute: .width, relatedBy: .equal, toItem: nil, attribute:.notAnAttribute, multiplier: 0, constant: 0.0)
Upvotes: 0