Search Posts in my Blog

Wednesday 21 March 2012

Adjust Textfield hidden behind Keyboard


Every time you create a form you’re gonna probably have some UITextField in it. When you have a lot of them, it’s very commom to have the UITextField hidden behind the Keyboard. I’ve searched all over for a solution to the problem of textfields hidden behind the keyboard and found that the solution is to use a UIScrollView. It’s possible to scroll some items over the keyboard and animate them so it goes up as smooth as Apple’s own applications
You can solve the problem by implementing UIKeyboardDidShowNotificationand UIKeyboardDidHideNotification. These are the main notification events a keyboard will fire. There is also UIKeyboardWillHideNotification that can be used for our purpose.
The problem with his solution is that the field only pops when you actually start typing, not when you touch/click the UITextField. This one was kinda easy to solve, just using scrollRectToVisible, but it still put the UITextField right over the keyboard. 

Creating Base App
From XCode menu choose New Project, IPhone OS Application and finally View Base Application. Let’s name it sample-scrollview. Under Classes, there should be a file named sample_scrollviewViewController.h, open it and create three IBOutlets we’re gonna need to demonstrate this sample.
01
// sample_scrollviewViewController.h
02
@interface sample_scrollviewViewController : UIViewController {
03
    IBOutlet UIScrollView *scrollview;
04
    IBOutlet UITextField *tx1;
05
    IBOutlet UITextField *tx2;
06
}
07

08
@property(nonatomic,retain) IBOutlet UIScrollView *scrollview;
09
@property(nonatomic,retain) IBOutlet UITextField *tx1;
10
@property(nonatomic,retain) IBOutlet UITextField *tx2;
And then add the synthesize directive in the implementation file:
1
// sample_scrollviewViewController.m
2
@implementation sample_scrollviewViewController
3

4
@synthesize scrollview,tx1,tx2;
Create Interface Using Interface Builder
Next we’re gonna create the User Interface using XCode’s Interface Builder. Browse the project looking for sample_scrollviewViewController.xib inside the Resources folder.
Picture-11-150x150.png
Double-click sample_scrollviewViewController.xib to open interface builder. From the Object Library drag a Scroll View (UIScrollView) into the main view, it should resize appropriately when you drop it over the existing view. Now drag two UITextFields over theUIScrollView. Now it’s time to connect the pieces on the Interface Builder to the IBOutlets inside your viewcontroller. Now right-click the File’s Owner Icon and associate the IBOutlets. You should associate the scrollview with the UIScrollView object, and tx1 and tx2 with the respective UITextFields on the screen. Then you should drag the Referencing Outlets to the TextFields and choose the delegate. Now you may close Interface Builder as we’re not gonna need it again for now.

Implementing Notifications for Keyboard Activity
Now open up again the implementation file and let’s code what we need to receive notifications from keyboard activity. First of all let’s define some constants that we’re gonna need to determine the size of the content. It’s important to note, that if you define a content height taller than the iphone screen you’ll and up with scrolling on the screen when the keyboard is hidden. Our objective is to keep the scroll of when the keyboard is hidden. Next to the top of the implementation file, right before the import statement, let’s define the following:
1
#define SCROLLVIEW_CONTENT_HEIGHT 460
2
#define SCROLLVIEW_CONTENT_WIDTH  320
3

4
#import "sample_scrollviewViewController.h"
Then we need to implement the methods to listen to the notification of keyboard activity. But first, let’s get back to the header file and create a variable to keep state information about the visibility of the keyboard. You can put it right after the declaration of the IBOutlets.
1
IBOutlet UITextField *tx2;
2

3
BOOL keyboardVisible;

Let’s implement code to handle notifications from keyboard. These methods will allow us to receive the notifications sent from the events.
01
- (void) viewWillAppear:(BOOL)animated {
02
    [super viewWillAppear:animated];
03
    NSLog(@"Registering for keyboard events");
04

05
    // Register for the events
06
    [[NSNotificationCenter defaultCenter]
07
                addObserver:self
08
                selector:@selector (keyboardDidShow:)
09
                name: UIKeyboardDidShowNotification
10
                object:nil];
11
    [[NSNotificationCenter defaultCenter]
12
                addObserver:self
13
                selector:@selector (keyboardDidHide:)
14
                name: UIKeyboardDidHideNotification
15
                object:nil];
16

17
    // Setup content size
18
    scrollview.contentSize = CGSizeMake(SCROLLVIEW_CONTENT_WIDTH,
19
                                        SCROLLVIEW_CONTENT_HEIGHT);
20

21
    //Initially the keyboard is hidden
22
    keyboardVisible = NO;
23
}
24

