Tener un UITextField en una UITableViewCell

Intento hacerlo durante un par de días y, después de leer toneladas de mensajes de personas que intentan hacer eso también, todavía no puedo tener un UITextField completamente funcional en algunas de mis UITableViewCells , como en este ejemplo :

Captura de pantalla

O tengo el formulario funcionando pero el texto no está visible (aunque configuré su color en azul), el teclado entra en el campo cuando hago clic en él y no he podido implementar correctamente los eventos del teclado. Intenté con un montón de ejemplos de Apple (principalmente UICatalog , donde hay un control similar) pero todavía no funciona correctamente.

¿Puede alguien ayudarme (y todas las personas que intentan realizar este control) y publicar una implementación simple de un UITextField en una UITableViewCell , que funciona bien?

Probar esto. Funciona como un encanto para mí (en dispositivos iPhone). Usé este código para una pantalla de inicio de sesión una vez. Configuré la vista de tabla para tener dos secciones. Por supuesto, puede deshacerse de los condicionales de la sección.

 - (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.contentView 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; } 

El resultado se ve así:

formulario de acceso

Aquí hay una solución que se ve bien en iOS6 / 7/8/9 .

Actualización 2016-06-10: esto todavía funciona con iOS 9.3.3

Gracias por su apoyo, ahora está en CocoaPods / Carthage / SPM en https://github.com/fulldecent/FDTextFieldTableViewCell

Básicamente tomamos el stock UITableViewCellStyleValue1 y UITableViewCellStyleValue1 un UITextField donde se supone que debe estar el detailTextLabel . Esto nos da una ubicación automática para todos los escenarios: iOS6 / 7/8/9, iPhone / iPad, Imagen / Sin imagen, Accesorio / Sin accesorios, Retrato / Paisaje, 1x / 2x / 3x.

enter image description here

Nota: esto está usando el guión gráfico con una UITableViewCellStyleValue1 tipo UITableViewCellStyleValue1 llamada “palabra”.

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { cell = [tableView dequeueReusableCellWithIdentifier:@"word"]; cell.detailTextLabel.hidden = YES; [[cell viewWithTag:3] removeFromSuperview]; textField = [[UITextField alloc] init]; textField.tag = 3; textField.translatesAutoresizingMaskIntoConstraints = NO; [cell.contentView addSubview:textField]; [cell addConstraint:[NSLayoutConstraint constraintWithItem:textField attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:cell.textLabel attribute:NSLayoutAttributeTrailing multiplier:1 constant:8]]; [cell addConstraint:[NSLayoutConstraint constraintWithItem:textField attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:cell.contentView attribute:NSLayoutAttributeTop multiplier:1 constant:8]]; [cell addConstraint:[NSLayoutConstraint constraintWithItem:textField attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:cell.contentView attribute:NSLayoutAttributeBottom multiplier:1 constant:-8]]; [cell addConstraint:[NSLayoutConstraint constraintWithItem:textField attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:cell.detailTextLabel attribute:NSLayoutAttributeTrailing multiplier:1 constant:0]]; textField.textAlignment = NSTextAlignmentRight; textField.delegate = self; return cell; } 

Así es como he logrado esto:

TextFormCell.h

 #import  #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]; } 

Puede parecer un poco detallado, ¡pero funciona!

¡No te olvides de configurar el delegado!

Prueba este. También puede manejar el desplazamiento y puede reutilizar las celdas sin la molestia de eliminar las subvistas que agregó antes.

 - (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]; } 

Esto no debería ser difícil. Al crear una celda para su tabla, agregue un objeto UITextField a la vista de contenido de la celda

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

Establezca el delegado de UITextField como uno mismo (es decir, su controlador de visualización). Dé una etiqueta al campo de texto para que pueda identificar qué campo de texto fue editado en sus métodos de delegado. El teclado debería aparecer cuando el usuario toca el campo de texto. Lo conseguí trabajando así. Espero eso ayude.

Había estado evitando esto llamando a un método para ejecutar [cell.contentView bringSubviewToFront:textField] cada vez que aparecían mis células, pero luego descubrí esta técnica relativamente simple:

 cell.accessoryView = textField; 

No parece tener el mismo problema de sobrepaso de fondo, y se alinea solo (algo). Además, textLabel auto-trunca para evitar el desbordamiento hacia (o debajo de) it, que es útil.

UITextField en una UITableViewCell en Swift 3

Detalles

Xcode 8.2.1, Swift 3

Tarea

Cree UITextField en UITableViewCell y delegue la función de edición de UITextField a ViewController

Código de muestra completo

