PDA

View Full Version : keyboard not going down when "return" is hit




kingsapo
Aug 4, 2010, 05:42 PM
Hey all, this is actually kind of embarrassing, but just bear with me. I am following the iPhone App Dev for dummies book, and creating their application that displays a phone number, and allows the user to type a phone number to replace the default number. Currently, I am up to the part where you get a keyboard to appear after tapping a text field, which works fine. My problem, like the title of this thread says, is when I press the "return" key, nothing happens. I followed the book exactly, and even matched my code against the sample code posted on their website. As always, any help is appreciated! (Also, sorry about the paragraphs of comments, I wrote those to myself)

#import <UIKit/UIKit.h>

@interface ReturnMeToViewController : UIViewController {

//these are the outlets, which link to the text field and label in this app. this process will not happen automatically.
//you need to create accessor methods, which allow the specific instance variable of an object to be read and updated.
//creating accessor methods is a two-step process, that begins with an @property declaration (below) which tellx Xcode that
//they are accessor methods.
IBOutlet UITextField *textField;
IBOutlet UILabel *label;

//used to determine whether the content view needs to be - or has been - scrolled
BOOL moveViewUp;

//the amount the content view needs to be scrolled
CGFloat scrollAmount;

}

//properties are used to synthesize accessor methods the way you specify (nonatomic, retain)
//nonatomic tells the compiler to return the value directly, ie the accessors can be interrupted while in use
//retain tells the compiler to create an access method that sends a retain message to any object - this keeps it from being deallocated while you are using it
@property (nonatomic, retain) UITextField *textField;
@property (nonatomic, retain) UILabel *label;

- (void)scrollTheView:(BOOL)movedUp;

@end

#import "ReturnMeToViewController.h"

@implementation ReturnMeToViewController

//though @property tells Xcode that they are accessor methods, they still have to be created.
//@synthesize does this
//this is the final step in creating these two accessor methods

//@synthesize also creates a getter and setter method for each accessor method
//this, for example, would result in textField, setTextField, label, and setLabel methods being created
//textField and label are getter methods, and setTextField and setLabel are setter methods
@synthesize textField;
@synthesize label;




/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
// Custom initialization
}
return self;
}
*/

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/


/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
}
*/

//loaded before the view is loaded
- (void)viewWillAppear:(BOOL)animated {

//this adds a notification to tell the program when the keyboard was loaded into this view.
//defaultCenter requires four things
//addObserver is the object you want to send the message to. It would either be self or ReturnMeToViewController (in this case they're the same thing)
//selector is the method within the object you want to call. In this example, we want to code the keyboardWillShow method. selector can have only one argument
//name specifies the notification you're registering for, in this case UIKeyboardWillShowNotification
//object is the particular object whose notification I am registering for, in this case, the window
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:self.view.window];

//this calls the super class's (UIViewController) method ([super viewWillAppear:animated];
//this is important because there may be some things UIViewController needs to do on its own before the view appears
[super viewWillAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated {

//this removes the notification to tell the program when the keyboard was loaded into this view.
//removeObserver is the object you want to send the message to. (just like addObserver from above)
//name specifies the notification you're unregistering for, in this case UIKeyboardWillShowNotification
//object: since I am unregistering, nil will be used for object because that will remove all UIKeyboardWillShowNotification notifications (if there were more than one)
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];

[super viewWillDisappear:animated];
}

- (void)keyboardWillShow:(NSNotification *)notif {

//send message to notification center to return a reference to the dictionary that has the information
NSDictionary* info = [notif userInfo];

//use the key to have the method extract the keyboard size for you

//NSValue is a simple container that can hold variables that hold values. In this case, it points to a CGRect
NSValue *aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];

//a CGRect is a structure that contains the location (origin) and dimensions (size) or a rectangle.
//[aValue CGRectValue] calls a method that extracts the size of the rectangle at which aValue is pointing.
//CGSize is a structure that contains width and height values
CGSize keyboardSize = [aValue CGRectValue].size;

//compute the bottomPoint
//textField.frame.origin.y tells me the top-left point of the text field. To find the bottom point, you add
//both the height of the text field and a 10-pixel margin, to make it look nice
float bottomPoint = (textField.frame.origin.y + textField.frame.size.height + 10);

