50

I have one tableview and each cell contains one button. It's working pretty well all iOS versions but 7. I don't know what's going on. The cell is constructed in one xib file.

Could anyone give me some suggestions? Thanks in advance.

Xavier
  • 517
  • 1
  • 4
  • 5
  • 11
    Had same problem just now. Solved by making sure the button is added to the content view (ie. [self.contentView addSubview:button]), which appears to have changed between iOS6 and iOS7. FWIW, I think the question is reasonably clear. The only code I can think to add is all the generic UITableView stuff. – mblackwell8 Sep 18 '13 at 03:46
  • 11
    Tired of guys putting things on hold without even trying to understand the thing. I have the same problem and it is pretty clear once you experience it! No code is required. Really the breaking change in iOS7. – Stanislav Dvoychenko Sep 18 '13 at 20:51
  • hi guys, facing same problem, i am using custom nib for cells and suddenly they are all not interactive in ios7.. any clue? – mkto Sep 26 '13 at 03:27
  • @Xavier - can you put on github ? – DogCoffee Sep 28 '13 at 05:56
  • May be you need to create custom cell class and add everything in content view ratherthen XIB. this was work for me.. no XIB needed just usr [self.ContentView addSubView:yourbutton] – Dipen Chudasama Sep 30 '13 at 09:17
  • I have the exact same button. THe 2 answers do not answer this for me. The buttons are subviews of subviews of self.Contentview. – user4951 Oct 11 '13 at 05:16

24 Answers24

70

What worked for me is this:

contentView.userInteractionEnabled = NO;

called after loading my custom cell from nib. It looks like this content view is created and set as a top-level child view after creating views defined in the nib file.

b005t3r
  • 716
  • 5
  • 8
  • 1
    Technically the button is a subview of contentView. Setting it to 0 will disable the button. What am I missing? – user4951 Oct 10 '13 at 08:08
  • I also don't understand why this solution works (and also yonix's solutions didn't do the trick for me). Logic says that contentView for cell will be like view for viewController... – Aviel Gross Oct 14 '13 at 14:55
  • 16
    This works if you created your custom UITableViewCell prior to Xcode 5, because the contentView is new for iOS 7. If your cell is the "old style", the contentView will be obscuring it, which is why this works in those cases. For those of us who already have our button as a subview of contentView, this doesn't work and the journey for a solution continues. – Bek Oct 19 '13 at 16:56
  • Thank you so much :) Literally you saved my life. I had to freeze my code today :) – Srikanth Feb 24 '16 at 14:45
32

Calling [cell bringSubviewToFront:button] after loading the cell from nib solved this for me.

yonix
  • 11,665
  • 7
  • 34
  • 52
  • 4
    It doesn't work for me. Also button is already on the "frontiest" – user4951 Oct 10 '13 at 10:42
  • @JimThio I actually just found the solution here: https://devforums.apple.com/message/877894#877894, not sure why it works. I guess there's a bug in iOS7 that messes up the view order when loading the cell from nib. – yonix Oct 13 '13 at 07:32
  • 4
    The reason this works is iOS 7 introduces an intermediate `contentView` subview that responds to cell touches. If this view is overtop of your button, it will receive the touch instead of the button. `bringSubviewToFront` ensures your button is at the top of the view stack. – devios1 Jan 08 '14 at 19:24
  • 1
    Great answer Yonix. I have tried all the solutions but none of them works out. thanks for the nice and simple answer – SURESH SANKE May 13 '16 at 10:05
30

I have also struggled with this problem and I did a lot of research over the different answers on stackoverflow and internet, the solution is different depending on the source of the problem. For the most case, you need to do the following with the element that is supposed to take user action (tap/click etc.):
myButton.userInteractionEnabled = YES;

Particularly for UILabel/UIImageView, by default the userInteractionEnabled flag is NO.

If you are loading the view from a xib, you need make sure, from the custom cell view, content view, and the element you want the user action enabled, all have the check box checked:
enter image description here

In the example above, DeviceViewCell, Content View and Button element all have "User Interaction Enabled" check box checked.
If the custom cell is implemented as a sub class of UITableViewCell, and the custom cell view is loaded from another xib file dynamically, you HAVE TO DO one more thing which is confusing to most of the people but I will explain why later on:
In the custom cell's initialization method, you need to do the following:
self.contentView.userInteractionEnabled = NO

where self is the subclass of UITableViewCell you created. Again, IF the custom cell is implemented as a sub class of UITableViewCell, and the custom cell view is loaded from another xib file DYNAMICALLY, you need to do the above. Here is the explanation:

