我有一个使用自定义单元格的 TableView 的应用程序,每个单元格都包含一个 textField。当用户点击一个单元格时,我想将相应的 textField 置于编辑模式。如果另一个单元格的 textField 已经处于编辑模式,我需要让它 resignFirstResponder 以便我可以保存它的数据,然后使新单元格的 textField 成为 FirstResponder。但是当我在新单元格的 textField 上调用 becomeFirstResponder 时,它返回一个零,表示失败。这似乎是一种混乱的处理方式,但我还没有找到更好的方法。
这是我的 TableViewController 文件的全文,其中去除了很多杂乱的内容:
// TEST_TVC.h
// TVC_Test
#import <UIKit/UIKit.h>
@interface TEST_TVC : UITableViewController <UITextFieldDelegate>
@end
// TEST_TVC.m
// TVC_Test
#import "TEST_TVC.h"
@interface TEST_TVC ()
@property (strong, nonatomic) NSMutableArray * TestData;
@property (strong, nonatomic) UITextField * fieldBeingEdited;
@property (assign, nonatomic) NSInteger cellIndex;
@property (strong, nonatomic) UITableViewCell * cellContainingField;
@end
@implementation TEST_TVC
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Init data for testing the TableView
self.TestData = [NSMutableArray array];
for (int i=0; i<25; i++) {
NSString * title = [NSString stringWithFormat:@"Field %d", i];
NSArray * data = [NSArray arrayWithObjects:title, @"*", nil];
[self.TestData addObject:data];
}
self.fieldBeingEdited = NULL;
self.cellContainingField = NULL;
self.cellIndex = -1;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.TestData.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Configure the cell...
NSString *CellIdentifier = @"TVCell";
NSString * titleText;
NSString * detailText;
NSString * detailPlaceholder = @"none";
// Get the data for this row
int rowNumber = indexPath.row;
NSArray * cellData = self.TestData[rowNumber];
titleText = cellData[0];
detailText = cellData[1];
//NSLog(@"cellForRow..., entered row=%d, titleText=%@, detailText=%@", rowNumber, titleText, detailText);
// Retrieve a pre-built cell to fill in the blanks
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UILabel * cellTitle = (UILabel *)[cell viewWithTag:98];
cellTitle.text = titleText;
UITextField * cellDetail = (UITextField *)[cell viewWithTag:99];
NSLog(@"cellForRow.. reusing cell with Title=%@ and Detail=%@", cellTitle.text, cellDetail.text);
NSLog(@"cellForRow.. intended Title=%@, intended Detail=%@", titleText, detailText);
if (cellDetail == NULL) {
NSLog(@"cellForRow..; cellDetail = NULL *******************************************");
}
// Set default configuration of the cellData UITextField here, and make exceptions later
cellDetail.placeholder = @"";
cellDetail.text = @"";
cellDetail.borderStyle = UITextBorderStyleRoundedRect;
cellDetail.userInteractionEnabled = NO;
cell.accessoryType = UITableViewCellAccessoryNone;
cell.userInteractionEnabled = YES;
// Configure the cell...
// based on the data type of the cell's contents
// Set the cell's editable textField
if ( [detailText isEqualToString:@"*"] ) {
cellDetail.text = @"";
cellDetail.placeholder = detailPlaceholder;
} else {
cellDetail.text = detailText;
}
cellDetail.keyboardType = UIKeyboardTypeASCIICapable;
cellDetail.autocapitalizationType = UITextAutocapitalizationTypeWords;
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int rowNumber = indexPath.row;
[tableView deselectRowAtIndexPath:indexPath animated:NO];
NSLog(@"didSelectRow.. entered; row=%d, cellData=%@", rowNumber, self.TestData[rowNumber]);
// The selected cell contains a textField with content to be edited
// If another cell's textField is currently being edited, save its data before proceding
UITableViewCell * cell = [tableView cellForRowAtIndexPath:indexPath];
UITextField * cellDetail = (UITextField *)[cell viewWithTag:99];
NSLog(@"didSelectRow..: curently editing cell at [%p], selected cell at [%p]", self.fieldBeingEdited, cell);
// if a textField is still in edit mode, show the Responder status of the cell and all in it
if ( self.fieldBeingEdited != NULL ) {
[self showCellResponderStatus:self.cellContainingField];
}
if ( self.fieldBeingEdited == NULL ) {
NSLog(@"didSelectRow..: no field is being edited.");
} else if ( cellDetail == self.fieldBeingEdited ) {
// the cell selected is the same one being edited
if ( ![self.fieldBeingEdited isFirstResponder] ) {
// fieldBeingEdited is NOT the firstResponder. Try to make it the firstResponder.
BOOL becameFirstResponder = [self.fieldBeingEdited becomeFirstResponder];
NSLog(@"didSelectRow..: textField at [%p] returned %d from becomeFirstResponder.", self.fieldBeingEdited, becameFirstResponder);
[self showCellResponderStatus:self.cellContainingField];
}
} else if ( cellDetail != self.fieldBeingEdited ) {
// the cell selected is NOT the one being edited. Save the edited data and release the keyboard
NSLog(@"didSelectRow..: field in cell with index=%d is being edited. Text=%@", self.cellIndex, self.fieldBeingEdited.text);
BOOL resignedFirstResponder;
[self showCellResponderStatus:self.cellContainingField];
// This method call will log the responder status of this cell and all it is contained within
//[self showViewHierarchy:self.fieldBeingEdited];
resignedFirstResponder = [self.fieldBeingEdited resignFirstResponder];
NSLog(@"didSelect..: resignFirstResponder on [%p] returned %d", self.fieldBeingEdited, resignedFirstResponder);
//[self showViewHierarchy:self.fieldBeingEdited];
if (resignedFirstResponder) {
self.fieldBeingEdited = NULL;
self.cellContainingField = NULL;
self.cellIndex = -1;
}
}
// Enable the textField within the selected cell for in-place editing
cellDetail.userInteractionEnabled = YES;
cellDetail.enabled = YES;
BOOL becameFirstResponder = [cellDetail becomeFirstResponder];
NSLog(@"didSelectRow..: becomeFirstResponder returned %d", becameFirstResponder);
if ( becameFirstResponder ) {
// Update all the references and indexes for the cell and textField being edited.
self.fieldBeingEdited = cellDetail;
self.cellContainingField = cell;
self.cellIndex = rowNumber;
}
NSLog(@"didSelectRow.. exit; textFieldBeingEdited.text=%@, cellIndex=%d", self.fieldBeingEdited.text, self.cellIndex);
}
-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField
{
NSLog(@"textFieldShouldBeginEditing entered");
NSLog(@"... returning YES");
return YES;
}
-(void) textFieldDidEndEditing:(UITextField *)textField
{
NSLog(@"textFieldDidEndEditing entered with text: %@, cellIndex=%d", textField.text, self.cellIndex);
NSInteger cellIndex = self.cellIndex;
NSMutableArray * cellData = [NSMutableArray arrayWithArray:self.TestData[cellIndex]];
[cellData replaceObjectAtIndex:1 withObject:textField.text];
[self.TestData replaceObjectAtIndex:cellIndex withObject:cellData];
textField.enabled = NO;
[self.tableView reloadData];
if ( [textField isFirstResponder] ) {
NSLog(@"EditFlight(466): textFieldDidEndEditing; textField IS STILL the firstresponder!");
}
NSLog(@"textFieldDidEndEditing exit; cellData=%@", cellData);
}
-(BOOL) textFieldShouldReturn: (UITextField *)textField
{
NSLog(@"textFieldShouldReturn; textField.text=%@", textField.text);
[textField resignFirstResponder];
BOOL resignedFirstResponder = [textField resignFirstResponder];
NSLog(@"textFieldShouldReturn; resignFirstResponder returned %d",resignedFirstResponder);
return YES;
}
-(void) showCellResponderStatus:(UITableViewCell*)cell
{
NSLog(@"showCellResponderStatus entered");
if ( [cell isFirstResponder] ) {
NSLog(@"cell at [%p] IS first responder", cell);
}else{
NSLog(@"cell at [%p] IS NOT first responder", cell);
}
NSArray * cellSubViews = [[cell contentView] subviews];
for ( UIView* uiv in cellSubViews ) {
if ( [uiv isFirstResponder ]) {
NSLog(@"subview at [%p] is a %@ and IS first responder", uiv, uiv.class);
} else {
NSLog(@"subview at [%p] is a %@ and IS NOT first responder", uiv, uiv.class);
}
}
}
-(void) showViewHierarchy:(UIView*) uiv
{
NSLog(@"View Hierarchy");
while (uiv != NULL) {
BOOL isfirst = [uiv isFirstResponder];
NSLog(@"view at [%p] is a %@, isFirstResponder=%d", uiv, uiv.class, isfirst);
uiv = uiv.superview;
}
NSLog(@"view at [%p] is a %@", uiv, uiv.class);
NSLog(@"End of view hierarchy");
}
@end