Elegantly replace iPhone keyboard with UIPickerView - iphone

I have a table view that has embedded UITextFields for entering some data. It also has two other fields that popup a UIPickerView and a UIDatePicker - as demonstrated in the DateCell example from Apple.
Mostly it works but I can't figure out how to cleanly transition from the text field keyboard to the other pickers - one slides out, one slides in - it looks weird and the scroll position on the table view sometimes gets screwed up - with everything scrolled off the top.
What I'd like to do is replace the text field keyboard without it animating away and without it growing the table view back to full size.
Any clues?

First, here is a screencapture showing how this looks.
Implement UITextFieldDelegate and display a "popup" containing a UIPickerView.
- (void)textFieldDidEndEditing:(UITextField *)textField {
UIPickerView *picker = [[UIPickerView alloc]
initWithFrame:CGRectMake(0, 244, 320, 270)];
picker.delegate = self;
picker.dataSource = self;
[self.view addSubview:picker];
[picker release];
}
When the keyboard disappears, a picker view is then visible.
If you want to take this a bit further, you can animate the UIPickerView "slide in" like the keyboard.
- (void)viewDidLoad {
//picker exists in the view, but is outside visible range
picker = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 480, 320, 270)];
picker.delegate = self;
picker.dataSource = self;
[self.view addSubview:picker];
[picker release];
}
//animate the picker into view
- (void)textFieldDidEndEditing:(UITextField *)textField {
[UIView beginAnimations:#"picker" context:nil];
[UIView setAnimationDuration:0.5];
picker.transform = CGAffineTransformMakeTranslation(0,-236);
[UIView commitAnimations];
}
//animate the picker out of view
- (void)textFieldDidBeginEditing:(UITextField *)textField {
[UIView beginAnimations:#"picker" context:nil];
[UIView setAnimationDuration:0.5];
picker.transform = CGAffineTransformMakeTranslation(0,236);
[UIView commitAnimations];
}
//just hide the keyboard in this example
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return NO;
}

Just set the UITextField's inputView property to a UIPickerView.

Related

UITableView resizes when adding element

I´m working on a IRC client for iPhone and I am having problems with my UITableView.
First I resized the tableview so that a toolbar and the keyboard will fit on the screen as the user is typing a message. Looking like this:
But the problem is that when the user is done typing and wants to send the message (send to stream and add to the tableview) the tableview is resized and the toolbar is put at the bottom but the keyboard remain, I do NOT which the textfield to resign first responder, I want to keep the keyboard and toolbar where its at before and after pressing the send button. Looking like this:
This is some of my code:
-Resizing the windows
// Keyboard will show
- (void)keyboardWillShow {
[UIView animateWithDuration:0.25 animations:^{
[self.tableView setFrame:CGRectMake(0, 0, 320, 177)];
}];
[UIView animateWithDuration:0.25 animations:^{
[self.toolBar setFrame:CGRectMake(0, 177, 320, 43)];
}];
}
// Keyboard will hide
- (void)keyboardWillHide {
[UIView animateWithDuration:0.25 animations:^{
[self.tableView setFrame:CGRectMake(0, 0, 320, 481)];
}];
[UIView animateWithDuration:0.25 animations:^{
[self.toolBar setFrame:CGRectMake(0, 393, 320, 43)];
}];
}
-Adding element to the tableview
// Retrieve the sender and the message from the input and add it to the data context
- (void)addMessage:(NSString *) input isSender: (BOOL) sender {
Message *messageToBeAdded = [[Message alloc] init];
[messageToBeAdded setIsSender:sender];
NSArray *arr = [input componentsSeparatedByString:[NSString stringWithFormat:#"PRIVMSG %# :",[connection channel]]];
[messageToBeAdded setMessage:[arr objectAtIndex:1]];
arr = [input componentsSeparatedByString:#"!"];
if (sender) {
[messageToBeAdded setSender:[connection nick]];
} else {
NSString *tmp = [arr objectAtIndex:0];
[messageToBeAdded setSender:[tmp substringWithRange:NSMakeRange(1, [tmp length]-1)]];
}
[_messageList addObject:messageToBeAdded];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[_messageList count]-1 inSection:0];
[self.tableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
I´ve looked everywhere and I´m certain that it has to do with the add part of the tableview. I would appreciate any help or guidance.
Thank you!
EDIT:
I have just realized that is has to do with the use of a custom cell. I created a new project and tried to simulate what I have done step-by-step. And everything worked fine up too the point where I used a custom cell with an UILabel. The UILabel was connected to the UITableViewCell class with an outlet and this is where the problem occurred.
#import <UIKit/UIKit.h>
#interface CustomCell : UITableViewCell
#property (strong, nonatomic) IBOutlet UILabel *myLabel;
#end
Any thought what could be wrong here?
I am guessing that you have a UITextField in your Toolbar. Try...
[aTextField resignFirstResponder];
... when you handle hitting the the send/return button.
The text field controls the keyboard so resignfirstresponder sends a message to the keyboard to remove itself. Does the band move to the bottom of the screen or is removed after the send button is pressed. Either way do what Michael said to do and once the keyboard disappears you will know what happens to the banner. I hope this helps!
You can use UITextFieldDelegate -
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
}
Or if you have IBOutlet of textField then in 'Keyboard will hide' call resignFirstResponder
// Keyboard will hide
- (void)keyboardWillHide {
[self.myTextField resignFirstResponder];
[UIView animateWithDuration:0.25 animations:^{
[self.tableView setFrame:CGRectMake(0, 0, 320, 481)];
}];
[UIView animateWithDuration:0.25 animations:^{
[self.toolBar setFrame:CGRectMake(0, 393, 320, 43)];
}];
}

uitableview footer

I have added a footer to the UITableView in plain style if the user clicks the textfield of last cell the tableview is not scrolling
-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection: (NSInteger)section{
UIView *view =[[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
[view setBackgroundColor:[UIColor blackColor]];
return view;
}
if it is a sectioned table this works, please help
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
if(textField == yourTextField){ /// here write name of your Textfield in which you want to scroll tableview
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
yourTableView.frame = CGRectMake(yourTableView.frame.origin.x, -160, yourTableView.frame.size.width, tblContactUS.frame.size.height);
[UIView commitAnimations];
}
return YES;
}
and put your TableView with previous frame then use bellow method
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
if(textField == yourTextField){ /// here write name of your Textfield in which you want to scroll down tableview
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
yourTableView.frame = CGRectMake(yourTableView.frame.origin.x, 0, yourTableView.frame.size.width, tblContactUS.frame.size.height);
[UIView commitAnimations];
}
return YES;
}
i hope this help you...

How to make a Subview pop-up from an action in UITableviewController

I would like to pop-up a subview pop-up from one of the actions performed by a button placedon a tableview controller.
I initially added a sub-view(initally hidden below the screen) and later want to animate it to
animate and pop-up.
Here is the code for the button action
-(IBAction) finalShareVerse: (id) sender
{
NSLog(#"finalShare Button");
UIView *tempView;
CGRect tmpFrame;
tempView = [[[UIView alloc] initWithFrame:CGRectMake(0, 490, 320, 90)]
autorelease];
[tempView setBackgroundColor:[UIColor blackColor]];
[tempView setAlpha:.87];
[self.view addSubview:tempView];
tmpFrame = tempView.frame;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.75];
tmpFrame.origin.y=390;
self.view.frame=tmpFrame;
[UIView commitAnimations];
}
The problem is that now the parent controller gets animated and popped down instead of
the subview to be popped up.
Is there a way to specify the animation to trigger on only the sub view.
I am new to iPhone app dev.. Please advise.
If I understand correctly, the problem is the line:
self.view.frame=tmpFrame;
You are applying the change of position to the view rather than the tmpView

TableView frame not resizing properly when pushing a new view controller and the keyboard is hiding

I must be missing something fundamental here. I have a UITableView inside of a NavigationViewController. When a table row is selected in the UITableView (using tableView:didSelectRowAtIndexPath:) I call pushViewController to display a different view controller. The new view controller appears correctly, but when I pop that view controller and return the UITableView is resized as if the keyboard was being displayed. I need to find a way to have the keyboard hide before I push the view controller so that the frame is restored correctly. If I comment out the code to push the view controller then the keyboard hides correctly and the frame resizes correctly.
The code I use to show the keyboard is as follows:
- (void) keyboardDidShowNotification:(NSNotification *)inNotification {
NSLog(#"Keyboard Show");
if (keyboardVisible) return;
// We now resize the view accordingly to accomodate the keyboard being visible
keyboardVisible = YES;
CGRect bounds = [[[inNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
bounds = [self.view convertRect:bounds fromView:nil];
CGRect tableFrame = tableViewNewEntry.frame;
tableFrame.size.height -= bounds.size.height; // subtract the keyboard height
if (self.tabBarController != nil) {
tableFrame.size.height += 48; // add the tab bar height
}
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(shrinkDidEnd:finished:contextInfo:)];
tableViewNewEntry.frame = tableFrame;
[UIView commitAnimations];
}
The keyboard is hidden using:
- (void) keyboardWillHideNotification:(NSNotification *)inNotification {
if (!keyboardVisible) return;
NSLog(#"Keyboard Hide");
keyboardVisible = FALSE;
CGRect bounds = [[[inNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
bounds = [self.view convertRect:bounds fromView:nil];
CGRect tableFrame = tableViewNewEntry.frame;
tableFrame.size.height += bounds.size.height; // add the keyboard height
if (self.tabBarController != nil) {
tableFrame.size.height -= 48; // subtract the tab bar height
}
tableViewNewEntry.frame = tableFrame;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(_shrinkDidEnd:finished:contextInfo:)];
tableViewNewEntry.frame = tableFrame;
[UIView commitAnimations];
[tableViewNewEntry scrollToNearestSelectedRowAtScrollPosition:UITableViewScrollPositionMiddle animated:YES];
NSLog(#"Keyboard Hide Finished");
}
I trigger the keyboard being hidden by resigning first responser for any control that is the first responder in ViewWillDisappear. I have added NSLog statements and see things happening in the log file as follows:
Show Keyboard
ViewWillDisappear: Hiding Keyboard
Hide Keyboard
Keyboard Hide Finished
PushViewController (an NSLog entry at the point I push the new view controller)
From this trace, I can see things happening in the right order, but It seems like when the view controller is pushed that the keyboard hide code does not execute properly.
Any ideas would be really appreciated. I have been banging my head against the keyboard for a while trying to find out what I am doing wrong.
-- Added didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
switch (indexPath.section) {
case 0: // Required Info
// removed to simplify
case 1: // Optional Info
switch (indexPath.row) {
case 0:
[self showTextDetailPicker: #"Enter a description"
tag: tDescriptionPicker
sourceTarget: self.newRecord
fieldSource: #selector(description)];
break;
default:
break;
}
break;
default:
break;
}
}
- (void) showTextDetailPicker: (NSString*) titleText tag:(int)tagID sourceTarget:(NSObject*)target fieldSource:(SEL)selector{
FieldEditorViewController *fe = [[FieldEditorViewController alloc] init];
fe.titleText = titleText;
fe.fieldText = [target performSelector: selector];
fe.tag = tagID;
// Replace default back button with one that just says 'Back'
UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc]
initWithTitle:#"Back"
style:UIButtonTypeInfoLight
target:nil action:nil];
[[self navigationItem] setBackBarButtonItem: newBackButton];
[newBackButton release];
[fe setDelegate: self];
[self.navigationController pushViewController:fe animated:YES];
[fe release];
}
Right before you push your view controller, find the first responder and call resign. Use the category from this SO post to see how to find the first responder recursively (not sure if you're already doing this).
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIView *fp = [[self view] findFirstResponder];
[fp resignFirstResponder];
// Push new view controller here.
NextViewController *controller = [[NextViewController alloc] init];
[[self navigationController] pushViewController:controller animated:YES];
[controller release], controller = nil;
}
The other thing to keep in mind is that your table view is getting resized automatically because your root view controller is derived from UITableViewController (or so it seems). If you make your root view controller a regular UIViewController that contains a UITableView, you can manipulate the frame of the table view manually more easily--at least that's been my experience.

iPhone: Animating a view when another view appears/disappears

I have the following view hierarchy
UITabBarController
- UINavigationController
- UITableViewController
When the table view appears (animated) I create a toolbar and add it as subview of the TabBar at the bottom of the page
and let it animate in with the table view. Same procedure in other direction, when the table view disappears.
It does not work as expected.
The animation duration is OK, but somehow not exact the same as the animation of the table view when it becomes visible
When I display the table view for the second time, the toolbar does not disappear at all and remains at the bottom of the
parent view.
What's wrong with it?
- (void)animationDone:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{
UIView *toolBar = [[[self tabBarController] view] viewWithTag:1000];
[toolBar removeFromSuperview];
}
- (void)viewWillAppear:(BOOL)animated
{
UIEdgeInsets insets = UIEdgeInsetsMake(0, 0, 44, 0);
[[self tableView] setContentInset:insets];
[[self tableView] setScrollIndicatorInsets:insets];
// Toolbar initially placed outside of the visible frame (x=320)
UIView *toolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(320, 480-44, 320, 44)];
[toolBar setTag:1000];
[[[self tabBarController] view] addSubview:toolBar];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.35];
[toolBar setFrame:CGRectMake(0, 480-44, 320, 44)];
[UIView commitAnimations];
[toolBar release];
[super viewWillAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
UIView *toolBar = [[[self tabBarController] view] viewWithTag:1000];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.35];
[UIView setAnimationDidStopSelector:#selector(animationDone:finished:context:)];
[toolBar setFrame:CGRectMake(320, 480-44, 320, 44)];
[UIView commitAnimations];
[super viewWillDisappear:animated];
}
Have you tried just using the table view controller's toolbarItems property? UINavigationController will manage a toolbar for you, updating it with the toolbar items of its current topmost view controller; use the -setToolbarHidden:animated: method in your -viewWillAppear: and -viewWillDisappear: to control the visibility of that toolbar.