What is difference between
[tableView deselectRowAtIndexPath:indexPath animated:NO];
and
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexpath];
[cell setSelected:NO];
???
In a UITableView a cell does not match a specific piece of your data. It can (and should most of the time) be reused and it is nil when not visible.
deselectRowAtIndexPath will set the indexPath as 'not selected' in your tableview, so when you scroll back and forth to that cell, it will stay unselected, because you told your tableview that whatever the cell you display at that indexPath it should be unselected.
With UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexpath];
[cell setSelected:NO]; you set the cell as unselected. However that cell can be used for other pieces of data, and it can even be nil if this indexPath is not displayed.
First one is programmatically deselecting the cell. So it will un-highlight the cell if the user has selected it already.
As for the second bit of code, I believe that is just a pointer or reference to one of the cells in your table view. You can use this code to edit a cell OUTSIDE of any of the table view delegate methods. So if you wanted to edit/update a label on one of your cells but from a random method (not a table view delegate method), then you could use that code to reference the label text property.
I think you should also check out the Apple Developer Library website. It explains all the different table view method/properties/etc in lots of detail:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/
The concepts of "selected" is different for a tableview and for a cell. The tableview can have one or more rows selected that changes the state of the tableview, however changing the tableview cell selected state only affects its appearance and nothing else.
I'm getting some weird behavior in my UITableViewController.
I've subclassed UITableViewCell and created by own "visited" property within it.
- (void)setVisited:(BOOL)visited animated:(BOOL)animated
{
[self setVisited:visited];
...
}
I set this property when I create the cell in tableView:cellForRowAtIndexPath: (the only place I create it) like below:
if (cell == nil) {
cell = [[ArticleListViewCell alloc] initWithReuseIdentifier:CellIdentifier art:art index:indexPath.row];
[cell setVisited:NO animated:NO];
}
Later, in tableView:didSelectRowAtIndexPath:, I set this property to YES:
ArticleListViewCell *cell = (ArticleListViewCell *) [tableView cellForRowAtIndexPath:indexPath];
[cell setVisited:YES animated:NO];
However, when I select a cell and then return to this UITableView, which currently has 10 cells, I find that not only has the cell I selected become "visited", but also another cell has as well. It's hard to explain, but if I select the 1st cell, the 7th also becomes visited, if I select the 2nd, the 8th also becomes visited, and so on. Does anyone know why this is, and how I should go about fixing it?
I've checked this question, but it doesn't seem to help much.
This is caused by cell reuse. You need to set visited every time, not just when you create the cell.
if (cell == nil) {
cell = [[ArticleListViewCell alloc] initWithReuseIdentifier:CellIdentifier art:art index:indexPath.row];
}
BOOL visited = ... // value for this indexPath
[cell setVisited:visited animated:NO];
And in your didSelectRow method you need to update some sort of data structure keeping track of which row has been visited. You use this data to set the value properly in the cellForRow method.
Do not use the cell to keep track of state. The cell is a view. Your data source needs to track the state.
I have a situation where I need to display more than one sections in a grouped table. Each section has three content rows and I need a "View More" row. The content row will open a detail view, where as "view more" will open a tableview with status messages. Need some help with
The prototype cell is set to have the image and the labels. So I am not sure how to add the "View More" Row in the end.
Am I right in using dynamic prototypes ( I have it working pretty much) or is static cells the right choice?
The prototype cell is set to have the image and the labels. So I am not sure how to add the "View More" Row in the end.
You are not limited to a single prototype cell per table. Add a custom cell for the "View More" cell, then add some code to your tableView:cellForRowAtIndexPath: method to pick the "main" prototype for the top cells, and the "view more" prototype for the last cell.
-(UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
UITableViewCell *cell;
if (indexPath.row != [self numberOfRowsInSection:indexPath.section]-1) {
cell = [tableView dequeueReusableCellWithIdentifier:#"mainPrototype"];
...
} else {
cell = [tableView dequeueReusableCellWithIdentifier:#"viewMorePrototype"];
...
}
return cell;
}
Am I right in using dynamic prototypes ( I have it working pretty much) or is static cells the right choice?
Yes, this is the right choice.
Create an array to contain all the status messages. Group them according to the section when you initialise the screen. You could give the same index to the groups as the section as well. In the didSelectRowAtIndexPath method, when a particular section is clicked, pass the particular section of the status messages to the next view controller.
Hope you get my idea and this helps you..
Adding the custom cell to the end of each section can be done as #dasklinkenlight said...
It's My first time to post a question, thank you for you all in advanced.
Now, i want to implement a default style grouped UITableView contains multiple group of data. for each row, there will be a detail Disclosure button as accessoryType icon. when people click on the disclosure button, i want the Cell expand with detail info for the selected row.
i was trying to fulfill this task by add a customized cell to selected row, however, it was very complex. So currently, i am trying to finish this task by reload a specific row with Customized cell xib. i knew there is a delegate method for reloadRowsAtIndexPaths. but can i use this to reload a specific cell? Thanks
please suggest!
Great Thanks
Have you tried something like this:
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == mySpecialSelectedCell)
{
//Load all your custom stuff here
}
else
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: CellIdentifier];
}
if (cell == nil)
{
}
return cell;
}
You would have to get the cell's indexPath when you click the expand button.
Or you could look at this answer. And then, like the code above, just load that one cell that you have specified with that NIB and load the rest the way you would normally.
You can implement the tableview delegate methods to set the height for the cell which needs to expand. Add some condition check in heightForRow method and when user taps on button, change the condition to increase the height. When table is reloading it will call this method and will reload cell with bigger height.
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];