I implemented a Periodic Table keyboard for my app, Compounds.
Don't use UIButtons.
To display your keyboard, use either:
UIViews or CALayers to display the individual keys
OR
A static PNG. It is a lot easier on memory and "zippier". (this is what I have done for my yet to come update)
You must track all touches using the parent view. (small aside added at the bottom to explain why this is so) Implement the touches methods like so:
- (void)touchesBegan: (NSSet *)touches
withEvent: (UIEvent *)event {
NSLog(@"TouchDown");
CGPoint currentLocation = [[touches anyObject] locationInView:self.view];
[self magnifyKey:[self keyAtPoint:currentLocation]];
}
-(void)touchesMoved: (NSSet *)touches
withEvent: (UIEvent *)event {
NSLog(@"TouchMoved");
CGPoint currentLocation = [[touches anyObject] locationInView:self.view];
[self magnifyKey:[self keyAtPoint:currentLocation]];
}
-(void) touchesEnded: (NSSet *)touches
withEvent: (UIEvent *)event{
NSLog(@"TouchUp");
CGPoint currentLocation = [[touches anyObject] locationInView:self.view];
int key = [self keyAtPoint:currentLocation];
[self selectKey:aKey];
}
These methods get the key and appropriately "magnify" the selected key.
I run the point against an array of CGRects to determine the key press (this is faster compared to hit testing).
- (int)keyAtPoint:(CGPoint)aPoint{
int aKey=1;
for(NSString *aRect in keys){
if(CGRectContainsPoint(CGRectFromString(aRect), aPoint)){
break;
}
aKey++;
}
if(aKey==kKeyOutOfBounds)
aKey=0;
NSLog([NSString stringWithFormat:@"%i",aKey]);
return aKey;
}
- (void)magnifyKey:(int)aKey{
if(aKey!=0) {
if(magnifiedKey==nil){
self.magnifiedKey = [[[MagnifiedKeyController alloc] initWithKey:aKey] autorelease];
[self.view addSubview:magnifiedKey.view];
}else{
[magnifiedKey setKey:aKey];
if([magnifiedKey.view superview]==nil)
[self.view addSubview: magnifiedKey.view];
}
}else{
if(magnifiedKey!=nil)
[magnifiedKey.view removeFromSuperview];
}
}
- (void)selectKey:(int)aKey{
if(magnifiedKey!=nil){
if(aKey!=0){
[magnifiedKey flash];
[self addCharacterWithKey:aKey];
}
[magnifiedKey.view performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:0.5];
}
}
There are a few methods in there for you to implement, but it is pretty straight forward. you are basically creating a view that is a magnified key. Then moving it around as the user slides their finger.
Aside:
You can't track touches with subviews because once a touch is being tracked by a view, it continues to track the touch until touchesEnded: (or touchesCancelled:) is called. This means once the letter "Q" is tracking a touch, not other key will have access to that touch, ever. Even if you are hovering over the letter "W". This is a behavior you can use to your advantage elsewhere, but in this situation you must work around it by having a "parent view" whose job it is to track touches.
(updated to fix memory leak)