Clear all UITextField changes in a UITableView with a UIButton
I have a UITableView with a dozen rows, each containing a UITextField. By default the UITextField contains a placeholder value "Add Value" if the user hasn't previously edited the text field:
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(158, 6, 148, 24)];
NSString *strReplacement = [valueArray objectAtIndex:indexPath.row];
if (([strReplacement length] != 0) {
textField.text = strReplacement;
} else {
textField.placeholder = @"Add Value";
}
textField.delegate = self;
[cell addSubview:textF开发者_如何学JAVAield];
[textField release];
So far so good.
I've also added a UIButton to the footer of the UITableView. What I want is to clear all the edited values and refresh all the UITextFields in the UITableView when the user clicks the UIButton.
I can easily enough remove all objects from the valueArray but I can't figure out how to refresh all the UITableView cells to reflect the changes.
Any help is appreciated. lq
I believe what you're looking for is
[tableView reloadData];
Your solution feels weird. Filipe's right that the correct way to do it is with [wordsTableView reloadData]
, which will cause tableView:cellForRowAtIndexPath:
to be called for each visible cell. That method is also called as you scroll through the table, so if reloadData isn't working, you're probably also going to end up with bugs with data not updating correctly as you change it and scroll. In your clearValues method, you're doing the same thing by calling tableView:cellForRowAtIndexPath:
.
I think the real problem is in your tableView:cellForRowAtIndexPath:
implementation. That method generally has 2 sections. First, you create or recycle a cell to get a reference with something like:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
}
Inside that if statement is generally the only place you should be adding subviews to your cell. If dequeueReusableCellWithIdentifier:
returns a cell, it should already have the subview.
Then, after that if statement, you populate or update the contents of the subviews. The problem with your original code is that it's populating the text field and adding it as a subview, assuming there isn't already a text field in the cell. So your tableView:cellForRowAtIndexPath:
should look something more like this:
int textFieldTag = 100;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(158, 6, 148, 24)];
[textField setTag:textFieldTag];
[textField setDelegate:self];
[cell addSubview:textField];
[textField release];
}
UITextField *textField = [cell viewWithTag:textFieldTag];
NSString *strReplacement = [valueArray objectAtIndex:indexPath.row];
if (([strReplacement length] != 0) {
textField.text = strReplacement;
} else {
textField.placeholder = @"Add Value";
}
It looks like you may be setting the textField's tag value to the row number, presumably so you can use it in the UITextFieldDelegate. That could also lead to bugs, as if the cell from row 1 is recycled by dequeueReusableCellWithIdentifier:
and becomes row 12, it's going to have an unexpected tag value. Even if it doesn't happen now, it's a bug waiting to happen, and will be tricky to troubleshoot.
Filipe's solution should also work, however, calling reloadData
should be avoided wherever possible as calling this method has a high performance overhead.
You need some class that has a reference to both the UIButton instance as well as all the instances of the UITextField that you have on the screen/in the table. Sounds like the perfect job for your UITableView controller subclass!
In your code above, why don't you also add each UITextField that you create to an NSArray of text fields that lives in your UITableView controller? Then when the user presses the UIButton, the action can call some method in your controller class, which loops through all the UITextField elements in the NSArray setting the text
property of each instance to @""
.
Warning: If you're reusing cells then you may have to ensure that the controller's NSArray of UITextFields is being updated properly.
After a few hours of trial and error, I came up with this solution. The UIButton "Clear All" invokes the following method:
- (IBAction)clearValues:(id)sender {
// count the number of values in the array (this is the same as the number of rows in the table)
int count = [valueArray count];
// remove all values from the array (deletes any user added values):
[self.valueArray removeAllObjects];
UITableViewCell *cell;
UITextField *textField;
// loop through each row in the table and put nil in each UITextField:
for (NSUInteger i = 0; i < count; ++i) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
cell = [self.wordsTableView cellForRowAtIndexPath:indexPath];
// NOTE: Make sure none of your tags are set to 0 since all non-tagged objects are zero.
// In table construction, your textFieldTags should be: textField.tag=indexPath.row+1;
textField = (UITextField*)[cell viewWithTag:i+1];
textField.text = nil;
}
}
精彩评论