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;
}
Related
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
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!
I have got an iphone project that has a UITableView which is populated from Core Data..
When a cell is selected, the user is directed to a new view controller (see code line below) which shows additional information about that cell entry (from core data)
[self presentModalViewController:noteViewController animated:YES]
What i want to do is to be able to set some sort of checkmark on either side of each cell to represent whether the task is complete of incomplete..
I have read that i could do this using:
UITableViewCellAccessoryCheckmark
but i am not sure how to implement is as currently
didSelectRowAtIndexPath:
is being used to present the modal view controller..
So essentially i want to know if there is a method for changing the state of a cell's accessory from checkmark to nothing (and vice versa) independently.. in the sense that if the actual checkmark is touch.. it shows it.. and if it is touched again, it hides it..
Any help would be greatly appreciated!
You will need to track selected rows externally from Cell presentation. This means, your model (that you used to build the cells in the first place) will need to track some sort of boolean. Once you have that you set accessoryType to the proper type.
i.e.
if ([[data objectAtIndex:indexPath.row] isSelected]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
This would be some of the logic in your:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if (selectedCell.accessoryType == UITableViewCellAccessoryNone)
{
selectedCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
if (selectedCell.accessoryType == UITableViewCellAccessoryCheckmark)
{
selectedCell.accessoryType = UITableViewCellAccessoryNone;
}
//Do something
}
Hope this helps
UPDATE
This tutorial will give you a basic info on custom table view cell.
Another Reference.
I think this will give you the solution.
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;
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.