Friday, June 8, 2012

Having a UITextField in a UITableViewCell


I'm trying to do that for a couple of days now, and after reading tons of messages of people trying to do that too, I'm still unable to have a fully working UITextField in some of my UITableViewCells , just like in this example:



Screenshot



Either I have the form working but the text is not visible (although I set its color to blue), the keyboard goes on the field when I click on it and I haven't been able to correctly implement the keyboard events. I tried with a bunch of examples from Apple (mainly UICatalog , where there is a kinda similar control) but it's still not working correctly.



Can somebody help me (and all the people trying to realize this control) and post a simple implementation of a UITextField in a UITableViewCell , that works fine?


Source: Tips4all

9 comments:

  1. Try this out. Works like a charm for me (on iPhone devices). I used this code for a login screen once. I configured the table view to have two sections. You can of course get rid of the section conditionals.

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
    if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
    reuseIdentifier:kCellIdentifier] autorelease];
    cell.accessoryType = UITableViewCellAccessoryNone;

    if ([indexPath section] == 0) {
    UITextField *playerTextField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)];
    playerTextField.adjustsFontSizeToFitWidth = YES;
    playerTextField.textColor = [UIColor blackColor];
    if ([indexPath row] == 0) {
    playerTextField.placeholder = @"example@gmail.com";
    playerTextField.keyboardType = UIKeyboardTypeEmailAddress;
    playerTextField.returnKeyType = UIReturnKeyNext;
    }
    else {
    playerTextField.placeholder = @"Required";
    playerTextField.keyboardType = UIKeyboardTypeDefault;
    playerTextField.returnKeyType = UIReturnKeyDone;
    playerTextField.secureTextEntry = YES;
    }
    playerTextField.backgroundColor = [UIColor whiteColor];
    playerTextField.autocorrectionType = UITextAutocorrectionTypeNo; // no auto correction support
    playerTextField.autocapitalizationType = UITextAutocapitalizationTypeNone; // no auto capitalization support
    playerTextField.textAlignment = UITextAlignmentLeft;
    playerTextField.tag = 0;
    //playerTextField.delegate = self;

    playerTextField.clearButtonMode = UITextFieldViewModeNever; // no clear 'x' button to the right
    [playerTextField setEnabled: YES];

    [cell addSubview:playerTextField];

    [playerTextField release];
    }
    }
    if ([indexPath section] == 0) { // Email & Password Section
    if ([indexPath row] == 0) { // Email
    cell.textLabel.text = @"Email";
    }
    else {
    cell.textLabel.text = @"Password";
    }
    }
    else { // Login button section
    cell.textLabel.text = @"Log in";
    }
    return cell;
    }


    Result looks like this:

    ReplyDelete
  2. Here is how I have achieved this:

    TextFormCell.h

    #import <UIKit/UIKit.h>

    #define CellTextFieldWidth 90.0
    #define MarginBetweenControls 20.0

    @interface TextFormCell : UITableViewCell {
    UITextField *textField;
    }

    @property (nonatomic, retain) UITextField *textField;

    @end


    TextFormCell.m

    #import "TextFormCell.h"

    @implementation TextFormCell

    @synthesize textField;

    - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier {
    if (self = [super initWithReuseIdentifier:reuseIdentifier]) {
    // Adding the text field
    textField = [[UITextField alloc] initWithFrame:CGRectZero];
    textField.clearsOnBeginEditing = NO;
    textField.textAlignment = UITextAlignmentRight;
    textField.returnKeyType = UIReturnKeyDone;
    [self.contentView addSubview:textField];
    }
    return self;
    }

    - (void)dealloc {
    [textField release];
    [super dealloc];
    }

    #pragma mark -
    #pragma mark Laying out subviews

    - (void)layoutSubviews {
    CGRect rect = CGRectMake(self.contentView.bounds.size.width - 5.0,
    12.0,
    -CellTextFieldWidth,
    25.0);
    [textField setFrame:rect];
    CGRect rect2 = CGRectMake(MarginBetweenControls,
    12.0,
    self.contentView.bounds.size.width - CellTextFieldWidth - MarginBetweenControls,
    25.0);
    UILabel *theTextLabel = (UILabel *)[self textLabel];
    [theTextLabel setFrame:rect2];
    }


    It may seems a bit verbose, but it works!

    Don't forget to set the delegate!

    ReplyDelete
  3. Try this one. It can handle scrolling as well and you can reuse the cells without the hassle of removing subviews you added before.

    - (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section{
    return 10;
    }

    - (UITableViewCell *)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [table dequeueReusableCellWithIdentifier:@"Cell"];
    if( cell == nil)
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"] autorelease];

    cell.textLabel.text = [[NSArray arrayWithObjects:@"First",@"Second",@"Third",@"Forth",@"Fifth",@"Sixth",@"Seventh",@"Eighth",@"Nineth",@"Tenth",nil]
    objectAtIndex:indexPath.row];

    if (indexPath.row % 2) {
    UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 200, 21)];
    textField.placeholder = @"Enter Text";
    textField.text = [inputTexts objectAtIndex:indexPath.row/2];
    textField.tag = indexPath.row/2;
    textField.delegate = self;
    cell.accessoryView = textField;
    [textField release];
    } else
    cell.accessoryView = nil;

    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    return cell;
    }

    - (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    [inputTexts replaceObjectAtIndex:textField.tag withObject:textField.text];
    return YES;
    }

    - (void)viewDidLoad {
    inputTexts = [[NSMutableArray alloc] initWithObjects:@"",@"",@"",@"",@"",nil];
    [super viewDidLoad];
    }

    ReplyDelete
  4. This should not be difficult. When creating a cell for your table, add a UITextField object to the cell's content view

    UITextField *txtField = [[UITextField alloc] initWithFrame....]
    ...
    [cell.contentView addSubview:txtField]


    Set the delegate of the UITextField as self (ie your viewcontroller) Give a tag to the text field so you can identify which textfield was edited in your delegate methods. The keyboard should pop up when the user taps the text field. I got it working like this. Hope it helps.

    ReplyDelete
  5. I had been avoiding this by calling a method to run [cell.contentView bringSubviewToFront:textField] every time my cells appeared, but then I discovered this relatively simple technique:

    cell.accessoryView = textField;


    Doesn't seem to have the same background-overpasting issue, and it aligns itself on its own (somewhat). Also, the textLabel auto-truncates to avoid overflowing into (or under) it, which is handy.

    ReplyDelete
  6. This a complex problem. I did post my solution in a similar post: http://stackoverflow.com/questions/350868/clicking-on-uitextfield-in-a-uitableviewcell/2030005#2030005

    ReplyDelete
  7. I realy struggled with this task on the iPad, with text fields showing up invisible in the UITableView, and the whole row turning blue when it gets focus.

    What worked for me in the end was the technique described under "The Technique for Static Row Content" in Apple's
    Table View Programming Guide. I put both the label and the textField in a Table View Cell in the NIB for the view, and pull that cell out via an outlet in cellForRowAtIndexPath. The resulting code is much neater than UICatalog.

    ReplyDelete
  8. I ran into the same problem. It seems that setting the cell.textlabel.text property brings the UILabel to the front of the contentView of the cell.
    Add the textView after setting textLabel.text or (if that's not possible) call: [cell.contentView bringSubviewToFront:textField].

    ReplyDelete
  9. I said had it working. =) Anyway I used the EditableDetailView sample. I think the EditCell class might be the key. Did you try that sample?

    ReplyDelete