clase ViewController

 import UIKit class ViewController: UIViewController { @IBOutlet var tableView: UITableView! override func viewDidLoad() { super.viewDidLoad() setupTableView() } } // MARK: - TableView extension ViewController { func setupTableView() { tableView.dataSource = self tableView.tableFooterView = UIView() let gesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.endEditing)) tableView.addGestureRecognizer(gesture) } func endEditing() { tableView.endEditing(true) } } // MARK: - UITableViewDataSource extension ViewController: UITableViewDataSource { func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 2 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "TextFieldInTableViewCell") as! TextFieldInTableViewCell cell.delegate = self return cell } } // MARK: - TextFieldInTableViewCellDelegate extension ViewController: TextFieldInTableViewCellDelegate { func textFieldInTableViewCell(didSelect cell:TextFieldInTableViewCell) { if let indexPath = tableView.indexPath(for: cell){ print("didSelect cell: \(indexPath)") } } func textFieldInTableViewCell(cell:TextFieldInTableViewCell, editingChangedInTextField newText:String) { if let indexPath = tableView.indexPath(for: cell){ print("editingChangedInTextField: \"\(newText)\" in cell: \(indexPath)") } } } 

clase TextFieldInTableViewCell

 import UIKit class TextFieldInTableViewCell: UITableViewCell { @IBOutlet var textField: UITextField! @IBOutlet var descriptionLabel: UILabel! var delegate: TextFieldInTableViewCellDelegate? override func awakeFromNib() { super.awakeFromNib() let gesture = UITapGestureRecognizer(target: self, action: #selector(TextFieldInTableViewCell.didSelectCell)) addGestureRecognizer(gesture) } } // MARK: - Actions extension TextFieldInTableViewCell { func didSelectCell() { textField.becomeFirstResponder() delegate?.textFieldInTableViewCell(didSelect: self) } @IBAction func textFieldValueChanged(_ sender: UITextField) { if let text = sender.text { delegate?.textFieldInTableViewCell(cell: self, editingChangedInTextField: text) } } } 

protocolo TextFieldInTableViewCellDelegate

 import UIKit protocol TextFieldInTableViewCellDelegate { func textFieldInTableViewCell(didSelect cell:TextFieldInTableViewCell) func textFieldInTableViewCell(cell:TextFieldInTableViewCell, editingChangedInTextField newText:String) } 

Main.storyboard

 < ?xml version="1.0" encoding="UTF-8"?>                                                                                  

Resultado

enter image description here enter image description here

Tuve el mismo problema. Parece que establecer la propiedad cell.textlabel.text lleva el UILabel al frente del contentView de la celda. Agregue textView después de configurar textLabel.text o (si eso no es posible) llame a esto:

 [cell.contentView bringSubviewToFront:textField] 

Realmente tuve problemas con esta tarea en el iPad, con campos de texto que se muestran invisibles en UITableView, y toda la fila se vuelve azul cuando se enfoca.

Lo que funcionó para mí al final fue la técnica descrita en “La técnica del contenido estático de filas” en la Guía de progtwigción de Apple View . Puse la etiqueta y el campo de texto en una UITableViewCell en el NIB para la vista, y extraigo esa celda a través de una salida en cellForRowAtIndexPath: El código resultante es mucho más nítido que UICatalog.

Así es como se hace, creo que es la forma correcta. Funciona en Ipad y Iphone cuando lo probé. Tenemos que crear nuestras propias CustomCells clasificando una uitableviewcell:

comience en interfaceBuilder … cree un nuevo UIViewcontroller llámelo CustomCell (haga de voluntario para un xib mientras esté allí) Asegúrese de que customCell sea una subclase de uitableviewcell

borre todas las vistas ahora y cree una vista que sea del tamaño de una celda individual. hacer esa subclase viewcell personalizada. ahora crea otras dos vistas (duplica el primero).
Vaya a su inspector de conexiones y encuentre 2 IBOutlets que puede conectar con estas vistas ahora.

-backgroundView -SelectedBackground

conéctelos a las dos últimas vistas que acaba de duplicar y no se preocupe por ellas. la primera vista que extiende customCell, coloca tu etiqueta y uitextfield dentro de ella. entra en customCell.h y conecta su etiqueta y campo de texto. Establezca el alto de esta vista para decir 75 (altura de cada celda) todo hecho.

En su archivo customCell.m, asegúrese de que el constructor tenga el siguiente aspecto:

 - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { // Initialization code NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil]; self = [nibArray objectAtIndex:0]; } return self; } 

Ahora crea un UITableViewcontroller y en este método utiliza la clase customCell como esta:

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; // lets use our customCell which has a label and textfield already installed for us customCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { //cell = [[[customCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; NSArray *topLevelsObjects = [[NSBundle mainBundle] loadNibNamed:@"NewUserCustomCell" owner:nil options:nil]; for (id currentObject in topLevelsObjects){ if ([currentObject isKindOfClass:[UITableViewCell class]]){ cell = (customCell *) currentObject; break; } } NSUInteger row = [indexPath row]; switch (row) { case 0: { cell.titleLabel.text = @"First Name"; //label we made (uitextfield also available now) break; } } return cell; 

}

 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return 75.0; } 

Aquí hay una subclase para UITableViewCell que reemplaza a detailTextLabel con un UITextField editable (o, en el caso de UITableViewCellStyleDefault , reemplaza a la etiqueta de texto ). Esto tiene la ventaja de que le permite volver a utilizar todos los UITableViewCellStyles familiares, accesorios visuales, etc., ¡ahora el detalle es editable!

 @interface GSBEditableTableViewCell : UITableViewCell  @property UITextField *textField; @end @interface GSBEditableTableViewCell () @property UILabel *replace; @end @implementation GSBEditableTableViewCell - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { _replace = (style == UITableViewCellStyleDefault)? self.textLabel : self.detailTextLabel; _replace.hidden = YES; // Impersonate UILabel with an identical UITextField _textField = UITextField.new; [self.contentView addSubview:_textField]; _textField.translatesAutoresizingMaskIntoConstraints = NO; [_textField.leftAnchor constraintEqualToAnchor:_replace.leftAnchor].active = YES; [_textField.rightAnchor constraintEqualToAnchor:_replace.rightAnchor].active = YES; [_textField.topAnchor constraintEqualToAnchor:_replace.topAnchor].active = YES; [_textField.bottomAnchor constraintEqualToAnchor:_replace.bottomAnchor].active = YES; _textField.font = _replace.font; _textField.textColor = _replace.textColor; _textField.textAlignment = _replace.textAlignment; // Dont want to intercept UITextFieldDelegate, so use UITextFieldTextDidChangeNotification instead [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(textDidChange:) name:UITextFieldTextDidChangeNotification object:_textField]; // Also need KVO because UITextFieldTextDidChangeNotification not fired when change programmatically [_textField addObserver:self forKeyPath:@"text" options:0 context:nil]; } return self; } - (void)textDidChange:(NSNotification*)notification { // Update (hidden) UILabel to ensure correct layout if (_textField.text.length) { _replace.text = _textField.text; } else if (_textField.placeholder.length) { _replace.text = _textField.placeholder; } else { _replace.text = @" "; // otherwise UILabel removed from cell (!?) } [self setNeedsLayout]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ((object == _textField) && [keyPath isEqualToString:@"text"]) [self textDidChange:nil]; } - (void)dealloc { [_textField removeObserver:self forKeyPath:@"text"]; } @end 

Fácil de usar: simplemente cree su celda como antes, pero ahora use cell.textField en lugar de cell.detailTextLabel (o cell.textLabel en el caso de UITableViewCellStyleDefault ). p.ej

 GSBEditableTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; if (!cell) cell = [GSBEditableTableViewCell.alloc initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:@"Cell"]; cell.textLabel.text = @"Name"; cell.textField.text = _editablename; cell.textField.delegate = self; // to pickup edits ... 

Inspirado por, y mejorado en, la respuesta de FD

Para eventos next / return en múltiples UITextfield dentro de UITableViewCell en este método, tomé UITextField en el guión gráfico.

 @interface MyViewController () { NSInteger currentTxtRow; } @end @property (strong, nonatomic) NSIndexPath *currentIndex;//Current Selected Row @implementation MyViewController - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CELL" forIndexPath:indexPath]; cell.selectionStyle = UITableViewCellSelectionStyleNone; UITextField *txtDetails = (UITextField *)[cell.contentView viewWithTag:100]; txtDetails.delegate = self; txtDetails.placeholder = self.arrReciversDetails[indexPath.row]; return cell; } #pragma mark - UITextFieldDelegate - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { CGPoint point = [textField convertPoint:CGPointZero toView:self.tableView]; self.currentIndex = [self.tableView indexPathForRowAtPoint:point];//Get Current UITableView row currentTxtRow = self.currentIndex.row; return YES; } - (BOOL)textFieldShouldReturn:(UITextField *)textField { currentTxtRow += 1; self.currentIndex = [NSIndexPath indexPathForRow:currentTxtRow inSection:0]; UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:self.currentIndex]; UITextField *currentTxtfield = (UITextField *)[cell.contentView viewWithTag:100]; if (currentTxtRow < 3) {//Currently I have 3 Cells each cell have 1 UITextfield [currentTxtfield becomeFirstResponder]; } else { [self.view endEditing:YES]; [currentTxtfield resignFirstResponder]; } } 

Para tomar el texto del campo de texto-

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { switch (self.currentIndex.row) { case 0: NSLog(@"%@",[NSString stringWithFormat:@"%@%@",textField.text,string]);//Take current word and previous text from textfield break; case 1: NSLog(@"%@",[NSString stringWithFormat:@"%@%@",textField.text,string]);//Take current word and previous text from textfield break; case 2: NSLog(@"%@",[NSString stringWithFormat:@"%@%@",textField.text,string]);//Take current word and previous text from textfield break; default: break; } }