UITableview: How to Disable Selection for Some Rows but Not Others

I am displaying in a group tableview contents parsed from XML. I want to disable the click event on it (I should not be able to click it at all) The table contains two groups. I want to disable selection for the first group only but not the second group. Clicking the first row of second group navigates to my tube player view.

How can I make just specific groups or rows selectable?

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    if(indexPath.section!=0)
    if(indexPath.row==0)    

    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:tubeUrl]];   
}

Thanks.


Solution 1:

You just have to put this code into cellForRowAtIndexPath

To disable the cell's selection property: (while tapping the cell)

cell.selectionStyle = UITableViewCellSelectionStyleNone;

To enable being able to select (tap) the cell: (tapping the cell)

// Default style
cell.selectionStyle = UITableViewCellSelectionStyleBlue;

// Gray style
cell.selectionStyle = UITableViewCellSelectionStyleGray;

Note that a cell with selectionStyle = UITableViewCellSelectionStyleNone; will still cause the UI to call didSelectRowAtIndexPath when touched by the user. To avoid this, do as suggested below and set.

cell.userInteractionEnabled = NO;

instead. Also note you may want to set cell.textLabel.enabled = NO; to gray out the item.

Solution 2:

If you want to make a row (or subset of rows) non-selectable, implement the UITableViewDelegate method -tableView:willSelectRowAtIndexPath: (also mentioned by TechZen). If the indexPath should be not be selectable, return nil, otherwise return the indexPath. To get the default selection behavior, you just return the indexPath passed to your delegate method, but you can also alter the row selection by returning a different indexPath.

example:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // rows in section 0 should not be selectable
    if ( indexPath.section == 0 ) return nil;

    // first 3 rows in any section should not be selectable
    if ( indexPath.row <= 2 ) return nil;

    // By default, allow row to be selected
    return indexPath;
}

Solution 3:

Starting in iOS 6, you can use

-tableView:shouldHighlightRowAtIndexPath:

If you return NO, it disables both the selection highlighting and the storyboard triggered segues connected to that cell.

The method is called when a touch comes down on a row. Returning NO to that message halts the selection process and does not cause the currently selected row to lose its selected look while the touch is down.

UITableViewDelegate Protocol Reference

Solution 4:

None from the answers above really addresses the issue correctly. The reason is that we want to disable selection of the cell but not necessarily of subviews inside the cell.

In my case I was presenting a UISwitch in the middle of the row and I wanted to disable selection for the rest of the row (which is empty) but not for the switch! The proper way of doing that is hence in the method

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

where a statement of the form

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];

disables selection for the specific cell while at the same time allows the user to manipulate the switch and hence use the appropriate selector. This is not true if somebody disables user interaction through the

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

method which merely prepares the cell and does not allow interaction with the UISwitch.

Moreover, using the method

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

in order to deselect the cell with a statement of the form

[tableView deselectRowAtIndexPath:indexPath animated:NO];

still shows the row being selected while the user presses on the original contentView of the cell.

Just my two cents. I am pretty sure many will find this useful.

Solution 5:

For Swift 4.0 for example:

cell.isUserInteractionEnabled = false
cell.contentView.alpha = 0.5