Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

kingsapo

macrumors member
Original poster
Jun 10, 2010
58
4
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
 
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.
 
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!
 
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.
 
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.