UIButtonを動的に作る

iPhoneアプリを作りたいなーと思って、少し前から図書館で本を借りたりしながら勉強しているのだけど、どうもInterfaceBuilderの使い方がよく分からなくて挫折してしまう。というか図書館で借りてきた本のキャプチャ画像と実際の画面が違ってたりすると、自分でもびっくりするくらい簡単に混乱して諦めてしまってた。

そこで、とりあえずInterfaceBuilderを使うのはやめて、UI周りもコードでごりごり書こうかと思った。そうすることで、iPhoneアプリに必要な部分がコードとして可視化されて理解も深まるだろうと、ついでにInterfaceBuilderが何をしているのかが分かるようになるかなと。

とりあえず、今日はボタンを動的に作ってみたのでメモ。


とりあえず生成、UIButton の buttonWithType: でインスタンスを生成してその後でそれぞれのプロパティを設定する。

+ (id)buttonWithType:(UIButtonType)buttonType


UIButtonTypeは以下のものを指定できる。

UIButtonTypeCustom 画像ボタン
UIButtonTypeRoundedRect 普通のボタン
UIButtonTypeDetailDisclosure (>)ボタン
UIButtonTypeInfoLight (i)白ボタン
UIButtonTypeInfoDark (i)黒ボタン
UIButtonTypeContactAdd (+)ボタン


UIView から継承されている tag プロパティには数字をセットできて、同じようなボタンを大量に作ったときにどのボタンかを識別するのに使える。


簡単な生成コードは以下

UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = frame; // CGRect: UIViewのインスタンスメソッド
button.tag   = tag;   // NSInteger: UIViewのインスタンスメソッド
[button setTitle:title forState:UIControlStateNormal]; // UIButtonのインスタンスメソッド

[view addSubview:button]; // viewはボタンを貼付けるUIViewのインスタンス


ボタンなんで押したときに何か反応してほしい、それには UIControl の addTarget:action:forControlEvents を使う。

- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents


UIControlEventsは以下のように定義されている。動作の詳細はよく分からないけど、だいたい名前で判断できる。あと、ビットシフトで定義されているので複数のイベントをまとめて登録するとかもできそう。

enum {
   UIControlEventTouchDown           = 1 <<  0,
   UIControlEventTouchDownRepeat     = 1 <<  1,
   UIControlEventTouchDragInside     = 1 <<  2,
   UIControlEventTouchDragOutside    = 1 <<  3,
   UIControlEventTouchDragEnter      = 1 <<  4,
   UIControlEventTouchDragExit       = 1 <<  5,
   UIControlEventTouchUpInside       = 1 <<  6,
   UIControlEventTouchUpOutside      = 1 <<  7,
   UIControlEventTouchCancel         = 1 <<  8,
   
   UIControlEventValueChanged        = 1 << 12,
   
   UIControlEventEditingDidBegin     = 1 << 16,
   UIControlEventEditingChanged      = 1 << 17,
   UIControlEventEditingDidEnd       = 1 << 18,
   UIControlEventEditingDidEndOnExit = 1 << 19,
   
   UIControlEventAllTouchEvents      = 0x00000FFF,
   UIControlEventAllEditingEvents    = 0x000F0000,
   UIControlEventApplicationReserved = 0x0F000000,
   UIControlEventSystemReserved      = 0xF0000000,
   UIControlEventAllEvents           = 0xFFFFFFFF
};

サンプルプログラム

それらを踏まえて、ボタンを押したら数字が増える数字入力機能のみの電卓(?)プログラムを書いてみた。

#import <UIKit/UIKit.h>

#define KEY_CLEAR -1
#define KEY_BACK  -2
#define MAX_VALUE 10000000


@interface NumberController : UIViewController
{
    int num;
    UILabel *label;
}
@end


@implementation NumberController
// ボタンを押したときに呼ばれる
// どのボタンを押したかは [sender tag] で取得する
-(void)pushed_button: (id)sender
{
    if ([sender tag] == KEY_CLEAR) {
        num = 0;
    } else if ([sender tag] == KEY_BACK) {
        num /= 10;
    } else if (num < MAX_VALUE) {
        num *= 10;
        num += [sender tag];
    }
    label.text = [NSString stringWithFormat:@"%d", num];
}

-(CGRect)getFrameWithCol:(int)col row:(int)row
{
    return CGRectMake(100 * col + 15, 40 * row + 90, 90, 32);
}

-(UIButton*)createButtonWithTitle:(NSString*)title tag:(int)tag frame:(CGRect)frame
{
    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    button.frame = frame;
    button.tag   = tag;
    [button setTitle:title forState:UIControlStateNormal];
    [button addTarget:self action:@selector(pushed_button:)
            forControlEvents:UIControlEventTouchUpInside];
    return button;
}

- (void)loadView
{
    UIView *contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
    contentView.backgroundColor = [UIColor lightGrayColor];
    self.view = contentView;
    
    // ラベルの生成
    label = [[UILabel alloc] initWithFrame: CGRectMake(10, 20, 300, 55)];
    label.text = @"0";
    label.textAlignment = UITextAlignmentRight;
    label.font = [UIFont fontWithName:@"Courier" size:48.0f];
    label.textColor       = [UIColor blackColor];
    label.shadowColor     = [UIColor lightGrayColor];
    label.shadowOffset    = CGSizeMake(2.5f, 2.0f);
    label.backgroundColor = [UIColor whiteColor];
    [contentView addSubview: label];
    
    
    // 数字ボタンの生成
    for (int i = 0; i < 10; i++) {
        int n = i >= 9 ? 0 : (7 - (i / 3) * 3) + (i % 3);
        NSString *title  = [NSString stringWithFormat:@"%d", n];
        CGRect frame     = [self getFrameWithCol:(i % 3) row:(i / 3)];
        UIButton *button = [self createButtonWithTitle:title tag:n frame:frame];
        [contentView addSubview:button];
    }
    
    // Back, Clearボタンの生成
    UIButton *backButton = [self createButtonWithTitle:@"Back" tag:KEY_BACK
                                 frame:[self getFrameWithCol:1 row:3]];
    UIButton *clearButton = [self createButtonWithTitle:@"Clear" tag:KEY_CLEAR
                                  frame:[self getFrameWithCol:2 row:3]];
    [contentView addSubview:backButton];
    [contentView addSubview:clearButton];
    
    [contentView release];
}

- (void)dealloc
{
    [label release];
    [super dealloc];
}
@end


@interface TestDelegate : NSObject<UIApplicationDelegate>
@end


@implementation TestDelegate
- (void)applicationDidFinishLaunching: (UIApplication*)application
{
    UIWindow *window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
    UIViewController *vc = [[NumberController alloc] init];
    
    [window addSubview: vc.view];
    [window makeKeyAndVisible];
}

- (void)dealloc
{
    [super dealloc];
}
@end



int main(int argc, char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, @"TestDelegate");
    [pool release];
    return retVal;
}