1

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

rmaddy
  • 314,917
  • 42
  • 532
  • 579
juelizabeth
  • 485
  • 1
  • 8
  • 31
  • Can you see the button? – Adeel Miraj May 03 '17 at 20:25
  • Is the action function in the cell class or in the collection view controller class? You have specified the target for the action as "self", which will be the view controller. Your approach will give you problems, since storing the tag in the cell is fragile. Also you appear to be adding the button each time the cell is used, but maybe you just simplified your code – Paulw11 May 03 '17 at 20:50
  • I suggest you use one of the approaches in [these answers](http://stackoverflow.com/questions/28659845/swift-how-to-get-the-indexpath-row-when-a-button-in-a-cell-is-tapped/38941510#38941510) – Paulw11 May 03 '17 at 20:52

2 Answers2

4

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?

DonMag
  • 69,424
  • 5
  • 50
  • 86
  • Y coordinate of 241 is where I need the button to be, how will I change the cell frame. I have tried changing it on storyboard but it is still not working. – juelizabeth May 03 '17 at 21:39
  • How are you setting the cell size now? Using constraints to auto-size it? Are you implementing `sizeForItemAt indexPath:`? – DonMag May 03 '17 at 22:09
  • `func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: CGFloat((collectionView.frame.size.width / 5) - 20), height: CGFloat(300)) }` @DonMag – juelizabeth May 03 '17 at 22:14
  • @juelizabeth - well, that *should* be fine... you're setting the cell height to `300` so no problem putting a button at `Y:241`. I *do* wonder about the width though... `((collectionView.frame.size.width / 5) - 20)` makes for a pretty narrow cell... on a 7+ it's `63 pts` in portrait, `127 pts` in landscape, but you're setting the button width to `154`? So is the issue that you are just not seeing your button? – DonMag May 04 '17 at 12:13
  • I can see the button perfectly. When I put the button to Y = 41 it works fine and it is clickable but at Y = 241 the button is still visible but not clickable – juelizabeth May 04 '17 at 13:42
  • Well, that's rather odd... Try various `Y` values? As you increase `Y`, is there a specific point where the button is no longer "tappable"? Is there a point where the top portion of the button can be tapped, but the lower portion cannot? I assume you have other objects in the cell? Is there other code setting positions that might interfere? Are some objects using auto-layout and others are not? Have you tried using Debug View Hierarchy to see where the objects are *really* showing up? – DonMag May 04 '17 at 13:58
  • do you think it has anything to do with the preserve supervise margins – juelizabeth May 04 '17 at 15:02
  • I would have to see more of your code / project... Obviously, the cod you posted in your original question was *not* actual runnable code, so we don't know what else is going on. superview margins relate to the size / position of objects based on constraints. What we've looked at so far, you are not setting any constraints... – DonMag May 04 '17 at 15:20
-5

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

}
Jacob
  • 425
  • 3
  • 13