Home News Forum Social Networking Support Us Advertise

Spanish Lesson 1 ($1.99)

aWake!Gently ($1.99)

The Bird & The Snail - Knock Knock - Deluxe ($4.99)

Match-It Trains ($0.99)

Tangled ($0.99)

iFlatter ($0.99)

The 15 puzzle ($0.99)

Tap Forms Database ($8.99)

Higher or Lower Card Game (Hi Lo) ($0.99)

Red Pixel ($0.99)

Time-Shift Radio ($0.99)

Want your application advertised here? Only $10/week!

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Tutorials

Reply
 
LinkBack Thread Tools Display Modes
Old 12-03-2008, 03:00 PM   #1 (permalink)
Member
 
Join Date: Oct 2008
Posts: 55
Rep Power: 1
keyboardcowboy is on a distinguished road
Default Adding Subviews to custimize a keyboard

****** IMPORTANT*******
Inside the code segements, some code i had was causing the code blocks to mess up and cut out code, so please not that when i write hasPrefix:@"(lessThen)UIKeyboard" the (lessThen) should be replaced by the actual symbol. so like this hasPrefix:@" ***********************

************************************************** *****
* There is a code example a few posts down that has all this code in it *
************************************************** *****

This tutorial will show an example of how to add content to a UIKeyboard by adding a custom button. The following will show you how to add a decimal button to the numeric keyboard so you can enter decimal values without having to use a full keyboard. The key idea to understand here is that although the UIKeyboard is not directly available to us through the current iPhone SDK, we can still reference an instance of the keyboard using its base class.

UIKeyboard is a subclass of UIView. This is handy because it is very easy to add content to a view using code like below:

Code:
[myView addSubview:subview];
This is how we will add a button to our keyboard, by referencing the keyboard and adding a subview.

In my program I only had one keyboard and on text area to use the keyboard, so the following code worked fine for me. This example is not robust enough to handle multiple keyboard and multiple text areas but hopefully it gives you a good idea how things work.

STEP 1: Finding the UIKeyboard

The first thing we have to do is actually get a reference to the UIKeyboard. If your application uses a keyboard, you will find that they keyboard is not actually inside the UIWindow you create in your applicationDelegate, but in a separate UIWindow that is automatically generated. Each iPhone application you create has an array of windows. The example below shows you how to reference an item in your applications array of UIWindows.

Code:
UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
The code above works fine if you know what window you want to reference. I am not 100% sure what the max number of windows an application can have is, but in general it is better to write smart code that can automatically find each window, instead of writing working code once and hoping that conditions never change. With that said lets take a look at the following code example. The code blow shows how to iterate through each window in our applications

Code:
	UIWindow* tempWindow;

	//Check each window in our application
	for(int c = 0; c < [[[UIApplication sharedApplication] windows] count]; c ++)
	{
		//Get a reference of the current window
		tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:c];
	}
So now that we are able to loop through all of our application windows, we are ready to starting looking for the UIKeyboard. As mentioned before, UIKeyboard is a subclass of UIView. This is helpful because each UIWindow has an array of its subviews. All we have to do now is loop through each subview of the current window. We can do this with a nested for loop. Below is an extended version of the code above that will show you how to iterate through all the subviews in a window.

Code:
	UIWindow* tempWindow;
	
	//Check each window in our application
	for(int c = 0; c < [[[UIApplication sharedApplication] windows] count]; c ++)
	{
		//Get a reference of the current window
		tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:c];
		
		//Get a reference of the current view 
		for(int i = 0; i < [tempWindow.subviews count]; i++)
		{

		}
	}
