How to make UITableViewCell highlighted state persist - iphone

I have a UITableviewCell. When a user clicks the cell, Im saving the indexpath and then calling the cellforrowAtIndexpath method to get the cell and then call the SetHighlighted:TRUE on that cell.
This works fine but the problem is when I scroll up and down the tableview, the selected cell when reappears, is not highlighted. How do I make the highlighted blue color persist so the user can visually see their selection even after scrolling the table up or down?
Thanks

save the indexpath of the selected cell
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.selectedIndexPath = indexPath;
}
and compare in tableVIew:cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// configure cell
if ([indexPath isEqual:self.selectedIndexPath]) {
[cell setHighlighted:YES];
}
else {
[cell setHighlighted:NO];
}
return cell;
}
However, keep in mind that apple discourages the use of the cell highlight state to indicate selected cell. You should probably use cell.accessoryType = UITableViewCellAccessoryCheckmark;

Related

Xcode Setting Accessory Mark on Static Cells error

I am having a problem with the Settings page of my app. I have chosen to use static cells so I have a few table sections with 3-4 cells in each.
In viewDidLoad I load my NSUserDefaults and set the accessory marks like this:
...
}
else if ( ... my Condition3 ... ) {
indexPath = [NSIndexPath indexPathForRow:2 inSection:0];
}
UITableViewCell* cell = [settingsTable cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
This works fine and it sets the cell with the matching setting with a Checkmark. However, this is only working for the cells that are on screen by default. Any cells which require scrolling do not contain the checkmark.
Is there a way to fix this, preferably without having to use dynamic cells?
Ahh, I finally figured it out. cellForRowAtIndexPath crashes the app so I had to do the following:
I set the cells which require a checkmark in my viewDidAppear method using the code above (in the question). I also remove all checkmarks and then add one to the selected cell in the didSelectRowAtIndexPath method as I was doing before.
In each of the two methods I set an NSString variable to the .textview.text of the selected cell and then implement this method:
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.accessoryType = UITableViewCellAccessoryNone;
if ([cell.textLabel.text isEqualToString:[NSString stringWithFormat:#"%#", myFirstString]] || [cell.textLabel.text isEqualToString:[NSString stringWithFormat:#"%#", mySecondString]]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
Hopefully this might help someone.
That's because when you scroll your cells are rebuilt and the checkmarks are cleaned.
You need to set it up in the
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

multiple selection in grouped tableview

I am working with grouped tableview with multiple sections.
and I have to implement the functionality of multiple selection on didselectrow at indexpath
method. my code is as follows.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)path
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:path];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
else
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
}
which allows me to select multiple cells
but when I scroll my tableview at that time my selection disappears.
Your selection goes off when you scroll because it calls cellForRowAtIndexPath and there you have not handle selection.
To avoid this problem you can do as follows:
In didSelectRowAtIndexPath you can save index path of selected row as follows:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)path
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:path];
if (cell.accessoryType == UITableViewCellAccessoryCheckmark)
{
cell.accessoryType = UITableViewCellAccessoryNone;
//remove index path
[selectedIndexPathArray removeObject:path];
}
else
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[selectedIndexPathArray addObject:path];
}
}
and in cellForRowAtIndexPath you can check whether cell is selected or not.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//If selectedIndexPathArray contains current index path then display checkmark.
if([selectedIndexPathArray containsObject:indexPath])
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
Try this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
if (self.tableView.isEditing) {
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
} else {
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
return cell;
}
-(UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleMultiSelect;
}
-(IBAction) switchEditing {
[self.tableView setEditing:![self.tableView isEditing]];
[self.tableView reloadData]; // force reload to reset selection style
}
Hope this helps solving your problem.(ref)
Your selection disapear cause the method CellForRowAtIndexPath will be called at scroll.
You need to set the accessory again.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
// here
...
}
You are getting this issue because you are not tracking your row selections.When the callback method cellForRowAtIndexPath gets called for the rows that had disappeared/(scrolled up/down) the cell object no longer remembers whether it was selected or not. (reason those selections are disappearing)
I would suggest you to use a collection like NSMutableArray/NSArray to track the selected rows.
You can use either of these approaches.
This would be a quick working fix:
Add/Remove the index path object in didSelectRowAtIndexPath based on the users selection
and then based on the contents of that array u can toggle the value of cell.accessoryType for the corresponding cell.
Ideally,you can use a data bean/model with some boolean member called selected and u can update its value based on the selection made.Then instead of simply adding those index path u can add those meaningful data bean objects onto your array and get the selections back from the selected property of the bean.This approach would help u in getting back the row selections even if the user kills and restarts the app provided u persist the bean objects in database/archive..(But it all depends on ur use case and requirements!)
Hope this helped!

