Scrolling to hidden table view cells

I’m currently using BSKeyboardControls to add that fancy Next/Previous/Done buttons to the top of the keyboard on the iPad. I have noticed, however, that while scrolling through the fields in a UITableView, the cursor would sometimes disappear and the keyboard would be detached (typing does nothing).

I threw some logging together and make a discovery – scrolling to a UITableViewCell far off the screen that is UIView.hidden == YES doesn’t allow subviews to receive the becomeFirstResponder message.

- (void)keyboardControls:(BSKeyboardControls *)keyboardControls selectedField:(UIView *)field inDirection:(BSKeyboardControlsDirection)direction
{
AppointmentDetailEditCell *cell = (AppointmentDetailEditCell *)keyboardControls.activeField.superview.superview;
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:cell.center];
NSLog(@"Scroll to: %@ for cell: %@ and field: %@", indexPath, cell, field);
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
}
view raw gistfile1.m hosted with ❤ by GitHub

And the logs:

2013-03-06 09:27:40.748 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0xcab9230> 2 indexes [1, 0] for cell: <AppointmentDetailEditCell: 0xc90d050; baseClass = UITableViewCell; frame = (0 140; 512 46); text = 'Name'; autoresize = W; layer = <CALayer: 0xc90d1b0>> and field: <UITextField: 0xc90cba0; frame = (266 12; 183 19); text = 'Santa-Maria'; clipsToBounds = YES; opaque = NO; autoresize = LM+W; tag = 1; gestureRecognizers = <NSArray: 0xc915090>; layer = <CALayer: 0xc90ccf0>>
2013-03-06 09:27:41.130 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0x12bc09e0> 2 indexes [3, 0] for cell: <AppointmentDetailEditCell: 0xc9215f0; baseClass = UITableViewCell; frame = (0 351; 512 45); text = 'Address 1'; autoresize = W; layer = <CALayer: 0xc921750>> and field: <UITextField: 0xc921e80; frame = (83 12; 350 19); text = '134 cc way'; clipsToBounds = YES; opaque = NO; autoresize = W; tag = 2; gestureRecognizers = <NSArray: 0xc922410>; layer = <CALayer: 0xc921fd0>>
2013-03-06 09:27:41.525 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0xac7d260> 2 indexes [3, 1] for cell: <AppointmentDetailEditCell: 0xc922be0; baseClass = UITableViewCell; frame = (0 396; 512 44); text = 'Address 2'; autoresize = W; layer = <CALayer: 0xc922d40>> and field: <UITextField: 0xc923470; frame = (83 12; 350 19); text = ''; clipsToBounds = YES; opaque = NO; autoresize = W; tag = 3; gestureRecognizers = <NSArray: 0xc923a00>; layer = <CALayer: 0xc9235c0>>
2013-03-06 09:27:41.888 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0x12bc8f90> 2 indexes [3, 2] for cell: <AppointmentDetailEditCell: 0xc9241d0; baseClass = UITableViewCell; frame = (0 440; 512 44); text = 'City'; autoresize = W; layer = <CALayer: 0xc924330>> and field: <UITextField: 0xc924aa0; frame = (83 12; 151 19); text = 'Port washington'; clipsToBounds = YES; opaque = NO; tag = 4; gestureRecognizers = <NSArray: 0xc925030>; layer = <CALayer: 0xc924bf0>>
2013-03-06 09:27:42.145 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0xac936e0> 2 indexes [3, 3] for cell: <AppointmentDetailEditCell: 0xc925e10; baseClass = UITableViewCell; frame = (0 484; 512 44); text = 'Postal'; autoresize = W; layer = <CALayer: 0xc925f70>> and field: <UITextField: 0xc9266e0; frame = (83 12; 151 19); text = '53202'; clipsToBounds = YES; opaque = NO; tag = 6; gestureRecognizers = <NSArray: 0xc926c70>; layer = <CALayer: 0xc926830>>
2013-03-06 09:27:42.405 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0x9c6fcd0> 2 indexes [3, 4] for cell: <AppointmentDetailEditCell: 0xc927a50; baseClass = UITableViewCell; frame = (0 528; 512 44); text = 'Home'; autoresize = W; layer = <CALayer: 0xc927bb0>> and field: <UITextField: 0xc9282e0; frame = (83 12; 350 19); text = '4143332222'; clipsToBounds = YES; opaque = NO; autoresize = W; tag = 8; gestureRecognizers = <NSArray: 0xc928870>; layer = <CALayer: 0xc928430>>
2013-03-06 09:27:42.648 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0xac8ae30> 2 indexes [3, 5] for cell: <AppointmentDetailEditCell: 0xc929040; baseClass = UITableViewCell; frame = (0 572; 512 44); text = 'Mobile'; autoresize = W; layer = <CALayer: 0xc9291a0>> and field: <UITextField: 0xc9298d0; frame = (83 12; 350 19); text = ''; clipsToBounds = YES; opaque = NO; autoresize = W; tag = 9; gestureRecognizers = <NSArray: 0xc929e60>; layer = <CALayer: 0xc929a20>>
2013-03-06 09:27:42.962 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0x9c6eb90> 2 indexes [3, 6] for cell: <AppointmentDetailEditCell: 0xc92a630; baseClass = UITableViewCell; frame = (0 616; 512 44); text = 'Alt. Phone'; autoresize = W; layer = <CALayer: 0xc92a790>> and field: <UITextField: 0xc92aec0; frame = (83 12; 350 19); text = ''; clipsToBounds = YES; opaque = NO; autoresize = W; tag = 10; gestureRecognizers = <NSArray: 0xc92b450>; layer = <CALayer: 0xc92b010>>
2013-03-06 09:27:43.268 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0x12bd00c0> 2 indexes [3, 7] for cell: <AppointmentDetailEditCell: 0xc92bc20; baseClass = UITableViewCell; frame = (0 660; 512 44); text = 'Email'; autoresize = W; layer = <CALayer: 0xc92bd80>> and field: <UITextField: 0xc92c4b0; frame = (83 12; 350 19); text = ''; clipsToBounds = YES; opaque = NO; autoresize = W; tag = 11; gestureRecognizers = <NSArray: 0xc92ca40>; layer = <CALayer: 0xc92c600>>
2013-03-06 09:27:43.593 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0x9c6ecc0> 2 indexes [4, 0] for cell: <AppointmentDetailEditCell: 0xc92daa0; baseClass = UITableViewCell; frame = (0 804; 512 152); autoresize = W; layer = <CALayer: 0xc92dc00>> and field: <UITextView: 0x13bd3a00; frame = (0 0; 450 149); text = ''; clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0xc92e4c0>; layer = <CALayer: 0xc92e000>; contentOffset: {0, 0}>
2013-03-06 09:27:44.922 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0xcaba3d0> 2 indexes [3, 7] for cell: <AppointmentDetailEditCell: 0xc92bc20; baseClass = UITableViewCell; frame = (0 660; 512 44); text = 'Email'; autoresize = W; layer = <CALayer: 0xc92bd80>> and field: <UITextField: 0xc92c4b0; frame = (83 12; 350 19); text = ''; clipsToBounds = YES; opaque = NO; autoresize = W; tag = 11; gestureRecognizers = <NSArray: 0xc92ca40>; layer = <CALayer: 0xc92c600>>
2013-03-06 09:27:45.293 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0xcac44f0> 2 indexes [3, 6] for cell: <AppointmentDetailEditCell: 0xc92a630; baseClass = UITableViewCell; frame = (0 616; 512 44); text = 'Alt. Phone'; autoresize = W; layer = <CALayer: 0xc92a790>> and field: <UITextField: 0xc92aec0; frame = (83 12; 350 19); text = ''; clipsToBounds = YES; opaque = NO; autoresize = W; tag = 10; gestureRecognizers = <NSArray: 0xc92b450>; layer = <CALayer: 0xc92b010>>
2013-03-06 09:27:45.662 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0x12bcab00> 2 indexes [3, 5] for cell: <AppointmentDetailEditCell: 0xc929040; baseClass = UITableViewCell; frame = (0 572; 512 44); text = 'Mobile'; autoresize = W; layer = <CALayer: 0xc9291a0>> and field: <UITextField: 0xc9298d0; frame = (83 12; 350 19); text = ''; clipsToBounds = YES; opaque = NO; autoresize = W; tag = 9; gestureRecognizers = <NSArray: 0xc929e60>; layer = <CALayer: 0xc929a20>>
2013-03-06 09:27:46.035 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0x12bbce10> 2 indexes [3, 4] for cell: <AppointmentDetailEditCell: 0xc927a50; baseClass = UITableViewCell; frame = (0 528; 512 44); text = 'Home'; autoresize = W; layer = <CALayer: 0xc927bb0>> and field: <UITextField: 0xc9282e0; frame = (83 12; 350 19); text = '4143332222'; clipsToBounds = YES; opaque = NO; autoresize = W; tag = 8; gestureRecognizers = <NSArray: 0xc928870>; layer = <CALayer: 0xc928430>>
2013-03-06 09:27:46.408 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0x12bd3490> 2 indexes [3, 3] for cell: <AppointmentDetailEditCell: 0xc925e10; baseClass = UITableViewCell; frame = (0 484; 512 44); text = 'Postal'; autoresize = W; layer = <CALayer: 0xc925f70>> and field: <UITextField: 0xc9266e0; frame = (83 12; 151 19); text = '53202'; clipsToBounds = YES; opaque = NO; tag = 6; gestureRecognizers = <NSArray: 0xc926c70>; layer = <CALayer: 0xc926830>>
2013-03-06 09:27:46.823 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0x12bd3640> 2 indexes [3, 2] for cell: <AppointmentDetailEditCell: 0xc9241d0; baseClass = UITableViewCell; frame = (0 440; 512 44); text = 'City'; autoresize = W; layer = <CALayer: 0xc924330>> and field: <UITextField: 0xc924aa0; frame = (83 12; 151 19); text = 'Port washington'; clipsToBounds = YES; opaque = NO; tag = 4; gestureRecognizers = <NSArray: 0xc925030>; layer = <CALayer: 0xc924bf0>>
2013-03-06 09:27:47.173 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0xac96e00> 2 indexes [3, 1] for cell: <AppointmentDetailEditCell: 0xc922be0; baseClass = UITableViewCell; frame = (0 396; 512 44); text = 'Address 2'; autoresize = W; layer = <CALayer: 0xc922d40>> and field: <UITextField: 0xc923470; frame = (83 12; 350 19); text = ''; clipsToBounds = YES; opaque = NO; autoresize = W; tag = 3; gestureRecognizers = <NSArray: 0xc923a00>; layer = <CALayer: 0xc9235c0>>
2013-03-06 09:27:47.566 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0x12bd74e0> 2 indexes [3, 0] for cell: <AppointmentDetailEditCell: 0xc9215f0; baseClass = UITableViewCell; frame = (0 351; 512 45); text = 'Address 1'; autoresize = W; layer = <CALayer: 0xc921750>> and field: <UITextField: 0xc921e80; frame = (83 12; 350 19); text = '134 cc way'; clipsToBounds = YES; opaque = NO; autoresize = W; tag = 2; gestureRecognizers = <NSArray: 0xc922410>; layer = <CALayer: 0xc921fd0>>
2013-03-06 09:27:48.080 PowerPlay[11962:c07] Scroll to: <NSIndexPath 0x9c6b7a0> 2 indexes [1, 0] for cell: <AppointmentDetailEditCell: 0xc90d050; baseClass = UITableViewCell; frame = (0 140; 512 46); text = 'Name'; hidden = YES; autoresize = W; layer = <CALayer: 0xc90d1b0>> and field: <UITextField: 0xc90cba0; frame = (266 12; 183 19); text = 'Santa-Maria'; clipsToBounds = YES; opaque = NO; autoresize = LM+W; tag = 1; gestureRecognizers = <NSArray: 0xc915090>; layer = <CALayer: 0xc90ccf0>>
view raw gistfile1.txt hosted with ❤ by GitHub

The solution (the only one I could come up with) is to fire off a message to the text field after a short delay to become the first responder. This seems to solve the problem.

- (void)keyboardControls:(BSKeyboardControls *)keyboardControls selectedField:(UIView *)field inDirection:(BSKeyboardControlsDirection)direction
{
AppointmentDetailEditCell *cell = (AppointmentDetailEditCell *)keyboardControls.activeField.superview.superview;
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:cell.center];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];
double delayInSeconds = 0.2;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[field becomeFirstResponder];
});
}
view raw gistfile1.m hosted with ❤ by GitHub

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s