When you tap a row in a UITableView, the row is highlighted and selected. Is it possible to disable this so tapping a row does nothing?
All you have to do is set the selection style on the UITableViewCell instance using either:
Objective-C:
cell.selectionStyle = UITableViewCellSelectionStyleNone;
or
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
Swift 2:
cell.selectionStyle = UITableViewCellSelectionStyle.None
Swift 3 and 4.x:
cell.selectionStyle = .none
Further, make sure you either don't implement -tableView:didSelectRowAtIndexPath: in your table view delegate or explicitly exclude the cells you want to have no action if you do implement it.
More info here and here
For me, the following worked fine:
tableView.allowsSelection = false
This means didSelectRowAt# simply won't work. That is to say, touching a row of the table, as such, will do absolutely nothing. (And hence, obviously, there will never be a selected-animation.)
(Note that if, on the cells, you have UIButton or any other controls, of course those controls will still work. Any controls you happen to have on the table cell, are totally unrelated to UITableView's ability to allow you to "select a row" using didSelectRowAt#.)
Another point to note is that: This doesn't work when the UITableView is in editing mode. To restrict cell selection in editing mode use the code as below:
tableView.allowsSelectionDuringEditing = false
Because I've read this post recently and it has helped me, I wanted to post another answer to consolidate all of the answers (for posterity).
So, there are actually 5 different answers depending on your desired logic and/or result:
1.To disable the blue highlighting without changing any other interaction of the cell:
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
I use this when I have a UIButton - or some other control(s) - hosted in a UITableViewCell and I want the user to be able to interact with the controls but not the cell itself.
NOTE: As Tony Million noted above, this does NOT prevent tableView:didSelectRowAtIndexPath:. I get around this by simple "if" statements, most often testing for the section and avoiding action for a particular section.
Another way I thought of to test for the tapping of a cell like this is:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// A case was selected, so push into the CaseDetailViewController
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.selectionStyle != UITableViewCellSelectionStyleNone) {
// Handle tap code here
}
}
2.To do this for an entire table, you can apply the above solution to each cell in the table, but you can also do this:
[tableView setAllowsSelection:NO];
In my testing, this still allows controls inside the UITableViewCell to be interactive.
3.To make a cell "read-only", you can simply do this:
[cell setUserInteractionEnabled:NO];
4.To make an entire table "read-only"
[tableView setUserInteractionEnabled:NO];
5.To determine on-the-fly whether to highlight a cell (which according to this answer implicitly includes selection), you can implement the following UITableViewDelegate protocol method:
- (BOOL)tableView:(UITableView *)tableView
shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath
To sum up what I believe are the correct answers based on my own experience in implementing this:
If you want to disable selection for just some of the cells, use:
cell.userInteractionEnabled = NO;
As well as preventing selection, this also stops tableView:didSelectRowAtIndexPath: being called for the cells that have it set. (Credit goes to Tony Million for this answer, thanks!)
If you have buttons in your cells that need to be clicked, you need to instead:
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
and you also need to ignore any clicks on the cell in - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath.
If you want to disable selection for the whole table, use:
tableView.allowsSelection = NO;
(Credit to Paulo De Barros, thanks!)
As of iOS 6.0, UITableViewDelegate has tableView:shouldHighlightRowAtIndexPath:. (Read about it in the iOS Documentation.)
This method lets you mark specific rows as unhighlightable (and implicitly, unselectable) without having to change a cell's selection style, messing with the cell's event handling with userInteractionEnabled = NO, or any other techniques documented here.
You can also disable selection of row from interface builder itself by choosing NoSelection from the selection option(of UITableView Properties) in inspector pane as shown in the below image
FIXED SOLUTION FOR SWIFT 3
cell.selectionStyle = .none
In your UITableViewCell's XIB in Attribute Inspector set value of Selection to None.
EDIT: for newer Swift it is changed to:
cell.selectionStyle = .none
See this for more info:
https://developer.apple.com/documentation/uikit/uitableviewcell/selectionstyle
In case anyone needs answer for Swift:
cell.selectionStyle = .None
If you want selection to only flash, not remain in the selected state, you can call, in
didSelectRowAtIndexPath
the following
[tableView deselectRowAtIndexPath:indexPath animated:YES];
so it will flash the selected state and revert.
From the UITableViewDelegate Protocol you can use the method willSelectRowAtIndexPath
and return nil if you don't want the row selected.
In the same way the you can use the willDeselectRowAtIndexPath method and return nil if you don't want the row to deselect.
This is what I use ,in cellForRowAtIndexPath write this code.:
cell.selectionStyle = UITableViewCellSelectionStyleNone;
1- All you have to do is set the selection style on the UITableViewCell instance using either:
Objective-C:
cell.selectionStyle = UITableViewCellSelectionStyleNone;
or
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
Swift 2:
cell.selectionStyle = UITableViewCellSelectionStyle.None
Swift 3:
cell.selectionStyle = .none
2 - Don't implement -tableView:didSelectRowAtIndexPath: in your table view delegate or explicitly exclude the cells you want to have no action if you do implement it.
3 - Further,You can also do it from the storyboard. Click the table view cell and in the attributes inspector under Table View Cell, change the drop down next to Selection to None.
4 - You can disable table cell highlight using below code in (iOS) Xcode 9 , Swift 4.0
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "OpenTbCell") as! OpenTbCell
cell.selectionStyle = .none
return cell
}
Objective-C:
Below snippet disable highlighting but it also disable the call to didSelectRowAtIndexPath. So if you are not implementing didSelectRowAtIndexPath then use below method. This should be added when you are creating the table. This will work on buttons and UITextField inside the cell though.
self.tableView.allowsSelection = NO;
Below snippet disable highlighting and it doesn't disable the call to didSelectRowAtIndexPath. Set the selection style of cell to None in cellForRowAtIndexPath
cell.selectionStyle = UITableViewCellSelectionStyleNone;
Below snippet disable everything on the cell. This will disable the interaction to buttons, textfields:
self.tableView.userInteractionEnabled = false;
Swift:
Below are the Swift equivalent of above Objective-C solutions:
Replacement of First Solution
self.tableView.allowsSelection = false
Replacement of Second Solution
cell?.selectionStyle = UITableViewCellSelectionStyle.None
Replacement of Third Solution
self.tableView.userInteractionEnabled = false
Try to type:
cell.selected = NO;
It will deselect your row when needed.
In Swift3 ...
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let r = indexPath.row
print("clicked .. \(r)")
tableView.cellForRow(at: indexPath)?.setSelected(false, animated: true)
}
Swift 3,4 and 5
Better practice, write code in UITableViewCell
For example, you have UITableViewCell with the name MyCell,
In awakeFromNib just write self.selectionStyle = .none
Full example:
class MyCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
self.selectionStyle = .none
}
}
I've been battling with this quite profusely too, having a control in my UITableViewCell prohibited the use of userInteractionEnabled property. I have a 3 cell static table for settings, 2 with dates, 1 with an on/off switch. After playing about in Storyboard/IB i've managed to make the bottom one non-selectable, but when you tap it the selection from one of the top rows disappears. Here is a WIP image of my settings UITableView:
If you tap the 3rd row nothing at all happens, the selection will stay on the second row. The functionality is practically a copy of Apple's Calendar app's add event time selection screen.
The code is surprisingly compatible, all the way down to IOS2 =/:
- (NSIndexPath *)tableView: (UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 2) {
return nil;
}
return indexPath;
}
This works in conjunction with setting the selection style to none, so the cell doesn't flicker on touch down events
We can write code like
cell.selectionStyle = UITableViewCellSelectionStyleNone;
but when we have custom cell xib above line give warning at that time for
custom cell xib
we need to set selection style None from the interface builder
You just have to put this code into cellForRowAtIndexPath
To disable the cell's selection property:(While tapping the cell).
cell.selectionStyle = UITableViewCellSelectionStyle.None
From UITableViewDataSource Protocol, inside method cellForRowAt add:
let cell = tableView.dequeueReusableCell(withIdentifier: "YOUR_CELL_IDENTIFIER", for: indexPath)
cell.selectionStyle = .none
return cell
OR
You can goto Storyboard > Select Cell > Identity Inspector > Selection and select none from dropdown.
I am using this, which works for me.
cell?.selectionStyle = UITableViewCellSelectionStyle.None
try this
cell.selectionStyle = UITableViewCellSelectionStyleNone;
and
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
and you can also set selection style using interfacebuilder.
Directly disable highlighting of TableViewCell into storyboard
While this is the best and easiest solution to prevent a row from showing the highlight during selection
cell.selectionStyle = UITableViewCellSelectionStyleNone;
I'd like to also suggest that it's occasionally useful to briefly show that the row has been selected and then turning it off. This alerts the users with a confirmation of what they intended to select:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
...
}
To disable the highlighting of the UItableviewcell
cell.selectionStyle = UITableViewCellSelectionStyleNone;
And should not allow the user to interact with the cell.
cell.userInteractionEnabled = NO;
You Can also set the background color to Clear to achieve the same effect as UITableViewCellSelectionStyleNone, in case you don't want to/ can't use UITableViewCellSelectionStyleNone.
You would use code like the following:
UIView *backgroundColorView = [[UIView alloc] init];
backgroundColorView.backgroundColor = [UIColor clearColor];
backgroundColorView.layer.masksToBounds = YES;
[cell setSelectedBackgroundView: backgroundColorView];
This may degrade your performance as your adding an extra colored view to each cell.
You can also do it from the storyboard. Click the table view cell and in the attributes inspector under Table View Cell, change the drop down next to Selection to None.
You can use :
cell.selectionStyle = UITableViewCellSelectionStyleNone;
in the cell for row at index path method of your UITableView.
Also you can use :
[tableView deselectRowAtIndexPath:indexPath animated:NO];
in the tableview didselectrowatindexpath method.
You can use this
cell.selectionStyle = UITableViewCellSelectionStyleNone;
You can use ....
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
Related
I am looking for is a clean way of changing the model after tapping a button in a custom cell. It's tapping the button that matters here and not selecting the row, so didSelectRowAtIndexPath isn't what I am interested in.
For example
let array = [true, false, true]
When the user taps the button in the second cell, the model should become
array[1] = true
In cellForRowAtIndexPath a target action is added to the button :
cell.button.addTarget(self, action: "myAction:", forControlEvents: UIControlEvents.TouchUpInside)
the action looks like :
func myAction(sender:UIButton!)
{
//how to change the model and reloadRowsAtIndexPaths since the sender is just a UIButton!?
}
If you only have one section in the tableViewController, you could always set button.tag = [indexPath row] inside cellForRowAtIndexPath. Then your action would always know which row was touched from the sender.tag value. Quick and dirty, but it would work.
Or, if you will reuse this custom cell in tableviews with multiple sections, you could subclass the UIButton and add a property for the indexPath. Then you would always have access to both section and row values. Personally, I would take this approach because it gives you the most flexibility in the long run.
inside of cellForRowAtIndexPath()
cell.button.tag = indexPath.row
Then inside of your function myAction()
func myAction(sender:UIButton)
{
var index = sender.view.tag
array[index] = true // just like you want
}
I am a little unclear about your question - are you asking how you can change a uitableviewcell's content once a button is pressed in the cell then one way to go about it would be to tag the button with the cell's indexPath when the cell is created in the cellForRowAtIndexPath method. Then you can read the tag from the selector once the button is pushed.
I just tested this and it works. When you create the cell add the line:
cell.tag=indexPath.row;
and then in the selector method for the button you can use:
NSInteger p=sender.tag;
int x=(int)p;
NSIndexPath *path = [NSIndexPath indexPathForRow:x inSection:0];
UITableViewCell *cell = [_tableView cellForRowAtIndexPath:path];
cell.backgroundColor=[UIColor blackColor];
In my example I changed the background color of the cell that the pressed button was in.
I'm working with UICollectionView using PSTCollectionView
Library. I've to create a grid where user can select and deselect
images by tapping on UICollectionViewCell. I've to show checkBox like
image if cell is selected. And uncheckedBox image if cell is
deselected. I am able to select cell and display checkBox image.And
also can deselect. But when I select next cell, the previous deselected
cell also get selected and shows checkBox image. This is the method I declared in UICollectionViewCell subClass
-(void)applySelection{
if(_isSelected){
_isSelected=FALSE;
self.contentView.backgroundColor=[UIColor whiteColor];
self.selectImage.image=[UIImage imageNamed:#"unchecked_edit_image.png"];
}else{
_isSelected=TRUE;
self.contentView.backgroundColor=[UIColor whiteColor];
self.selectImage.image=[UIImage imageNamed:#"checked_edit_image.png"];
}
}
And here is my code for didSelectItemAtIndexPath and
didDeselectItemAtIndexPath
- (void)collectionView:(PSTCollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"didSelect method called");
FriendImageCell *cell = (FriendImageCell*)[imageGrid cellForItemAtIndexPath:indexPath];
[selectedImages addObject:[[list objectAtIndex:indexPath.item] objectForKey:#"thumbnail_path_150_150"]];
[cell applySelection];
}
- (void)collectionView:(PSTCollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"did deselect called");
FriendImageCell *cell = (FriendImageCell*)[imageGrid cellForItemAtIndexPath:indexPath];
[selectedImages removeObjectAtIndex:indexPath.item];
[cell setSelected:NO];
[cell applySelection];
}
Can anyone please make me understand whats wrong with my code ? Make
me correct if I'm doing anything wrong. Tried many answers on
stack-overflow but nothing worked. Any help would be appreciated.
Thanks in advance.
After days of back and forth discussion. I think I finally understand what your problem really is. You must have forgotten to set the allowsMultipleSelection to YES. So whenever a new cell is selected, your previous cells got deselected.
allowsMultipleSelection
This property controls whether multiple items can be selected simultaneously. The default value of this property is NO.
And in my previous answer, I also suggested you to make your own boolean array to keep track of the selected items. However, I just realized that you don't have to. indexPathsForSelectedItems gives you an array of selected index paths.
indexPathsForSelectedItems
An array of NSIndexPath objects, each of which corresponds to a single selected item. If there are no selected items, this method returns an empty array.
As a matter of fact, you don't even have to implement the didSelectItemAtIndexPath, and didDeselectItemAtIndexPath. By default, these two delegate methods will call setSelected: for you. Therefore, a more appropriate way to do is move your applySelection code in to setSelected.
Overwrite the setSelected: method in your custom UICollectionViewCell.
- (void)setSelected:(BOOL)selected
{
[super setSelected:selected];
// Change your UI
if(_isSelected){
self.contentView.backgroundColor=[UIColor whiteColor];
self.selectImage.image=[UIImage imageNamed:#"unchecked_edit_image.png"];
}else{
self.contentView.backgroundColor=[UIColor whiteColor];
self.selectImage.image=[UIImage imageNamed:#"checked_edit_image.png"];
}
}
I have a table view with multiple cells. When I click on one of the cell it navigates to the next view controller, but my problem is that I cannot select multiple cells.
Could any one please help me on this issue, I want to select two or more cells with two finger tap.
set by code if you set by programming
table.allowsMultipleSelection = YES;
and if you set in xib tick on allowsMultipleSelection
Just add button like checkbox and multiple choose like checkbox.
If you are implementing the tableview programatically then the better way is to create a custom cell which will have button (and obviously other UI components that you need to show in the table view cell) which will work as a checkbox and assign button.tag as indexPath.row which will help you to select multiple rows.
Take a look here --
Below code will go into cellForRowAtIndexPath
YourCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.button.tag = indexPath.row;
[cell.button addTarget:self action:#selector(multipleCheckAction:) forControlEvents:UIControlEventTouchUpInside];
return cell;
-(void)multipleCheckAction:(UIButton *)sender { //sender.tag will be equal to indexPath.row }
Happy Coding
Since cells are being reused, you need to set the accessory mark to on or off for every cell in the table in the cellForRowAtIndexPath table datasource method.
So the cell.accessoryType cell property should be specified in the cellForRowAtIndexPath and not the didSelectRowAtIndexPath delegate method.
In the didSelectRow, just keep track of the selected rows in an array, and set the cells accessory mark to none or checkmark in the cellForRowAtIndexPath depending on the array value.
I've a tableView with some cells. Each cell also contains a button. When the user clicks the button, the cell should be unclickable, but not the button. So when the user clicks on the button of a cell which is not clickable, this cell should be clickable again.
I tried:
cell.userInteractionEnabled = NO;
...but then the button wasn't clickable anymore.
Thanks to your effort in advance.
EDIT
I mean: When I click on a cell a new view opens. But I want, that no action happens, when the cell is not "clickable".
Unclickable in which way? If you just want the cell to not be selectable, you are probably seeking for this:
cell.selectionStyle = UITableViewCellSelectionStyleNone;
If you want to prevent your code to be executed when the selection is disabled, just check for the selection property inside your didSelectRowAtIndexPath:method. Something like this:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.selectionStyle != UITableViewCellSelectionStyleNone) {
//(your code opening a new view)
}
}
Remember, you still have to play with this property, setting to UITableViewCellSelectionStyleNone when you don't want the cell to be selectable, and setting back to UITableViewCellSelectionStyleBlue (or UITableViewCellSelectionStyleGray) when you want it to be selectable again.
Swift version:
cell.selectionStyle = .none
Remove selection by setting UITableViewCellSelectionStyleNone as the selectionStyle.
cell.selectionStyle = UITableViewCellSelectionStyleNone;
And do nothing in -tableView:didSelectRowAtIndexPath:
You can be selective in that delegate method for example if only the first row in the first section has the button and should do nothing :
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSIndexPath *indexPathForDisabledCell = [NSIndexPath indexPathForRow:0
inSection:0];
if([indexPath compare:indexPathForDisabledCell] != NSOrderedSame) {
//Do whatever you do with other cells
}
}
This can also be done through Interface Builder using User Defined Runtime Attributes on the TableViewCell:
Key Path | Type | Value
selectionStyle | Number | 0
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableViewCell_Class/#//apple_ref/c/tdef/UITableViewCellStyle
When ever you tap on a row in a UITableView, the row is highlighted and selected. Is it possible to disable this so tapping a row does nothing?
cell.selectionStyle = UITableViewCellSelectionStyleNone;
or [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
Further, make sure you either don't implement -tableView:didSelectRowAtIndexPath: in your table view delegate or explicitly exclude the cells you want to have no action if you do implement it.
Implement tableView:willSelectRowAtIndexPath: delegate method of UITableView and return nil.Returning nil from this method tells the table view to not select the row consequently tableView:didSelectRowAtIndexPath: method will not get called.But doing this does not prevent highlighting the row.To disable highlighting effect on row set cell selection style toUITableViewCellSelectionStyleNone as explained in the above answers.
Just set :
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
If you want stop highlighting use the code say: your desired value to be 19
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexpath.row == '19')
cell.selectionStyle = UITableViewCellSelectionStyleNone;
else
cell.selectionStyle = UITableViewCellSelectionStyleGray;
}
But, if you want to control the selection of cell
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexpath.row == '19')
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
for Swift 3 :
cell.selectionStyle = UITableViewCellSelectionStyle.none
The accepted answer was not working for me. This problem driving me crazy for awhile because it would look like a "glitch" on any selection when the next view loaded..
My SOLUTION: I had to go to the .xib file of the actual TableViewCell (my custom cell that I built) select the cell and select the CellView. (Make sure you select the Cell, and NOT a subview within it. It will turn Blue like the picture shows). On the left side click "Selection" -> "None". This SHOULD be the exact same as doing it with code, but for some reason it just wasn't working...
This is for the case in which you have a custom cell, but I found this question when I was looking for the answer, so I thought I'd leave this here in case this helps others.
Go to your custom cell, and set selectionStyle to .none in the awakeFromNib method:
override func awakeFromNib() {
super.awakeFromNib()
// disable selection
selectionStyle = .none;
}
If you use this custom cell in multiple UITableViews, you only have to set it once in the custom cell instead of on every UITableView you use :)
for Swift 4
cell.selectionStyle = UITableViewCell.SelectionStyle.none
you could simply do this for OBJ C:
cell.selectionStyle = UITableViewCellSelectionStyleNone;