Now we are at the point where we can look for the view that contains the keyboard. There are a couple of ways you can check the content/type of a UIView, in my code I do this by checking the prefix of the view description. Through debugging I found out that a UIKeyboard description starts with the text "
Code:
	UIWindow* tempWindow;
	
	//Because we cant get access to the UIKeyboard throught the SDK we will just use UIView. 
	//UIKeyboard is a subclass of UIView anyways
	UIView* keyboard;
	
	//Check each window in our application
	for(int c = 0; c < [[[UIApplication sharedApplication] windows] count]; c ++)
	{
		//Get a reference of the current window
		tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:c];
		
		//Get a reference of the current view 
		for(int i = 0; i < [tempWindow.subviews count]; i++)
		{
			keyboard = [tempWindow.subviews objectAtIndex:i];
			
			if([[keyboard description] hasPrefix:@"(lessThen)UIKeyboard"] == YES)
			{
				//If we get to this point, then our UIView "keyboard" is referencing our keyboard.
			}
		}
	}
So there you have it. Using a couple simple loops, we can reference our keyboard. Next, we need to add content.

STEP 2: Adding a custom button to the keyboard.

So now that we have a UIView reference of the keyboard. Adding a custom button is actually really simple. All we need to do is add a subview to the keyboard view. Below is the code that I use in my application to add a peroid to my numeric keypad keyboard. Keep in mind that we are referencing the keyboard directly, so position 0, 0 is not the top left of your screen, rather the top left of the keyboard. Remeber that the variable keyboard is the UIView we found in step1.

Code:
	dot = [UIButton buttonWithType:UIButtonTypeCustom];
	dot.frame = CGRectMake(0, 163, 106, 53);
	[dot setImage:[UIImage imageNamed:@"period.gif"] forState:UIControlStateNormal];
	[dot setImage:[UIImage imageNamed:@"period2.gif"] forState:UIControlStateHighlighted];
	[keyboard addSubview:dot];
	[dot addTarget:self action:@selector(addDot:)  forControlEvents:UIControlEventTouchUpInside];
The code is just as simple as adding any other button. The button has 2 images, one for when its not clicked and one for when it is. When the button is pressed I want to update my textbox by appending a '.' which is show in the code below.

Code:
	gameOptions.size.text = [gameOptions.size.text stringByAppendingString:@"."];
Now this was a little bit more difficult in my case then what I showed, that is because where I add the button, and where the buttons textarea target are in 2 different classes. But there are plenty of examples of calling methods from other classes on these forums so i wont get into that. If I can figure out how I will include the 2 images I used for this button in this tutorial so that anyone who wants to use them can.

STEP 3: Where does all this code go?

So here comes the point where I tell you that I am not 100% sure that what I am about to write is the best way to do things. There are most likely better places to add buttons to your text boxes, I just did it the following way. It will work fine, but you are more then welcome/encouraged to find a better solution.

Using notifications we can easily find out when a keyboard is about to be shown and attach a method to that event. Because a keyboard cannot be show without this method being called, I figured it would be a good place to reference the keyboard. This way we dont waste any time creating a custom keyboard if the user never uses a textarea.

I put all this code into the app delegate. I figured it was a good spot because it will live as long as my application does. Below is the first thing you need to do. As mention before, I wanted to listen for the notification of when the keyboard will be shown. The following line of code shows how to do this.

Code:
 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
As seen above, i just told my application that each time the keyboard is shown, I want to call the method keyboardWillShow. This method is where all the code from step 1 and 2 is held. As mentioned this method sits inside of my app delegate. The follow code is what my appDelegate looks like. As you can see I have a function keyboardWillShow that handles events due the the code above. Each time the keyboard is to be shown we will add our button. The way i have done things, if you do not do this each time, the button will not persist. I hope this all makes sense.

--- My post is to long, tutorial continues below ---
Attached Images
File Type: gif period.gif (5.1 KB, 334 views)
File Type: gif period2.gif (5.3 KB, 291 views)
File Type: jpg Keboard.jpg (18.6 KB, 374 views)

Last edited by keyboardcowboy; 12-18-2008 at 02:04 PM.
keyboardcowboy is offline   Reply With Quote
Old 12-03-2008, 03:01 PM   #2 (permalink)
Member
 
