Having a UITextField in a UITableViewCell
我现在试图这样做几天,在阅读了大量试图这样做的人的消息之后,我仍然无法在我的某些
要么我的表单工作,但文本不可见(虽然我将其颜色设置为蓝色),当我点击它时键盘在场上,我无法正确实现键盘事件。
我尝试了一些来自Apple的示例(主要是
有人可以帮助我(以及所有试图实现此控制的人)并在
试试吧。对我来说就像一个魅力(在iPhone设备上)。我将此代码用于登录屏幕一次。我将表视图配置为包含两个部分。你当然可以摆脱部分条件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | - (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 = @"[email protected]"; 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; } |
结果如下所示:
这是一个在iOS6 / 7/8/9下看起来不错的解决方案。
更新2016-06-10:这仍适用于iOS 9.3.3
感谢您的支持,现在可以通过https://github.com/fulldecent/FDTextFieldTableViewCell访问CocoaPods / Carthage / SPM
基本上我们采用股票
注意:这是使用具有名为"word"的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | - (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; } |
以下是我如何实现这一目标:
TextFormCell.h
1 2 3 4 5 6 7 8 9 10 11 12 | #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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #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]; } |
它可能看起来有点冗长,但它确实有效!
别忘了设置代表!
试试这个吧。它也可以处理滚动,您可以重复使用单元格,而无需删除之前添加的子视图。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | - (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]; } |
这应该不难。为表创建单元格时,将UITextField对象添加到单元格的内容视图中
1 2 3 | UITextField *txtField = [[UITextField alloc] initWithFrame....] ... [cell.contentView addSubview:txtField] |
将UITextField的委托设置为self(即viewcontroller)为文本字段指定标记,以便您可以识别在委托方法中编辑的文本字段。当用户点击文本字段时,键盘应弹出。我让它像这样工作。希望能帮助到你。
每次我的细胞出现时,我都会通过调用一个运行
1 | cell.accessoryView = textField; |
似乎没有相同的背景覆盖问题,并且它自己(有点)对齐。此外,textLabel自动截断以避免溢出(或在其下),这很方便。
细节
- Xcode 10.2(10E125),Swift 5
完整的示例代码
TextFieldInTableViewCell
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | import UIKit protocol TextFieldInTableViewCellDelegate: class { func textField(editingDidBeginIn cell:TextFieldInTableViewCell) func textField(editingChangedInTextField newText: String, in cell: TextFieldInTableViewCell) } class TextFieldInTableViewCell: UITableViewCell { private(set) weak var textField: UITextField? private(set) weak var descriptionLabel: UILabel? weak var delegate: TextFieldInTableViewCellDelegate? override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) setupSubviews() } private func setupSubviews() { let stackView = UIStackView() stackView.distribution = .fill stackView.alignment = .leading stackView.spacing = 8 contentView.addSubview(stackView) stackView.translatesAutoresizingMaskIntoConstraints = false stackView.topAnchor.constraint(equalTo: topAnchor, constant: 6).isActive = true stackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -6).isActive = true stackView.leftAnchor.constraint(equalTo: leftAnchor, constant: 16).isActive = true stackView.rightAnchor.constraint(equalTo: rightAnchor, constant: -16).isActive = true let label = UILabel() label.text ="Label" stackView.addArrangedSubview(label) descriptionLabel = label let textField = UITextField() textField.textAlignment = .left textField.placeholder ="enter text" textField.setContentHuggingPriority(.fittingSizeLevel, for: .horizontal) stackView.addArrangedSubview(textField) textField.addTarget(self, action: #selector(textFieldValueChanged(_:)), for: .editingChanged) textField.addTarget(self, action: #selector(editingDidBegin), for: .editingDidBegin) self.textField = textField stackView.layoutSubviews() selectionStyle = .none let gesture = UITapGestureRecognizer(target: self, action: #selector(didSelectCell)) addGestureRecognizer(gesture) } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } } extension TextFieldInTableViewCell { @objc func didSelectCell() { textField?.becomeFirstResponder() } @objc func editingDidBegin() { delegate?.textField(editingDidBeginIn: self) } @objc func textFieldValueChanged(_ sender: UITextField) { if let text = sender.text { delegate?.textField(editingChangedInTextField: text, in: self) } } } |
ViewController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | import UIKit class ViewController: UIViewController { private weak var tableView: UITableView? override func viewDidLoad() { super.viewDidLoad() setupTableView() } } extension ViewController { func setupTableView() { let tableView = UITableView(frame: .zero) tableView.register(TextFieldInTableViewCell.self, forCellReuseIdentifier:"TextFieldInTableViewCell") view.addSubview(tableView) tableView.translatesAutoresizingMaskIntoConstraints = false tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = UITableView.automaticDimension tableView.tableFooterView = UIView() self.tableView = tableView tableView.dataSource = self let gesture = UITapGestureRecognizer(target: tableView, action: #selector(UITextView.endEditing(_:))) tableView.addGestureRecognizer(gesture) } } 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 } } extension ViewController: TextFieldInTableViewCellDelegate { func textField(editingDidBeginIn cell: TextFieldInTableViewCell) { if let indexPath = tableView?.indexPath(for: cell) { print("textfield selected in cell at \(indexPath)") } } func textField(editingChangedInTextField newText: String, in cell: TextFieldInTableViewCell) { if let indexPath = tableView?.indexPath(for: cell) { print("updated text in textfield in cell as \(indexPath), value = "\(newText)"") } } } |
结果
我遇到了同样的问题。似乎设置
设置
1 | [cell.contentView bringSubviewToFront:textField] |
我真的很难在iPad上完成这项任务,文本字段在UITableView中显示为不可见,整个行在获得焦点时变为蓝色。
最终对我有用的是Apple的"静态行内容技术"中描述的技术
表视图编程指南。我将标签和textField放在视图的NIB中的UITableViewCell中,然后通过
以下是我认为正确的方式。当我测试它时,它适用于Ipad和Iphone。我们必须通过对uitableviewcell进行分类来创建我们自己的customCells:
从interfaceBuilder开始......
创建一个新的UIViewcontroller调用它customCell(志愿者为你的那里的xib)
确保customCell是uitableviewcell的子类
现在擦除所有视图并创建一个视图使其成为单个单元格的大小。使该视图子类为customcell。现在创建另外两个视图(复制第一个)。
转到您的连接检查器,找到2个IBOutlet,您现在可以连接到这些视图。
-backgroundView
-SelectedBackground
将这些连接到您刚刚复制的最后两个视图,不要担心它们。
第一个扩展customCell的视图,将你的标签和uitextfield放在其中。
进入customCell.h并连接你的标签和文本字段。将此视图的高度设置为75(每个单元格的高度)
全部完成。
在customCell.m文件中,确保构造函数看起来像这样:
1 2 3 4 5 6 7 8 9 10 | - (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; } |
现在创建一个UITableViewcontroller,在这个方法中使用customCell类,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | - (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; |
}
1 2 3 4 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return 75.0; } |
对于UITableViewCell内的多个UITextfield上的下一个/返回事件,我在故事板中使用了UITextField。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | @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]; } } |
要从文本字段中获取文本 -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | - (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; } } |
这是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | @interface GSBEditableTableViewCell : UITableViewCell <UITextFieldDelegate> @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 |
使用简单 - 只需像以前一样创建您的单元格,但现在使用cell.textField而不是cell.detailTextLabel(如果是
1 2 3 4 5 6 7 | 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 ... |
FD的答案启发并改进了它