I have a button inside a collectionview cell that I programmatically created.
@IBAction func editButtonTapped() -> Void {
print("Hello Edit Button")
}
j
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let editButton = UIButton(frame: CGRect(x: 8, y: 241, width: 154, height: 37))
editButton.setImage(UIImage(named: "background-1 (dragged).tiff"), for: UIControlState.normal)
editButton.addTarget(self, action: #selector(editButtonTapped), for: UIControlEvents.touchUpInside)
editButton.tag = indexPath.row
editButton.isUserInteractionEnabled = true
cell.addSubview(editButton)
cell.bringSubview(toFront: editButton)
}
But when I click on the button, nothing happens (it doesn't show "Hello Edit Button"). What am I missing
There are a few things you should do differently, but this works fine for me (pretty much just the code you posted):
class TestCollWithBtnsCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
@IBAction func editButtonTapped() -> Void {
print("Hello Edit Button")
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
{
return CGSize(width: 200.0, height: 200.0)
}
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 8
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.backgroundColor = .orange
// this is the WRONG way to do this...
// 1) the button is being added avery time a cell is reused
// 2) the button should be added to the cell.contentView (not the cell itself)
// 3) much better ways to track than setting the button .tag to the row
// 4) target for the button action is "self" - locks you into a bad structure
// however, this can help us debug the problem
let editButton = UIButton(frame: CGRect(x: 8, y: 41, width: 154, height: 37))
// I don't have an image, so I set a button title and background color
editButton.setTitle("\(indexPath.row)", for: .normal)
editButton.backgroundColor = .red
// editButton.setImage(UIImage(named: "background-1 (dragged).tiff"), for: UIControlState.normal)
editButton.addTarget(self, action: #selector(editButtonTapped), for: UIControlEvents.touchUpInside)
editButton.tag = indexPath.row
editButton.isUserInteractionEnabled = true
cell.addSubview(editButton)
return cell
}
}
If you can see your button in your collection view cells, then your code (assuming you have the cell being created correctly) should have worked.
The fact that you also have the line:
cell.bringSubview(toFront: editButton)
kinda makes me think you don't see the button... Possibly your Y
coordinate of 241
places it outside the cell frame?
What's happening is the collection view is capturing the touch events and processing them. You need to specify that the collection view needs to pass the touch event to its subclasses.
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
//loop through the cells, get each cell, and run this test on each cell
//you need to define a proper loop
for cell in cells {
//if the touch was in the cell
if cell.frame.contains(point) {
//get the cells button
for uiview in cell.subviews {
if uiview is UIButton {
let button = uiview as! UIButton
//if the button received the touch, return it, if not, return the cell
if button.frame.contains(point) {
return button
}
else {
return cell
}
}
}
}
}
//after the loop, if it could not find the touch in one of the cells return the view you are on
return view
}