Join Date: Oct 2008
Posts: 55
Rep Power: 1
keyboardcowboy is on a distinguished road
Default Continued

Most of the appDelegate
Code:
@synthesize window;
@synthesize viewController;

- (void)applicationDidFinishLaunching:(UIApplication *)application {    
	
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
	window.backgroundColor = [UIColor blackColor];
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];
}

- (void)keyboardWillShow:(NSNotification *)note {
    
	//The UIWindow that contains the keyboard view
	UIWindow* tempWindow;
	
	//Because we cant get access to the UIKeyboard throught the SDK we will just use UIView. 
	//UIKeyboard is a subclass of UIView anyways
	UIView* keyboard;
	
	//Check each window in our application
	for(int c = 0; c < [[[UIApplication sharedApplication] windows] count]; c ++)
	{
		//Get a reference of the current window
		tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:c];
		
		//Get a reference of the current view 
		for(int i = 0; i < [tempWindow.subviews count]; i++)
		{
			keyboard = [tempWindow.subviews objectAtIndex:i];
			
			if([[keyboard description] hasPrefix:@"(lessThen)UIKeyboard"] == YES)
			{
				//Keyboard is now a UIView reference to the UIKeyboard we want. From here we can add a subview
				//to th keyboard like a new button
				dot = [UIButton buttonWithType:UIButtonTypeCustom];
				dot.frame = CGRectMake(0, 163, 106, 53);
				[dot setImage:[UIImage imageNamed:@"period.gif"] forState:UIControlStateNormal];
				[dot setImage:[UIImage imageNamed:@"period2.gif"] forState:UIControlStateHighlighted];
				[keyboard addSubview:dot];
				[dot addTarget:self action:@selector(addDot:)  forControlEvents:UIControlEventTouchUpInside];
				
				return;
			}
		}
	}
}
If you have any questions let me know. This is probably the only tutorial I have ever written so I understand if it was confusing. Ive also included a screen shot of the keyboard and the images for the buttons you can use to add a decimal.

Good Luck

Last edited by keyboardcowboy; 12-03-2008 at 03:03 PM.
keyboardcowboy is offline   Reply With Quote
Old 12-16-2008, 09:11 AM   #3 (permalink)
Junior Member
 
Join Date: Apr 2008
Posts: 15
Rep Power: 0
trifusion
Default

Excellent tutorial, I have been looking to do exactly this.

Any chance you could post an example project with this code?

Thanks

Greg
trifusion is offline   Reply With Quote
Old 12-16-2008, 09:15 AM   #4 (permalink)
Member
 
Join Date: Oct 2008
Posts: 55
Rep Power: 1
keyboardcowboy is on a distinguished road
Default

Good idea, I will get on that when I have some free time. possibly later tonight.
keyboardcowboy is offline   Reply With Quote
Old 12-16-2008, 09:27 AM   #5 (permalink)
Junior Member
 
Join Date: Apr 2008
Posts: 15
Rep Power: 0
trifusion
Default

Looking forward to seeing your example.

FYI: I posted a related thread here:
https://devforums.apple.com/message/18403

In case you are interested or want to post your thoughts.

Thanks

Greg
trifusion is offline   Reply With Quote
Old 12-16-2008, 05:59 PM   #6 (permalink)
Member
 
Join Date: Oct 2008
Posts: 55
Rep Power: 1
keyboardcowboy is on a distinguished road
Default Code Example

Hey all,

Attached is a quick little example project I made as per the request above.

I also included some code that moves the screen up and down as the keyboard is shown so that the textfield is never hidden.

The code is pretty much the same as the tutorial so its not super commented cause i wrote it quickly right now.

Let me know if there are any problems
Thanks
Attached Files
File Type: zip Example.zip (23.4 KB, 420 views)

