2

我有一个使用自定义单元格的 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
4

3 回答 3

1

有一个更简单的方法。didSelectRowAtIndexPath存储对当前单元格的 UITextField 的引用。然后您可以将其设置为第一响应者,处理编辑等。

当您点击一个新单元格以选择它时,代理首先会收到一个didDeselectRowAtIndexPath. 在这里,您可以使用您的 UITextField 引用可以辞职第一响应者,保存任何必要的状态等。然后didDeselectRowAtIndexPath在新单元格上调用,您就可以开始了。所以类似于以下内容:

编辑:添加了额外的代码

// Code additions to Xcode's Master-Detail application template

// Use dynamic prototypes for table cells, custom cell class follows:

// MyCell.h
// Property is auto-synthesized, so there is nothing to see in MyCell.m

@interface MyCell : UITableViewCell
@property (nonatomic, weak) IBOutlet UITextField *tf;
@end



// MasterViewController.m

@interface MasterViewController () {
  NSMutableArray *_objects;
}
@property (nonatomic, weak) UITextField *selectedField;
@end


// this method is called when a cell is DE-selected
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
      [self.selectedField resignFirstResponder];
      // save state, etc if necessary
}


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    MyCell * cell = (MyCell *)[tableView cellForRowAtIndexPath:indexPath];
    self.selectedField = cell.tf; // cell.tf is a UITextField property defined on MyCell
    [self.selectedField becomeFirstResponder];
}
于 2013-10-09T02:03:18.017 回答
0

您可能会问第一个textfield是否是firstResponder然后更改它,然后将第二个设置为firstResponder

if ([textfield isEditing]) {
            [textfield resignFirstResponder];
}

textField在辞去第一响应者的职务之前,首先会询问它的代表:

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField{
}

NO因此,如果您已实施此方法,请检查您返回的原因。

于 2013-09-02T21:52:03.473 回答
0

您也可以使用开源作为 BSKeyboardControls。它还包括其他可能对您有所帮助的键盘-文本字段关系。s 链接:https ://www.cocoacontrols.com/controls/bskeyboardcontrols

于 2013-09-02T22:20:58.400 回答