So I have a UITableView where one of its rows is a UITextView.
When the user is 开发者_如何学Cwriting something to UITextView (using the keyboard) the user can scroll the tableview and select another cell. Everything works.
When the user selects another cell, a datePicker appears, and the user can select a given date. I want the user to be able to scroll the tableView the same way like when the keyboard is on the screen.
The problem here is that when I scroll with the picker, the table bounces back to the previous position (with some cells hidden by the picker).
I assume that this happens because I add the picker to the main window, as a subview... but I'm honestly not sure...
Where (and how) should I add my picker so that it "appears" where the keyboard appears?
Not sure I was clear...
Thanks a lot.
You should use inputView property of UIResponder class (also of UITextField class). Just do:
UIPickerView *picker = [[UIPickerView alloc] initWithFrame:CGRectZero];
//picker.delegate = self;
//picker.dataSource = self;
//[picker setShowsSelectionIndicator:YES];
textField.inputView = picker;
[picker release];
and UIPickerView will behave like the keyboard view.
For more details and a sample code see my article about working with pickers.
I actually did this with the UIDatePicker, created my own SlideUpDatePicker that animated up from the bottom just like the keyboard. It took me a week or two to get it all working perfectly, it was definitely not easy to get it to work in portrait and landscape and with a nav controller and its animations.
The keyboard creates a new top level window to hold its view and it posts notifications to the notification center before and after it appears and disappears so that the view controller can adjust the size of it's view to account for the keyboard. The view controller needs to handle those notifications and resize the tableview by the size of the keyboard.
My SlideUpDatePicker posted the same notifications as the keyboard so the view controller wouldn't have to be modified and could respond the same for both the keyboard and the slide up date picker.
If you use the dumpWindows() function you can see the UIWindow and UIView hierarchy with the keyboard and a table view in a navigation based app:
dumpView: <UIWindow: 0x411fd50; frame = (0 0; 320 480); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x4120af0>>
dumpView: : <UILayoutContainerView: 0x4123310; frame = (0 0; 320 480); autoresize = W+H; layer = <CALayer: 0x411f800>>
dumpView: : | <UINavigationTransitionView: 0x4123500; frame = (0 0; 320 480); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x41232e0>>
dumpView: : | : <UIViewControllerWrapperView: 0x4519d30; frame = (0 64; 320 416); autoresize = W+H; layer = <CALayer: 0x4519a40>>
dumpView: : | : | <UITableView: 0x7808000; frame = (0 0; 320 416); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x45182a0>>
dumpView: : | : | : <DeleteCell: 0x45196e0; baseClass = UITableViewCell; frame = (0 507; 320 45); opaque = NO; autoresize = W; layer = <CALayer: 0x4519a80>>
dumpView: : | : | : <TextCell: 0x4523280; baseClass = UITableViewCell; frame = (0 442; 320 45); autoresize = W; layer = <CALayer: 0x4521ed0>>
dumpView: : | : | : <DatePickerCell: 0x45224b0; baseClass = UITableViewCell; frame = (0 398; 320 44); autoresize = W; layer = <CALayer: 0x451e170>>
dumpView: : | : | : <ButtonCell: 0x4521680; baseClass = UITableViewCell; frame = (0 354; 320 44); autoresize = W; layer = <CALayer: 0x4521750>>
dumpView: : | : | : <ButtonCell: 0x45209f0; baseClass = UITableViewCell; frame = (0 310; 320 44); autoresize = W; layer = <CALayer: 0x4520ac0>>
dumpView: : | : | : <ButtonCell: 0x4520100; baseClass = UITableViewCell; frame = (0 266; 320 44); autoresize = W; layer = <CALayer: 0x45201d0>>
dumpView: : | <UINavigationBar: 0x45018b0; frame = (0 20; 320 44); clipsToBounds = YES; autoresize = W; layer = <CALayer: 0x4500fe0>>
dumpView: : | : <UINavigationItemView: 0x4522a20; frame = (100 8; 160 27); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x4526310>>
dumpView: : | : <UINavigationItemButtonView: 0x45230a0; frame = (5 7; 87 30); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x4520260>>
dumpView: <UITextEffectsWindow: 0x4537080; frame = (0 0; 320 480); opaque = NO; layer = <CALayer: 0x45371c0>>
dumpView: : <UIKeyboard: 0x4536ce0; frame = (0 264; 320 216); opaque = NO; layer = <CALayer: 0x4536f60>>
dumpView: : | <UIKeyboardImpl: 0x4175b10; frame = (0 0; 320 216); opaque = NO; layer = <CALayer: 0x4173f90>>
dumpView: : | : <UIKeyboardLayoutStar: 0x4177d90; frame = (0 0; 320 216); layer = <CALayer: 0x4177610>>
dumpView: : | : | <UIKBKeyplaneView: 0x418a6a0; frame = (0 0; 320 216); userInteractionEnabled = NO; layer = <CALayer: 0x418a750>>
dumpView: : | : | : <UIKBKeyView: 0x41748e0; frame = (1 119; 40 42); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x41545c0>>
dumpView: : | : | : <UIKBKeyView: 0x417e2d0; frame = (279 119; 40 42); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x417df10>>
dumpView: : | : | : <UIKBKeyView: 0x418a780; frame = (1 173; 78 42); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x417f990>>
dumpView: : | : | : <UIKBKeyView: 0x418adf0; frame = (81 173; 158 42); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x4180120>>
dumpView: : | : | : <UIKBKeyView: 0x418cdb0; frame = (241 173; 78 42); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x418cf20>>
Not so elegant...
Not so pro...
i did this...
CGRect frame3 = self.tableView.frame;
frame3.size.height = frame3.size.height-216;
self.tableView.frame = frame3;
and then i made my picker appear. Et voilá! ;)
As lechec points out just set the UITextField's inputView property to a UIPickerView. It is very easy to do.
This blog post goes into detail on how to do it: http://nomtek.com/tips-for-developers/working-with-pickers/ and there is a project included for download with sample code. The project opens fine in XCode 4.2 and compiles for iOS 5.
Additionally, I didn't want to put in a button for hiding it. The following code allows the user to tap anywhere in the View, outside of the UITextField and resign it as first responder, basically making it 'lose focus'. Actually the code to handle the tap gesture causes any UITextField to 'lose focus', thus hiding any inputView or keyboard.
-(void)handleViewTapGesture:(UITapGestureRecognizer *)gesture
{
[self endEditing:YES];
}
This is implemented in the ViewController. The handler is added as a gesture recognizer to the appropriate View in the View property's setter:
-(void) setLoginView:(LoginView *)loginView
{
_loginView = loginView;
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self.loginView action:@selector(handleTapGesture:)];
[tapRecognizer setDelegate:self]; // self implements the UIGestureRecognizerDelegate protocol
[self.loginView addGestureRecognizer:tapRecognizer];
}
The handler could be defined in the View as well. If you are unfamiliar with handling gestures, see Apple's docs and/or tons of samples elsewhere.
I should mention that you will need some additional code to make sure other controls get taps, you need a delegate that implements the UIGestureRecognizerDelegate protocol and this method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isKindOfClass:[UIButton class]]) // Customize appropriately.
return NO; // Don't let the custom gestureRecognizer handle the touch
return YES;
}
精彩评论