Last edited by keyboardcowboy; 12-16-2008 at 06:11 PM.
keyboardcowboy is offline   Reply With Quote
Old 12-26-2008, 07:51 AM   #7 (permalink)
Twitter: fabiankr
 
Forsworn's Avatar
 
Join Date: Oct 2008
Location: Germany
Posts: 419
Rep Power: 1
Forsworn is on a distinguished road
Default

I subclassed UITextField and want to share this...
Make sure that you import the AudioToolBox framework!
And copy the sound file to your project.
The textField has to be of the type "NumberPad". Otherwise it will look weird.
This will also work with multiple textFields.

FKTextField.h:
Code:
#import 


@interface FKTextField : UITextField {
}

-(void)addDot;

@end
FKTextField.m:
Code:
#import "FKTextField.h"
#import 


@implementation FKTextField

- (void)becomeFirstResponder {
	[super becomeFirstResponder];
	[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(resignFirstResponder) name:UITextFieldTextDidEndEditingNotification object:self];
	//The UIWindow that contains the keyboard view
	UIWindow* tempWindow;
	
	//Because we cant get access to the UIKeyboard throught the SDK we will just use UIView. 
	//UIKeyboard is a subclass of UIView anyways
	UIView* keyboard;
	
	//Check each window in our application
	for(int c = 0; c < [[[UIApplication sharedApplication] windows] count]; c ++)
	{
		//Get a reference of the current window
		tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:c];
		
		//Get a reference of the current view 
		for(int i = 0; i < [tempWindow.subviews count]; i++)
		{
			keyboard = [tempWindow.subviews objectAtIndex:i];
			
			if([[keyboard description] hasPrefix:@"
It's not that much but I hope it will help someone.

edit:
Something is messed up with the second code block.
Quote me or download the files.
Attached Files
File Type: zip click_off.wav.zip (437 Bytes, 76 views)
File Type: zip FKTextField.zip (13.5 KB, 137 views)

Last edited by Forsworn; 12-26-2008 at 07:56 AM.
Forsworn is offline   Reply With Quote
Old 01-07-2009, 11:16 PM   #8 (permalink)
Junior Member
 
Join Date: Dec 2008
Posts: 3
Rep Power: 0
brygruver is on a distinguished road
Default

I wanted to delete this, but I couldn't figure out how.

Last edited by brygruver; 01-07-2009 at 11:31 PM.
brygruver is offline   Reply With Quote
Old 01-07-2009, 11:21 PM   #9 (permalink)
Junior Member
 
Join Date: Dec 2008
Posts: 3
Rep Power: 0
brygruver is on a distinguished road
Default

I wanted to delete this, but I couldn't figure out how.

Last edited by brygruver; 01-07-2009 at 11:31 PM.
brygruver is offline   Reply With Quote
Old 01-07-2009, 11:22 PM   #10 (permalink)
Junior Member
 
Join Date: Dec 2008
Posts: 3
Rep Power: 0
brygruver is on a distinguished road
Default

Quote:
Originally Posted by keyboardcowboy View Post
Hey all,

Attached is a quick little example project I made as per the request above.

I also included some code that moves the screen up and down as the keyboard is shown so that the textfield is never hidden.

The code is pretty much the same as the tutorial so its not super commented cause i wrote it quickly right now.

Let me know if there are any problems
Thanks
This was a great Example Project, but it didn't do exactly what I needed for my App. Once I figured it out, I went back an modified this project to include my own additions. I also made it a little more Interface Builder friendly.

Here is my blog entry explaining my changes:
Billabonger.net » Blog Archive » Add a Decimal to UITextField : Number Pad Keyboard

And Here is the XCode Example Project:
Attached Files
File Type: zip CustomNumberPad Example.zip (45.0 KB, 249 views)

Last edited by brygruver; 01-07-2009 at 11:31 PM.
brygruver is offline   Reply With Quote
Old 02-09-2009, 03:26 PM   #11 (permalink)
Junior Member
 
Join Date: Feb 2009
Posts: 1
Rep Power: 0
sonnybunny is on a distinguished road
Default Just a BIG thank you

brygruver you are awsome. Just wanted to say that its people like you who make the world go round - a great insight into the keyboard functionality. Many thanks!!
sonnybunny is offline   Reply With Quote
Old 02-16-2009, 08:40 AM   #12 (permalink)
Junior Member
 
Join Date: Feb 2009
Posts: 2
Rep Power: 0
nacho4d is on a distinguished road
Default Thanks A lot!!, but I have a question.

Thanks keyboardCowboy and brygruver! You're awesome.
But I have this Question.
Does any one has solved the cursor position problem?
What I mean is, suppose you write "1234567890" and then you press "." and everything goes perfect. But how about inserting "." somewhere else rather than the tail?
for example in order to write "1234567.89" you will have to delete 8 and 9 and then write "." and then write "89" again.
I know this is something it has to be with UIKeyboard, which 3rd party programmers are not allowed to play with. But maybe there is a good idea someone could have... Any thoughts?

In case of UITextView I think can calculate the actual position by a function of the tapped possition, and current font sizes. But I don't know how accurate this method can be. I case of UITextField I am not sure whether I can do it.

Any ideas?
nacho4d is offline   Reply With Quote
Old 05-02-2009, 11:10 PM   #13 (permalink)
Member
 
Join Date: Apr 2009
Posts: 89
Rep Power: 1
Austin is on a distinguished road
Default

Any one know how to make the number pad button set off an Ibaction?
Austin is offline   Reply With Quote
Old 06-02-2009, 08:11 PM   #14 (permalink)
Member
 
slahteine's Avatar
 
Join Date: Oct 2008
Location: Northampton, MA USA
Age: 42
Posts: 63
Rep Power: 1
slahteine is on a distinguished road
Default

Quote:
Originally Posted by nacho4d View Post
In case of UITextView I think can calculate the actual position by a function of the tapped position, and current font sizes. But I don't know how accurate this method can be. I case of UITextField I am not sure whether I can do it.
Normally you don't need to know the cursor position ahead of the keypress. The cursor position becomes available to you when the key is pressed. So assuming you can generate a real keypress event instead of using the method from the example, do the usual thing...

Just implement a UITextFieldDelegate and in particular the method:
Code:
textField:shouldChangeCharactersInRange:replacementString:
The range corresponds to the current cursor position and the string corresponds to the pressed key. If you want to allow the keypress at the given cursor position, return YES. If you don't like it, just return NO. If you want to substitute something in place of the pressed key, use something like
Code:
[textField setText:[ textField.text stringByReplacingCharactersInRange:range
    withString:@"Q" ] ];
and return NO.

Of course, since there's no publicly documented way to generate a "keypress" event then I guess you may still be stuck!

Oh wait, never mind... In just poking around, I see there's a handy method/property if you use a UITextView instead of a UITextField:
Code:
[myTextView selectedRange]
That may be helpful, if you can dress up the text view to look more like a text field, and add the clear button to it, and so forth.... I still don't understand why this method isn't available in a text field. It's obviously very handy.
__________________
|
| scott was here
|

Last edited by slahteine; 06-02-2009 at 08:41 PM.
slahteine is offline   Reply With Quote
Old 06-17-2009, 10:38 PM   #15 (permalink)
New Member
 
Join Date: Jun 2009
Posts: 3
Rep Power: 0
TEEKAY is on a distinguished road
Default

the period period2 and keyboard .gifs aren't working for me. are they still around?

Last edited by TEEKAY; 06-17-2009 at 10:46 PM.
TEEKAY is offline   Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is On
Trackbacks are On
Pingbacks are On
Refbacks are On


» Advertisements


» Stats
Members: 8,231
Threads: 20,199
Posts: 90,216
Top Poster: RickMaddy (2,121)
Welcome to our newest member, OneGlobe
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 02:34 PM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.2.0