25
-(void) viewWillDisappear:(BOOL)animated {
26
    NSLog (@"Unregister for keyboard events");
27
    [[NSNotificationCenter defaultCenter]
28
                removeObserver:self];
29
}
Then implement the code to handle these notifications, but first we need to create another state variable, this one, offset, will hold the distance of the content from the top of the scroll, we are gonna need it to restore the scroller to its original position. Just put it right after the keyboardVisible.
1
BOOL keyboardVisible;
2
CGPoint offset;
Now the code for the keyboardDidShow, put it in the implementation file.
01
-(void) keyboardDidShow: (NSNotification *)notif {
02
    NSLog(@"Keyboard is visible");
03
    // If keyboard is visible, return
04
    if (keyboardVisible) {
05
        NSLog(@"Keyboard is already visible. Ignore notification.");
06
        return;
07
    }
08

09
    // Get the size of the keyboard.
10
    NSDictionary* info = [notif userInfo];
11
    NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
12
    CGSize keyboardSize = [aValue CGRectValue].size;
13

14
    // Save the current location so we can restore
15
    // when keyboard is dismissed
16
    offset = scrollview.contentOffset;
17

18
    // Resize the scroll view to make room for the keyboard
19
    CGRect viewFrame = scrollview.frame;
20
    viewFrame.size.height -= keyboardSize.height;
21
    scrollview.frame = viewFrame;
22

23
    CGRect textFieldRect = [tx1 frame];
24
    textFieldRect.origin.y += 10;
25
    [scrollview scrollRectToVisible:textFieldRect animated:YES];
26

27
    NSLog(@"ao fim");
28
    // Keyboard is now visible
29
    keyboardVisible = YES;
30
}
At this point, if you run the application, you can see that the textfield you clicked (tx1) moved over the keyboard. Explaining a little bit the code above, on line 4, we check if the keyboard is already visible, it may happen if for example you click in another TextField. Later, on lines 9-12 we get the size of the keyboard. On line 16 we save the original position (offset) of the content frame, so as to restore it later when the keyboard hides. On lines 18-21 we resize the UIScrollView frame, subtracting the size of the keyboard. Lines 23-25 get the position of the first UITextField and tell the UIScrollView to scroll until it’s visible, before, on line 24 we add 10 points as a margin from the UITextField to the Keyboard. At last on line 29 we configure the keyboard state variable as visible.
Implementing the Keyboard Handling Events
01
-(void) keyboardDidHide: (NSNotification *)notif {
02
    // Is the keyboard already shown
03
    if (!keyboardVisible) {
04
        NSLog(@"Keyboard is already hidden. Ignore notification.");
05
        return;
06
    }
07

08
    // Reset the frame scroll view to its original value
09
    scrollview.frame = CGRectMake(0, 0, SCROLLVIEW_CONTENT_WIDTH, SCROLLVIEW_CONTENT_HEIGHT);
10

11
    // Reset the scrollview to previous location
12
    scrollview.contentOffset = offset;
13

14
    // Keyboard is no longer visible
15
    keyboardVisible = NO;
16

17
}
But again, if you run the code right now, you will notice that the keyboard does not close, and that you cannot see the same effect on the second UITextField. Now we’re gonna fix that. Just add another variable to hold the state of which textfield is active, put it in your header file, which at last will look like the following:
1
@interface sample_scrollviewViewController : UIViewController {
2
    IBOutlet UIScrollView *scrollview;
3
    IBOutlet UITextField *tx1;
4
    IBOutlet UITextField *tx2;
5

6
    BOOL keyboardVisible;
7
    CGPoint offset;
8
    UITextField *activeField;
9
}
Making the Keyboard Close
Now we need to implement UITextField method delegates to make the keyboard close and set the active UITextField. The first code snippet, sets the current active UITextField:
1
-(BOOL) textFieldShouldBeginEditing:(UITextField*)textField {
2
    activeField = textField;
3
    return YES;
4
}
The second one, makes the keyboard close
1
- (BOOL)textFieldShouldReturn:(UITextField *)textField
2
{
3
    [textField resignFirstResponder];
4
    return YES;
5
}
Also we need to change the implementation method of keyboardDidShow, and change the line that recover the frame of the UITextField to the following:
1
scrollview.frame = viewFrame;
2

3
CGRect textFieldRect = [activeField frame];
4
textFieldRect.origin.y += 10;
As you can see it’s very simple to achieve good results, if you want to go further, you should calculate the middle of the visible area, so as to have a broader margin from the keyboard, this will mimic even better Apple Behavior in their applications.
Download source Code HERE.

Monday 19 March 2012

NumberPad With Decimal Point


Of the various keyboards you can choose when developing iPhone apps, the number pad doesn’t come with a decimal point. There is a blank button in the bottom left corner that doesn’t do anything, so I’m going to show you how to put a decimal point button there to look like this:

Screen shot 2010-03-13 at 17.40.13 Screen shot 2010-03-13 at 17.40.19
There are a few other tutorial around that show you how to do this, but i believe mine is better….because the code is simpler to use, its more flexible, and the UI colors and button states are perfectly matched to the rest of the keyboard (unlike some of the other tutorials) The code you use to implement this will look like this:
01@interface DecimalPointNumberPadViewController : UIViewController <UITextFieldDelegate> {
02    NumberKeypadDecimalPoint *numberKeyPad;
03}
04@end
05 
06@implementation DecimalPointNumberPadViewController
07- (void) textFieldDidBeginEditing:(UITextField *)textField {
08    numberKeyPad = [[NumberKeypadDecimalPoint keypadForTextField:textField] retain];
09}
10- (void)textFieldDidEndEditing:(UITextField *)textField {
11    [numberKeyPad release];
12}
13@end
  • it works on any number of UITextFields that are displayed on your view controller.
  • It will only add one decimal point per text field.
To achieve this, here are the basic steps of what i do:
  1. Create a custom UIButton with clear background and dark grey text.
  2. For the highlighted state i change the background image of the button and the text color to be white
  3. I find the UIKeyboard in the application window and add the custom button at the required location
  4. I add a delegate to the button to listen for click events and pass the event to a handler which adds a decimal point to the current UITextField
Download Code from HERE