//compute the amount to scroll
//subtracting the bottomPoint from the height of the content view gives the amount of content wanted to be covered by the keyboard.
//I get the height of the content view using the view controller's pointer view - the view pointer.
//the view has an instance variable, frame, which is a CGRect that has a size, just as the CGRect for keyboard did. Subtracting that
//result from the keyboard height gives me the amount to scroll
scrollAmount = keyboardSize.height - (self.view.frame.size.height - bottomPoint);

//check to see whether the view should be moved up.
//if the scroll amount is greater than zero, I set moveViewUp to YES. This will be used by the methods called when the user is done editing the text
//field to see whether the content view has been scrolled and needs to be restored. If not, set to NO. Finally, I call scrollTheView:YES to move the view up
//of course, if the scroll amount is not greater than zero, I set moveViewUp to NO and forget the whole thing
if (scrollAmount > 0) {
moveViewUp = YES;
[self scrollTheView:YES];
}
else {
moveViewUp = NO;
}
}

- (void)scrollTheView:(BOOL)movedUp {

//create an animation block
//to invoke a view's built-in animation behavior, you create an animation block and set the duration of the move
//beginAnimations has arguments to pass information to animation delegates. Since we're not using any, set them to nil and NULL.
//nil is used when there is a null pointer to an object - beginAnimations, for example
//NULL is used when there is a null pointer to anything else
[UIView beginAnimations:nil context:NULL];

//set the animation duration, 0.3 is the same as the keyboard
[UIView setAnimationDuration:0.3];

//get (access) the view's frame
CGRect rect = self.view.frame;

//if the view should be moved up, subtract the keyboard height from the frame
//the CGREct also contains the view's origin in x,y coordinates, with the upper-left part of the screen being 0,0
if (movedUp) {
rect.origin.y -= scrollAmount;
}
//if the view shouldn't be moved up, restore it by adding the keyboard height back to the origin
//if I move the content view up when the keyboard appears, then I must also restore the view to its original position when the keyboard disappears
//this code allows me to call scrollTheView with NO, which will scroll the view down
else {
rect.origin.y += scrollAmount;
}

//assign the new frame to the view
self.view.frame = rect;

//tell the view that you're all done with setting the animation parameters, and it should start the animation
[UIView commitAnimations];
}



- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}


- (void)dealloc {
[super dealloc];
//you need to release stuff your not using for good memory management
[textField release];
[label release];
}

-(BOOL)textFieldShouldReturn:(UITextField *)theTextField {

//call [theTextField resignFirstResponder];
//this dismisses the keyboard
[theTextField resignFirstResponder];

//when the view has been scrolled up, call scrollTheView, with the argument of NO, to restore the view to its original position
//moveViewUp lets the textFieldShouldReturn method know that the view has been scrolled and it needs to be restored
if (moveViewUp) [self scrollTheView:NO];

//this tells the text field to implement its default behavior for the return key
return YES;
}

@end



namanhams
Aug 4, 2010, 09:27 PM
Hi,

I assume that you use a UITextField to type text. The UITextField has a delegate, which is UITextFieldDelegate, which has this method :

- (BOOL)textFieldShouldReturn:(UITextField *)textField

First, you need to set the UITextField's delegate to some object. And then in that object's implementation, you put :

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}

Normally, i just set the UITestField's delegate to the current UIViewController. And in the UIViewController implementation, i put the above method.

Hope that helps.

kingsapo
Aug 5, 2010, 12:48 AM
hey, thanks for the response. I found out I did have to set the text field's delegate to the file's owner, and also add <UITextFieldDelegate> to the interface file. I'm pretty sure that's kind of what you said to do, if so then thanks, if not, then still thanks!

namanhams
Aug 5, 2010, 12:51 AM
Have you linked the UITextField to the File Owner in Interface Builder ? If not then UITextField is still nil, and since Objective-C allows method call on nil object, you'll not get any error but also nothing happens.

kingsapo
Aug 5, 2010, 12:53 AM
yes, that's actually exactly what I did, and it now works great