self.contentView is NOT the same Content View you see in Interface Builder, it is created by the system as the default content view that is on TOP of every other views/elements within your custom cell view, and it obscures the rest of views in the view hierarchy. Hence, you will need to disable the user interaction for it before the UI elements in the custom cell view can receive user interaction events. Hope this helps. If you have a better explanation I would love to hear it :-). Again is is my observation and there could be other reasons. Discussion is welcome!

us_david
  • 4,431
  • 35
  • 29
  • Thanks a lot us_davis, you solve my problem! Disable the cell contentView userInteraction to gain cell interaction is very weird. I really don't understand why the cell.contentView comes overs the other views... – Martin Dec 01 '14 at 18:05
  • I guess there is disconnection between Xcode and interface builder. Somehow a default content view is created before loading the custom UITableViewCell, I suspect Xcode needs to do so to avoid issue such that there is no content view to accommodate the custom cell view. If you do have a content view it will still use its default content view on top of your own. I spent quite sometime to find out. – us_david Dec 01 '14 at 20:44
  • Well observed regarding the `self.contentView`. That was the root cause. – Tchelow Feb 03 '15 at 05:19
  • It took me a while to find out it is the case. I am glad this helps others with similar issues. – us_david Feb 03 '15 at 19:43
  • Thanks! This was exactly my problem, and in the 3d debug view hierarchy indeed the tableviewcell's contentView was in front of everything else. – Doug Voss May 31 '16 at 01:50
6

The problem is that your nib is not containing a contentView, as required since the iOS 8 SDK (I'm writing by experience, don't have a viable source, sorry).

When you add an UITableViewController to a storyboard, an UITableViewCell is added to it's UITableView automatically. If you take a look at this UITableView, you'll see a contentView in it.

So when you subclass an UITableViewCell and create it with a .xib, you'll have to click&drag a UITableViewCell to the xib instead of the default UIView. Then don't forget to set the File Owner class and the UITableViewCell class to your subclass.

Dulgan
  • 6,674
  • 3
  • 41
  • 46
5

The solution to this problem is;

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {    
cell.bringSubviewToFront(cell.YOUR_UIView)    
}

This works for me.

ArK
  • 20,698
  • 67
  • 109
  • 136
4

I experienced the same issue. It turns out I had created a UIView object in IB and then set it's class to a subclass of UITableViewCell.

Since the object I originally created in IB was a UIView, the UITableViewCell contentView didn't get added until runtime, which happened to be on top of my UIButtons making them un-selectable.

Collin
  • 6,720
  • 4
  • 26
  • 29
4

Clearly, there are a number of things that can go wrong and some fixes work on certain iOS versions and not on others.

My problem was that I had a UIButton that was not an immediate subview of cell.contentView (i.e. it was a subview of a subview). I had to add my button directly to cell.contentView in order for it to be tappable. (iOS v8+)

mikejonesguy
  • 9,779
  • 2
  • 35
  • 49
3

My Cell's outline

In my case, everything that I would like the user to interact with is outside of the ContentView. Also I do not want the cell to be highlighted when it is selected.

All labels (Name, Categories, etc.) are immediately under "Content View". The WebsiteButton is not under "Content View", but it is under "Local Directory Table Cell".

In my tableViewController method tableView:cellForRowAtIndexPath: I have the following code: cell.contentView.userInteractionEnabled = NO;

That is all and the user is able to interact with the button. I do NOT use [cell bringSubviewToFront:cell.websiteButton];

3

I have been get the same problem. The reason is

self.contentView.Frame.size.height

is always 44.

There is a suggestion you can set your self.contentView.Frame to self.frame at the overwrite method - (void)layoutSubviews the problem will be solved

Drakes
  • 23,254
  • 3
  • 51
  • 94
Snail
  • 31
  • 1
2

As others have pointed out, always add subviews to the cell's content view. If you have overridden layoutSubviews method, make sure to call the super implementation. Forgetting to call the super implementation yields unexpected results.

diatche
  • 99
  • 5
2

I had same issue with a UIButton in a prototype cell in my storyboard. I solved it by checking "User Interaction Enabled" on the prototype cell. This worked on iOS 7.1.

Mike Taverne
  • 9,156
  • 2
  • 42
  • 58
2

The most obvious mistake I haven't seen described here is that you MUST have a selectedBackgroundImage for a UIButton to look different when selected. These are not like, say, UITableViewCells.

myButton.setBackgroundImage(UIImage(named: "ButtonBackgroundSelected.png"), forState: .Highlighted)
AppreciateIt
  • 696
  • 2
  • 8
  • 23