UITableViewCell with 2 accessory types

I would like to make a UITableViewCell with one label and two accessory types:
Unselected cells should display a UITableViewCellAccessoryDetailDisclosureButton accessory.
The selected cell should display both the UITableViewCellAccessoryDisclosureIndicator and the UITableViewCellAccessoryDetailDisclosureButton accessories.
The only way I know how to do this is by using an image for the selected cell's accessory view. Is there an alternative way to do this?
Make a custom UITableViewCell (numerous tutorials and examples online and also in the documentation).
In your
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
selectedIndex = indexPath //selectedIndex is a property
}
Then in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//usual cell stuff
if(indexPath == selectedIndex)
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
else
[cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];
}
So the trick is just to keep a reference to the selected cell and set the indicator accordingly.
Note that you might want to test if the cell is already selected before setting the selectedIndex, in that case you should set selectedIndex = nil.

Checkbox cell in a table view: User can't check it

I need help in using checkbox cell. I currently added the object to tableview. It looks ok until i tried building and running the program where I cannot check the checkbox. I am currently using a tableview which displays items runtime with a checkbox for each item so i can have multiple selections.
I am new to xcode and I have been stuck for a week with this problem. i tried google but still no luck.
Any snippets, answers, or explanations is very much appreciated.
First we need to edit this method: - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath. Assuming you generated a Navigation-based application, this method should already be there, only commented out. I don't know the exact details of your implementation, but you somehow have to keep track of the checkbox state for each cell in the tableView. For example, if you had a BOOL array, the following code would work:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (checkboxArray[indexPath.row])
checkboxArray[indexPath.row] = NO;
else
checkboxArray[indexPath.row] = YES;
[self.tableView reloadData];
}
Now that we know what cells need to have a checkmark next to them, the next step is to modify how the cell is displayed. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath handles the drawing of each cell. Building off the previous example, this is how you would display the checkbox:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
if (checkboxArray[indexPath.row]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
cell.accessoryType = UITableViewCellAccessoryNone;
// Configure the cell.
return cell;
}
If we don't call reloadData, the checkmark will not show up until it goes off-screen and reappears. You need to explicitly set the accessoryType each time because of the way cells are reused. If you set the style only when a cell is checked, other cells that may not necessarily be checked will have a checkmark when you go to scroll. Hopefully this gives you a general idea on how to use checkmarks.

Is it possible to configure a UITableView to allow multiple-selection?

