数字キーボードビュー(ライブラリ)を公開

2011年8月1日月曜日 | Published in | 4 コメント

このエントリーをはてなブックマークに追加

数字キーボードもどきを作ってみました。

キートップをタップすると標準キーボードのようにポップアップします。
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値が小さい)。これをやるとなるとそれなりに手間がかかるので、ここだけは手を抜いた。押した時にここは見えないし。




Responses

  1. 匿名
    2011年11月20日 22:08

    キーボードをスライドするとスライド後の文字になるように出来ませんか?
    今のままだとスライドするだけでスライドしてる文字がズラズラ出てしまうので
    このまま使えないと思います。
    iOS5で動作確認。

  2. 匿名
    2011年11月20日 22:08

    キーボードをスライドするとスライド後の文字になるように出来ませんか?
    今のままだとスライドするだけでスライドしてる文字がズラズラ出てしまうので
    このまま使えないと思います。
    iOS5で動作確認。

  3. xcatsan says:
    2011年11月22日 12:14

    こんにちは。コメントどうも。

    「スライド後の文字になる」とは指を動かしている間はデリゲートは呼び出されず、指を止めた時に呼び出すようなイメージでしょうか?

    では。

  4. xcatsan says:
    2011年11月22日 12:14

    こんにちは。コメントどうも。

    「スライド後の文字になる」とは指を動かしている間はデリゲートは呼び出されず、指を止めた時に呼び出すようなイメージでしょうか?

    では。

  5. 匿名
    2011年11月24日 13:21

    そうですね。
    標準のキーボードだとスライドしている間の文字は入力されませんが
    このライブラリだとスライドするだけでも文字が入力出来てしまうので…
    その辺りが使用するのに不便に感じました。

  6. 匿名
    2011年11月24日 13:21

    そうですね。
    標準のキーボードだとスライドしている間の文字は入力されませんが
    このライブラリだとスライドするだけでも文字が入力出来てしまうので…
    その辺りが使用するのに不便に感じました。

  7. xcatsan says:
    2011年11月24日 13:28

    こんにちは。
    了解です。これは対応します。

    - - - -
    元々先頭に数字の付いたデータをインクリメンタルに検索する時に使うつもりで作成したので今の仕様になっています。これを使ってパラパラっとテーブルビュー上のレコードを流し読みできるようなUIを作りました。

    ただ指摘の通り標準キーボードはそういう動作ではないですね。
    検索ではなく、数字の入力という用途としては最後の文字だけを読み取る方が普通だと思いますので対応することにします。

    指摘ありがとうございました。
    では。

  8. xcatsan says:
    2011年11月24日 13:28

    こんにちは。
    了解です。これは対応します。

    - - - -
    元々先頭に数字の付いたデータをインクリメンタルに検索する時に使うつもりで作成したので今の仕様になっています。これを使ってパラパラっとテーブルビュー上のレコードを流し読みできるようなUIを作りました。

    ただ指摘の通り標準キーボードはそういう動作ではないですね。
    検索ではなく、数字の入力という用途としては最後の文字だけを読み取る方が普通だと思いますので対応することにします。

    指摘ありがとうございました。
    では。

Leave a Response

人気の投稿(過去 30日間)