2

I had subclassed UITableViewCell and solved it by changing this code:

addSubview(myButton)

to this:

contentView.addSubview(myButton)

in my UITableViewCell subclass.

Bavafaali
  • 388
  • 1
  • 5
  • 14
1

I faced a similar issue on both UITableViewCell and UICollectionViewCell. Few steps to follow:

  1. Always add subviews to content view of the cell view and NOT the cell view itself
  2. If you are adding a container view (which contains your button), disable the auto layout of the container view and enable the auto layout only for the contents inside the container view. Use frame layout for the container view.

In short, TableView/CollectionView cells cannot take actionable subviews (UIButton, UISegmentedControl) that are auto-layout enabled. If you have a need for it, either disable auto-layouts and provide frames (or) put them inside a container view (Container view should have auto layout disabled) and add the actionable views (with auto layout) as subviews to the container view.

Visu
  • 159
  • 1
  • 6
1

In my case, I need to check the "User Interaction Enabled" for the cell itself (not just the contentView) as well. But as noted in other answers, there could be multiple reasons for why this is happening so I am sure this won't work for every case.

enter image description here

Jove Kuang
  • 322
  • 2
  • 12
0

When you are using Interface Builder (Storyboard) then be sure to check the User Interaction Enabled checkbox from the Content View

gpichler
  • 2,181
  • 2
  • 27
  • 52
0

None of these answers worked for me.

The only way I was able to fix this problem was to set the table cell selection from single to none. After that, I was able to receive button call backs.

Isaac Paul
  • 1,959
  • 2
  • 15
  • 20
0

Wired enough, the actually solution for me is to go to storyboard, select the contentview in the cell, and check the "userInteractionEnabled"... otherwise even if you have enabled userInteraction at the button or the cell, contentview will always block the action.

Summer
  • 488
  • 4
  • 14
0

I had transparent view on that cell which implemented some internal features and handled on touches on self.

Nikolay Shubenkov
  • 3,133
  • 1
  • 29
  • 31
0

I checked everything but I made silly mistake of In storyboard my button's superview was below some other view. so touch was not passing to my button.

Siddhesh Mahadeshwar
  • 1,591
  • 14
  • 16
0

My problem was that I was adding UIButton as subview of UIImageView which has user interaction disabled by default. So I had to enable it:

imageView.isUserInteractionEnabled = true
Robert Dresler
  • 10,580
  • 2
  • 22
  • 40
0

In Swift 5, I create a class UITableViewCell and I create a UIButton.

class DashboardingGameTableViewCell: UITableViewCell {
    
    // MARK: Setup Views
    
    var showInteractiveButton: UIButton = {
        let interactive = UIButton()
        interactive.setTitle("", for: .normal)
        interactive.contentEdgeInsets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0)
        interactive.setImage(UIImage(systemName: "ellipsis"), for: .normal)
        interactive.tintColor = .white
        interactive.backgroundColor = .clear
        interactive.translatesAutoresizingMaskIntoConstraints = false
        
        return interactive
    }()
    ...

and on my

class DashboardingGameViewController: UIViewController, UITableViewDelegate, UITableViewDataSource...

The UIButton was not clickable

for It works I have to make...

on DashboardingGameViewController: UITableViewCell...

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    
    contentView.isUserInteractionEnabled = false
    addSubview(showInteractiveButton)
...

on DashboardingGameViewController: UIViewController, UITableViewDelegate, UITableViewDataSource...

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: reusableIdentifier,
                                                            for: indexPath) as! DashboardingGameTableViewCell
        
        cell.showInteractiveButton.addTarget(self, action: #selector(interactiveGames(_:)), for: .touchUpInside) 
    ...
  
// MARK: - Private Funcs 
    
@objc private func interactiveGames(_ button: UIButton) {
                present(ShowInteractiveGameViewController(), animated: true, completion: nil)
}
Brave
  • 29
  • 2
0

If you have a CUSTOM cell class, simply include self.selectionStyle = .none in awakeFromNib()

override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        self.selectionStyle = .none
    }
Ruchir Baronia
  • 7,406
  • 5
  • 48
  • 83
-1

Okay, I've found a solution to this issue, but it appears to be a huge hack; however, it is all I was able to come up with (nothing else here worked for me).

Overtop of my button I've added a UITextField which delegates to the table view cell in question. That tableViewCell instance implements -(BOOL) textFieldShouldBeginEditing:(UITextField *)textField and returns NO.

dave
  • 1,150
  • 1
  • 13
  • 22