Reputation: 4440
I have a table view which has a good number of cells in it used to create a form. I have created a custom TableViewCell. This cell contains a label and a text field, so for example, each row will look something like this
I also have a custom table cell which contains a label and a text view, looks the same as image above, just cell is larger to allow room for the textview.
Now each of these text fields and text views has a tool bar added, so when text field becomes first responder, a tool bar is shown with the buttons, done, previous and next buttons.
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc]initWithTitle:@"Done" style:UIBarButtonItemStyleDone target:self action:@selector(doneWithTextField:)];
UIBarButtonItem *nextButton = [[UIBarButtonItem alloc]initWithTitle:@"Next" style:UIBarButtonItemStyleDone target:self action:@selector(nextTableTextField:)];
UIBarButtonItem *previousButton = [[UIBarButtonItem alloc]initWithTitle:@"Previous" style:UIBarButtonItemStyleDone target:self action:@selector(previousTableTextField:)];
UIToolbar *numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
numberToolbar.barStyle = UIBarStyleBlackTranslucent;
numberToolbar.items = [NSArray arrayWithObjects:
previousButton,
nextButton,
[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
doneButton,
nil];
[numberToolbar sizeToFit];
field.inputAccessoryView = numberToolbar;
The issue I am having is, say I have 10 table rows like this, the screen can only show about 5 full rows and a bit of the 6th row. I should add I also have added the code to the text field delegates so that when a text field becomes first responder, screen scrolls to allow the text field to be fully shown. See my older post here for code.
So when screen loads I press the first cell, and click next, works fine, moves onto the 2nd text field in the next cell. Then I hit the next button again, and it goes to the 3rd cell, then 4th, then 5th. Now at this point the problem occurs. When I am on the 5th cell, and I click next, the 6th text field becomes the first responder but the screen does not scroll for some reason. Now the bigger problem is, when I click next again, it does not move onto the 7th text field, as the 7th cell is not in memory yet as it is not visible on the screen. So if I hit next, it won't do anything, text field 6 will remain as the first responder. So I need to scroll down a bit first, so cell 7 is visible before the next button will work and make the next text field the first responder.
It is the same issue when hitting the previous button, if hit previous button and the previous cell is not in screen, then it will not do anything until that cell is visible on the screen.
This has been causing me quite a headache as can't seem to figure out a way around this. Has anyone else had similar problems like this? Is there a good work around to this problem?
Thanks in advance
Edit:
I should also add this makes saving data a problem because say I have a button that when clicked loops through each table cell and saves the data in each field, it will only loop through the table cells that are visible on screen and ignore the rest.
Upvotes: 1
Views: 1054
Reputation: 5175
It works for me, I'm using blocks which is fired when "done" button on keyboard pressed to move focus into next text fielded cell:
FRTextFieldTableViewCell *textFieldCell = [tableView_ dequeueReusableCellWithIdentifier:[FRTextFieldTableViewCell reuseIdentifier]];
if(textFieldCell == nil) {
textFieldCell = [[FRTextFieldTableViewCell alloc] initWithStyle:
UITableViewCellStyleDefault reuseIdentifier:[FRTextFieldTableViewCell reuseIdentifier]];
}
[textFieldCell.textField initialize];
textFieldCell.textField.secureTextEntry = (indexPath.row == 3);
__weak FRSignUpViewController *self_ = self;
__weak FRTextFieldTableViewCell *textFieldCell_ = textFieldCell;
if(indexPath.row == 1) {
textFieldCell.textField.placeholder = NSLocalizedString(@"name", @"");
textFieldCell.object = self.regUser.name;
textFieldCell.didChangedValueAction = ^(NSString *object) {
[self_ setName:object];
};
textFieldCell.didEndOnExitAction = ^{
[self_ setName:textFieldCell_.object];
FRTextFieldTableViewCell *nextCell = (FRTextFieldTableViewCell *)[self_.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:2 inSection:0]];
[nextCell.textField becomeFirstResponder];
};
}
if(indexPath.row == 2) {
textFieldCell.textField.placeholder = NSLocalizedString(@"email", @"");
textFieldCell.didChangedValueAction = ^(NSString *object) {
[self_ setLoginString:object];
};
textFieldCell.didEndOnExitAction = ^{
[self_ setLoginString:textFieldCell_.object];
FRTextFieldTableViewCell *nextCell = (FRTextFieldTableViewCell *)[self_.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:3 inSection:0]];
[nextCell.textField becomeFirstResponder];
};
}
if(indexPath.row == 3) {
textFieldCell.textField.placeholder = NSLocalizedString(@"password", @"");
textFieldCell.didChangedValueAction = ^(NSString *object) {
[self_ setPasswordString:object];
};
textFieldCell.didEndOnExitAction = ^{
[self_ setPasswordString:textFieldCell_.object];
[self_ signUp];
};
}
[textFieldCell reloadData];
return textFieldCell;
BlocksTypedefs:
/* type defenition for blocks, can be used by any app class */
typedef void (^CompletionBlock)(id, NSError *);
typedef void (^SimpleBlock)(void);
typedef void (^InfoBlock)(id);
typedef void (^ConfirmationBlock)(BOOL);
TableViewCell code:
.h file:
#import "FRTableViewCell.h"
#import "BlocksTypedefs.h"
#import "FRTextFieldWithPadding.h"
@interface FRTextFieldTableViewCell : FRTableViewCell <UITextFieldDelegate>
@property (nonatomic, copy) SimpleBlock didEndOnExitAction;
@property (nonatomic, copy) SimpleBlock didEndEditingAction;
@property (nonatomic, copy) InfoBlock didChangedValueAction;
@property (nonatomic, strong) IBOutlet FRTextFieldWithPadding *textField;
@end
.m:
#import "FRTextFieldTableViewCell.h"
@implementation FRTextFieldTableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
self.backgroundColor = [UIColor clearColor];
}
- (void)reloadData {
self.textField.text = self.object;
}
- (IBAction)textFieldValueDidChanged:(UITextField *)sender {
self.object = sender.text;
if (self.didChangedValueAction) {
self.didChangedValueAction(self.object);
}
}
- (IBAction)textFieldDidEndOnExit:(UITextField *)sender {
self.object = sender.text;
if (self.didEndOnExitAction) {
self.didEndOnExitAction();
}
}
#pragma mark - UITextFieldDelegate
- (void)textFieldDidEndEditing:(UITextField *)textField {
self.object = textField.text;
if (self.didEndEditingAction) {
self.didEndEditingAction();
}
}
@end
Upvotes: 1
Reputation: 1542
CGRect frame = CGRectMake(0.0, self.view.bounds.size.height, self.view.bounds.size.width, 44.0);
fieldAccessoryView = [[UIToolbar alloc] initWithFrame:frame];
fieldAccessoryView.barStyle = UIBarStyleBlackOpaque;
fieldAccessoryView.tag = 200;
[fieldAccessoryView setBarStyle:UIBarStyleBlack];
UIBarButtonItem *spaceButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done:)];
UISegmentedControl* segmentedControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:NSLocalizedString(@"Previous", @""), NSLocalizedString(@"Next", @""), nil]];
[segmentedControl addTarget:self action:@selector(segmentAction:) forControlEvents:UIControlEventValueChanged];
segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
[segmentedControl setMomentary:YES];
UIBarButtonItem *segmentButton = [[UIBarButtonItem alloc] initWithCustomView:segmentedControl];
[fieldAccessoryView setItems:[NSArray arrayWithObjects:segmentButton, spaceButton, doneButton, nil] animated:NO];
[segmentButton release];
[spaceButton release];
[doneButton release];
[segmentedControl release];
Upvotes: 0