keyboard not going down when "return" is hit

Discussion in 'iOS Programming' started by kingsapo, Aug 4, 2010.

  1. macrumors member

    Joined:
    Jun 10, 2010
    #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
     
  2. macrumors regular

    Joined:
    Jun 3, 2009
    #2
    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.
     
  3. thread starter macrumors member

    Joined:
    Jun 10, 2010
    #3
    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!
     
  4. macrumors regular

    Joined:
    Jun 3, 2009
    #4
    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.
     
  5. thread starter macrumors member

    Joined:
    Jun 10, 2010
    #5
    yes, that's actually exactly what I did, and it now works great
     

Share This Page