iOS keyboard not going down when "return" is hit

kingsapo

macrumors member
Original poster
Jun 10, 2010
56
1
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)

Code:
#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

Code:
#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

macrumors regular
Jun 3, 2009
153
0
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

macrumors member
Original poster
Jun 10, 2010
56
1
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

macrumors regular
Jun 3, 2009
153
0
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

macrumors member
Original poster
Jun 10, 2010
56
1
yes, that's actually exactly what I did, and it now works great
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.