For the iPhone, is it possible to configure a UITableView such that it will allow multiple-selection?
I've tried overriding -setSelected:animated: for each UITableViewCell, but trying to fudge the required behavior is tricky as it's difficult to separate the real unselections from the ones where the UITableView thinks I've unselected due to selection of another cell!
Hope someone can help!
Thanks,
Nick.
Following property should work fine if you are developing app for iOS5.0+
self.tableView.allowsMultipleSelection = YES;
The best way to do this would be to a checkmark per selected row.
You can do that by setting the accessoryType on the selected UITableViewCell instances to UITableViewCelAccessoryCheckmark.
To deselect the row, set it back to UITableViewCellAccessoryNone.
To enumerate which cells/rows were selected (say, upon clicking a button), simply iterate over the cells of the table looking for UITableViewCellAccessoryCheckmark. Or, manage some NSSet or the like in your table view delegate in the "did select" delegate methods.
Use the following code to set up the cell accesory types:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath];
if (thisCell.accessoryType == UITableViewCellAccessoryNone) {
thisCell.accessoryType = UITableViewCellAccessoryCheckmark;
}else{
thisCell.accessoryType = UITableViewCellAccessoryNone;
}
}
- (UITableViewCellAccessoryType)tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath {
//add your own code to set the cell accesory type.
return UITableViewCellAccessoryNone;
}
Jeff Lamarche has a tutorial on how to do this here:
http://iphonedevelopment.blogspot.com/2008/10/table-view-multi-row-edit-mode.html
I've not tried the code but it's been on the back of my mind for a while, knowing the day will come when I need it.
I backported allowsMultipleSelectionDuringEditing and allowsMultipleSelection from iOS5 to older iOS. You can fork it at https://github.com/ud7/UDTableView-allowsMultipleSelection
It's drop in replacement and only thing you need to do is change UITableView to UDTableView (in code or interface builder)
From the HIG:
Table views provide feedback when users select list items. Specifically, when an item can be selected, the
row containing the item highlights briefly when a user selects it to show that the selection has been received.
Then, an immediate action occurs: Either a new view is revealed or the row displays a checkmark to indicate
that the item has been selected. The row never remains highlighted, because table views do not display a
persistent selected state.
You'll need to roll your own multiple selection style, either with something like Mail, or using the checkmark accessory on your cells.
Guys for multiple selection you just need
self.tableView.allowsMultipleSelection = YES;
on viewDidLoad and
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *tableViewCell = [tableView cellForRowAtIndexPath:indexPath];
tableViewCell.accessoryView.hidden = NO;
// if you don't use custom image tableViewCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *tableViewCell = [tableView cellForRowAtIndexPath:indexPath];
tableViewCell.accessoryView.hidden = YES;
// if you don't use custom image tableViewCell.accessoryType = UITableViewCellAccessoryNone;
}
I was searching for the same issue and the answer of Bhavin Chitroda sovled it for me but with some addition to keep the check mark as it was while scrolling.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if ( [array indexOfObject:indexPath] == NSNotFound ) {
[array addObject:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
[array removeObject:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
The addition:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
// Your code here
.
.
.
if ( [array indexOfObject:indexPath] == NSNotFound ) {
cell.accessoryType = UITableViewCellAccessoryNone;
} else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
return cell;
}
If you're trying to do something like Mail's multiple-select (to delete mail, for example), then you're probably going to have to manage all the selection yourself. Multiple row selection isn't something that's standard on the iPhone. Mail solves this by using checkmarks to indicate which rows have been selected.
blue highlighted row as an indicator of whether a row is selected is actually discouraged according to the HIG page 121. Checkmarks will do the trick.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
int selectedRow = indexPath.row;
cout << "selected Row: " << selectedRow << endl;
UITableViewCell *indexPathForCell = [tableView cellForRowAtIndexPath:indexPath];
if (indexPathForCell.accessoryType == UITableViewCellAccessoryNone) {
indexPathForCell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
indexPathForCell.accessoryType = UITableViewCellAccessoryNone;
}
}
then add your arraying or how ever you wish to store the data of which were selected.
Note: This does not work in iOS 4+. This is a private, undocumented constant. Do not use it.
If you are not planning to submit your app to the App Store, you can invoke multi-row edit mode by implementing the following method in your UITableViewController delegate:
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return 3; // Undocumented constant
}
Tested with iOS4.3 - 6.0
-(void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
if ([controller.searchResultsTableView respondsToSelector:#selector(allowsMultipleSelectionDuringEditing)]) {
controller.searchResultsTableView.allowsMultipleSelectionDuringEditing = YES;
}
else {
controller.searchResultsTableView.allowsSelectionDuringEditing = YES;
}
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellAccessoryCheckmark;
}