I've got a UITableView
with each row containing a checkbox using UITableViewCellAccessoryCheckmark
. I can't figure out how to uncheck all the checkboxes using the didSelectRowAtIndexPath
method.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *oldCell;
int count开发者_C百科 = [self.myTableRowNamesArray count];
for (NSUInteger i = 0; i < count; ++i) {
// Uncheck all checkboxes
// OF COURSE THIS DOESN'T WORK
// BECAUSE i IS AN INTEGER AND INDEXPATH IS A POINTER
FOO: oldCell = [myTableView cellForRowAtIndexPath:(int)i];
// GOOD CODE:
oldCell = [penanceOptionsTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
oldCell.accessoryType = UITableViewCellAccessoryNone;
}
UITableViewCell *newCell = [myTableView cellForRowAtIndexPath:indexPath];
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
Instead of modifying the .accessoryType
of all cells in didSelectRowAtIndexPath:
, I suggest storing the selected index in some ivar, and change the .accessoryType
in the data source's -tableView:cellForRowAtIndexPath:
method, i.e.
-(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
self.selectedIndexPath = indexPath;
[tableView reloadData];
}
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
...
cell.accessoryType = [indexPath compare:self.selectedIndexPath] == NSOrderedSame
? UITableViewCellAccessoryCheckmark
: UITableViewCellAccessoryNone;
...
}
With this, only visible cells will be affected, and the million other cells outside of the screen won't need to be modified.
Quite right, here's a full implementation in Swift in the general case of selecting a cell .. you'd use selectedIndexPath elsewhere in the class as you see fit. For example, in cellForRowAtIndexPath
to choose the appropriate cell prototype.
// SelectingTableViewController
import UIKit
class SelectingTableViewController: UITableViewController
{
internal var selectedIndexPath:NSIndexPath? = nil
override func viewDidLoad()
{
super.viewDidLoad()
tableView.estimatedRowHeight = 68.0
tableView.rowHeight = UITableViewAutomaticDimension
self.clearsSelectionOnViewWillAppear = false;
}
override func tableView
(tableView:UITableView, didSelectRowAtIndexPath indexPath:NSIndexPath)
{
print("did select....")
// in fact, was this very row selected,
// and the user is clicking to deselect it...
// if you don't want "click a selected row to deselect"
// then on't include this clause.
if selectedIndexPath == indexPath
{
print("(user clicked on selected to deselect)")
selectedIndexPath = nil
tableView.reloadRowsAtIndexPaths(
[indexPath],
withRowAnimation:UITableViewRowAnimation.None)
tableView.deselectRowAtIndexPath(indexPath, animated:false)
return
}
// in fact, was some other row selected??
// user is changing to this row? if so, also deselect that row
if selectedIndexPath != nil
{
let pleaseRedrawMe = selectedIndexPath!
// (note that it will be drawn un-selected
// since we're chaging the 'selectedIndexPath' global)
selectedIndexPath = indexPath
tableView.reloadRowsAtIndexPaths(
[pleaseRedrawMe, indexPath],
withRowAnimation:UITableViewRowAnimation.None)
return;
}
// no previous selection.
// simply select that new one the user just touched.
// note that you can not use Apple's willDeselectRowAtIndexPath
// functions ... because they are freaky
selectedIndexPath = indexPath
tableView.reloadRowsAtIndexPaths(
[indexPath],
withRowAnimation:UITableViewRowAnimation.None)
}
}
for (UITableViewCell *cell in [myTableView visibleCells]) {
cell.accessoryType = UITableViewCellAccessoryNone;
}
But really, you'd be better off just modifying the one cell that actually has the checkmark set. You have to have stored this information somewhere in your model anyway.
You're probably setting some kind of property with this method. So what i do is:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// 1. first unsetting the property
[object someProperty:nil];
// 2. call the reloadData method to uncheck all the checkmarks
[tableView reloadData];
// 3. check the selected cell
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
// 4. set the checked property
[object setSomeProperty:[indexpath row]];
}
And in my cellForRowAtIndexPath methods i got something like the following code:
if([object someProperty] == [indexpath row]){
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
} else {
[cell setAccessoryType:UITableViewCellAccessoryNone];
}
Yes, cellForRowAtIndexPath:
uses NSIndexPath
instead of integer so make indexpath by using
indexPathForRow:inSection:
if you are using one section then your loop is fine just pass i in row and 0 for section.
精彩评论