数字キーボードもどきを作ってみました。
キートップをタップすると標準キーボードのようにポップアップします。
CoreGraphicsの関数を使って全部自力で描いてます。
lakesoft/LKNumberPad - GitHub
インストール
1. GitHubからプロジェクトをダウンロードした後 Xcode 4 で開く。
2. その中から LKNumberPadView.h と LKNumberPadView.m を自分のプロジェクトへコピーして追加する。
使い方
Xib を使う場合は次の通り。
1. 表示したいビューを開き、UIView を貼りつけた後、クラスを LKNumberPadView に変更する。
推奨サイズは 横 320 x 縦 54。
2. 背景色(Background)プロパティを設定する。
これだけで表示できるようになる。
次にボタンがタップされた時の動作を記述する。
3. アウトレット delegate を設定する。※例では File's Owner に設定している
4. デリゲート LKNumberPadViewDelegate のメソッドを実装する
@protocol LKNumberPadViewDelegate
@optional
- (void)didTouchNumberPadView:(LKNumberPadView*)numberPadView touchedString:(NSString*)string;
- (void)didTouchNumberPadView:(LKNumberPadView*)numberPadView withSequentialString:(NSString*)string;
@end
- didTouchNumberPadView:touchedString:
タップされる毎に呼び出され、押された数字が文字列として1文字だけ渡される。
- didTouchNumberPadView:withSequentialString:
タップされる毎に呼び出され、押された数字が文字列として渡される。一定期間に連続してボタンがタップされた場合は連続した数字が文字列として渡される。例えば1を押した直後にすぐに4を押すと @"14" が渡ってくる。
カスタマイズ
背景色などをプロパティで設定することができる。
BOOL startWithZero
YES だと0始まりになる(一番左が0で、一番右が9)。デフォルトは NOで標準のキーボードと同じ1始まり(一番左が1で、一番右が0)。
UIColor* keyboardColor
キーボードのキートップの背景色。
デフォルトは [UIColor colorWithWhite:0.95 alpha:1.0]。
UIColor* textColor
キーボードのキートップの文字色。
デフォルトは [UIColor blackColor]。
UIColor* disabledKeyboardColor
ディゼーブル時のキーボードのキートップの背景色。
デフォルトは [UIColor colorWithWhite:0.85 alpha:1.0]。
UIColor* disabledTextColor
ディゼーブル時のキーボードのキートップの文字色
デフォルトは [UIColor lightGrayColor]。
NSTimeInterval sequenceInterval
キー入力間隔(秒)。次のキーがこの間隔内にタップされた場合、連続したキー入力とみなす。
デフォルトは 0.75秒。
NSSet* enabledSet
キートップの有効・無効を指定する。有効にしたい数字(注意:インデックスではない)を NSNumber の値として入れておく。nil の場合は全て有効になる。
view.enabledSet = [NSSet setWithObjects:
[NSNumber numberWithInt:1],
[NSNumber numberWithInt:2], nil];
ソース解説
キートップは UIBezierPath などを使い描画している。
- (void)- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect frame;
CGColorRef shadowColorRef;
UIColor* drawColor;
// (1) draw keyboard
frame = CGRectMake(0, 0,
self.bounds.size.width / LKNUMBERPADVIEW_KEYBOARD_NUM,
self.bounds.size.height);
:
}
キーが押された時のポップアップ表示には CALayer を使っている。この描画を行う為に CALayer のサブクラス LKNumberPadLayer を LKNumberPadView.m 内で定義している。
enum {
LKNumberPadViewImageLeft = 0,
LKNumberPadViewImageInner,
LKNumberPadViewImageRight,
LKNumberPadViewImageMax
};
@interface LKNumberPadLayer : CALayer {
CGImageRef keytopImages_[LKNumberPadViewImageMax];
}
@property (nonatomic, copy) NSString* character;
@property (nonatomic, assign) int imageKind;
- (CGImageRef)createKeytopImageWithKind:(int)kind;
@end
ポップアップは左はじ、右はじ、それ以外の3種類の表示が必要になる。あらかじめ3種類の画像を描画しておき、配列 keytopImages_[] に取っておく。
ポップアップの描画は CoreImage関数の CGPathAddArc() や CGPathAddCurveToPoint() を使ってベタに書いている。
- (CGImageRef)createKeytopImageWithKind:(int)kind
{
CGMutablePathRef path = CGPathCreateMutable();
CGPoint p = CGPointMake(LKNUMBERPADVIEW_PADDING_X, LKNUMBERPADVIEW_PADDING_Y);
CGPoint p1 = CGPointZero;
CGPoint p2 = CGPointZero;
p.x += LKNUMBERPADVIEW_PAN_UPPER_RADIUS;
CGPathMoveToPoint(path, NULL, p.x, p.y);
p.x += LKNUMBERPADVIEW_PAN_UPPDER_WIDTH;
CGPathAddLineToPoint(path, NULL, p.x, p.y);
p.y += LKNUMBERPADVIEW_PAN_UPPER_RADIUS;
CGPathAddArc(path, NULL,
p.x, p.y,
LKNUMBERPADVIEW_PAN_UPPER_RADIUS,
3.0*M_PI/2.0,
4.0*M_PI/2.0,
false);
:
頂点のイメージ
キーがタップされたら適切なポップアップ画像を選び CALayer 上に表示する。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSUInteger index = [self _indexWithEvent:event];
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
[self _updateWithIndex:index];
[CATransaction commit];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSUInteger index = [self _indexWithEvent:event];
if (index != self.touchedIndex) {
[self _updateWithIndex:index];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
self.touchedIndex = -1;
self.numberPadLayer.opacity = 0.0;
[self setNeedsDisplay];
}
- (void)_updateWithIndex:(NSUInteger)index
{
self.touchedIndex = index;
NSUInteger number = [self _numberWithIndex:index];
self.touchedString = [NSString stringWithFormat:@"%d", number];
:
[self setNeedsDisplay];
[self.numberPadLayer setNeedsDisplay]; // ポップアップ表示
:
}
ポップアップの描画は -[CALayer drawInContext:] 内で描画する。あらかじめ描いておいた画像を表示し、その上に数字を描画する。
- (void)drawInContext:(CGContextRef)context
{
CGColorRef shadowColorRef = [[UIColor colorWithWhite:0.1 alpha:1.0] CGColor];
CGContextSetShadowWithColor(context,
CGSizeMake(LKNUMBERPADVIEW_PAN_SHADOW_OFFSET_X,
LKNUMBERPADVIEW_PAN_SHADOW_OFFSET_Y),
LKNUMBERPADVIEW_PAN_SHADOW_BLUR,
shadowColorRef
);
CGImageRef imageRef = keytopImages_[self.imageKind];
CGRect imageFrame = CGRectMake(0, 0,
CGImageGetWidth(imageRef),
CGImageGetHeight(imageRef));
CGContextDrawImage(context, imageFrame, imageRef);
// draw text
CGContextSelectFont(context, "Helvetica Bold", 44, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetFillColorWithColor(context, [[UIColor blackColor] CGColor]);
CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0, -1.0));
shadowColorRef = [[UIColor whiteColor] CGColor];
CGContextSetShadowWithColor(context,
CGSizeMake(0.0,
1.0),
1.0,
shadowColorRef
);
CGContextShowTextAtPoint(context, 28, 55,
[self.character UTF8String],
[self.character length]);
}
ライセンス
MIT ライセンスです。商用・非商用を問わず利用可能。カスタマイズしての再配布も自由。連絡も不要(でもくれるとうれしい)。
関連情報
なし
備考
・アプリ審査の実績なし。もし使って通った方がいたら是非教えて下さい。
・ポップアップ表示の下の影の部分だけは本物同様にできなかった(本物は影のblur値が小さい)。これをやるとなるとそれなりに手間がかかるので、ここだけは手を抜いた。押した時にここは見えないし。