UIButtonの背景色を簡単設定

UIButtonの背景色を変えるのに、一々画像作るの面倒だな〜と思ってたら、UIButtonに背景色を設定する | 404 odakoh Not Foundで、「プログラム内で画像作っちゃおう」って感じでやっていたので、自分用にアレンジしてみました。

元ネタ
・UIColor指定で背景色画像作成

変更点
・カテゴリ使ってUIButtonを拡張
・色指定を@"RRGGBB"にしたIFを追加

で、以下がその実装です。

//  UIButton+BGColor.h
@interface UIButton (BGColor)

- (void)setBackgroundColor:(UIColor *)color forState:(UIControlState)state;
- (void)setBackgroundColorString:(NSString *)colorStr forState:(UIControlState)state;

@end
//  UIButton+BGColor.m
#import "UIButton+BGColor.h"

#import <QuartzCore/QuartzCore.h>
#import "UIColor-Expanded.h"

@implementation UIButton (BGColor)

- (void)setBackgroundColor:(UIColor *)color forState:(UIControlState)state {
    CGRect buttonSize = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
    UIView *bgView = [[[UIView alloc] initWithFrame:buttonSize] autorelease];
    bgView.layer.cornerRadius = 5;
    bgView.clipsToBounds = true;
    bgView.backgroundColor = color;
    UIGraphicsBeginImageContext(self.frame.size);
    [bgView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *screenImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    [self setBackgroundImage:screenImage forState:state];
}

- (void)setBackgroundColorString:(NSString *)colorStr forState:(UIControlState)state {
    UIColor *color = [UIColor colorWithHexString:colorStr];
    [self setBackgroundColor:color forState:state];
}

@end

2つ目のメソッドが見ての通り文字列での背景色指定ですが、これいらない方は、UIColor-Expanded.hが不要です。というか、UIColor-Expanded.h取ってくるの面倒な方は省くと良いですね。
UIColor-Expanded.hによるUIColorの拡張については、以前の記事をどうぞ。もの自体はこちらで公開されています。

そして、使い方。

[button1 setBackgroundColor:[UIColor blueColor] forState:UIControlStateNormal];
[button2 setBackgroundColorString:@"ff0000" forState:UIControlStateNormal];

結果は(見なくても分かると思うけど)こんな感じになります。

ネタアプリと広告収入(iAd/AdMobその後)

ネタアプリ作って無料でリリースしたけど、なんとなくもったいないんで広告収入の雰囲気つかむのも兼ねてiAd付けて実験してみるか、って以前やったやつが、多少数字も大きくなって、まぁ参考くらいにはなるかなって思ったので、このあたりでまとめてみます。
あと、4/29のv1.2からAdMobもやってみた。

  • Adを仕掛けてるアプリ概要
    • Connectable LED-Board(無料だよ〜)
    • Wifi/bluetooth使って、複数台で表示できる電光掲示板アプリ
    • アプリの性質上、起動回数は少ない
    • 総ダウンロード数 58,000
    • 200新規ダウンロード/日
    • リリース 2010/11/9
    • iAd 2011/2/5〜
    • AdMob 2011/4/29〜

iAd全期間(2011/2/5〜2011/8/8)

  • Fill Rateは平均なので低くなっていますが、最近はもっと高いです。iAd直近10日間を参照。

iAd国別全期間(2011/2/5〜2011/8/8)

  • 日本まだ〜?

iAd直近10日間(2011/7/30〜2011/8/8)

  • 常用するアプリじゃないので、起動率が低いの丸分かり(;_;)

AdMob全期間(2011/4/29〜2011/8/8)

  • Fill Rateは高いが、想像以上に低かったePCM(T_T)
  • ありきたりの結論
    • iAdだけだとFill Rate低くて取りこぼしがあるので、AdMobか何かも併用しましょう。
    • 広告で勝負するなら、起動回数が増えるアプリにしましょう。

簡単に電光掲示板を作ってみる

『[福井]iPhoneアプリ開発勉強会』(http://atnd.org/events/16933)で話して来ました。

内容は、簡単な画像処理としてUIImageのビットマップをさわってモノクロ画像にするやり方の紹介と、簡単な電光掲示板の作成について。正直、電光掲示板の一般的な作り方とか知らないけど、まぁ、こうすればそれっぽくできますよ、という感じ。

簡単な画像処理(モノクロ画像化)はこちらの記事を参照。
【コラム】実践! iPhoneアプリ開発 (4) カメラアプリの作り方 (4) - 写真にエフェクトをかける | エンタープライズ | マイコミジャーナル
注意点としては、RGB値を参照するbitに注意すること。変な色になるなら調整しましょう。

で、ここからが本題です。

簡単な電光掲示板の仕様は次のとおり。

  • 横(480x320)レイアウトで、LEDの配置は30x20
  • 1LEDあたり、LEDのサイズは12pixelでマージンが2pixel
  • 16pixelずつメッセージ画像はスクロールする
  • メッセージ画像の上に、スクロールしないマスク画像を重ねる

メッセージ画像をUILabelで作って何も画像処理しないとこうなります。

見てのとおり、LEDの一部だけ色が付いてるのが気持ち悪いので、ここで画像処理を投入し、点灯するか消えるかはっきりさせます。

  1. UILabelからUIImageを作る
  2. 作ったUIImageを加工して、LEDの中心の色をLED全体の色にする

UILabelをtargetViewに与えるとUIImageができる

+ (UIImage *)createImage:(UIView *)targetView {
    UIGraphicsBeginImageContext(targetView.bounds.size);
    [targetView.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();  // autorelease済
    UIGraphicsEndImageContext();
    return viewImage;
}

UILabelをtargetViewに与えるとUIImageができる(上記処理)ので、そのビットマップを編集して、LEDの中心の色で(マスクで隠れる部分も含め)LEDを四角く塗りつぶす。

+ (UIImage *)createLEDImage:(UIView *)targetView {
    UIImage *image = [ImageUtil createImage:targetView];
	
    // CGImageを取得する
    CGImageRef cgImage = image.CGImage;
	
    // 画像情報を取得する
    size_t width = CGImageGetWidth(cgImage);
    size_t height = CGImageGetHeight(cgImage);
    size_t bitsPerComponent = CGImageGetBitsPerComponent(cgImage);
    size_t bitsPerPixel = CGImageGetBitsPerPixel(cgImage);
    size_t bytesPerPixel = bitsPerPixel / 8;
    size_t bytesPerRow = CGImageGetBytesPerRow(cgImage);
    CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgImage);
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(cgImage);
    bool shouldInterpolate = CGImageGetShouldInterpolate(cgImage);
    CGColorRenderingIntent intent = CGImageGetRenderingIntent(cgImage);
	
    // データプロバイダを取得する
    CGDataProviderRef dataProvider = CGImageGetDataProvider(cgImage);
	
    // ビットマップデータを取得する
    CFDataRef data = CGDataProviderCopyData(dataProvider);
    UInt8* buffer = (UInt8*)CFDataGetBytePtr(data);
	
    // ビットマップに効果を与える
    // 2 top margin, 2 bottom margin, 12 LED area, check LED center
    // check y = 8, 24, 40....
    for (int y = 8; y < height; y += 16) {
        for (int x = 8; x < width; x += 16) {
            UInt8 *checkBit = buffer + y * bytesPerRow + x * bytesPerPixel;
            // copy this color to (x-6, y-6, 12, 12)
            for (int j = y - 6; j < y + 6; j++) {
                for (int i = x - 6; i < x + 6; i++) {
                    memcpy(buffer + j * bytesPerRow + i * bytesPerPixel, checkBit, bytesPerPixel);
                }
            }
        }
    }
	
    // 効果を与えたデータを作成する
    CFDataRef effectedData = CFDataCreate(NULL, buffer, CFDataGetLength(data));
	
    // 効果を与えたデータプロバイダを作成する
    CGDataProviderRef effectedDataProvider = CGDataProviderCreateWithCFData(effectedData);
	
    // 画像を作成する
    CGImageRef effectedCgImage = CGImageCreate(
                                               width, height, 
                                               bitsPerComponent, bitsPerPixel, bytesPerRow, 
                                               colorSpace, bitmapInfo, effectedDataProvider, 
                                               NULL, shouldInterpolate, intent);

    UIImage* effectedImage = [[[UIImage alloc] initWithCGImage:effectedCgImage] autorelease];
	
    // 作成したデータを解放する
    CGImageRelease(effectedCgImage);
    CFRelease(effectedDataProvider);
    CFRelease(effectedData);
    CFRelease(data);	
	
    return effectedImage;
}

これで普通にLEDっぽい(文字の周辺部分が中心にあった場合に色が薄くなることもありますが、拘りがなければOKでしょう)

実際に動かせるプロジェクトはこちら(ImageTest.zip)に置いておきますので、ダウンロードして動かしたり、ソースを見てみてください。簡単ですよ。

ちなみに、これに通信機能や設定などを付けていったものがConnectable LED-Boardです。無料だし、気が向いたらダウンロードしてね。
#リンク先の動画が古いや・・(^^;

iAdの国が増えてる

iAdのページ見ても相変わらず国情報は更新されてない(「1月にドイツで開始されます。」のままだし)んだけど、Fill Rateから見た感じ、イタリアとスペインで始まってるみたい。
下記のデータは、Connectable LED-BoardのLast 7 Daysです。



イタリア来たっぽい

スペインも来たっぽい

日本いつくるの?(ノд-。)


eCPMが0だし、カナダ試験開始?


ここからは、一般的にiAd動いてる国。

フランス、eCPM高ぇ!
ドイツ、eCPMもっとがんばって!



iAd動いてる国々でここまで弱いと泣ける・・


実験的にiAd入れたけど、マジで実験にしかならなかった件。
ジュースも買えないよorz

iAd実験中

iAdの効果がどんなもんか実測してみたいなーと、Connectable LED-BoardにiAd組み込んでみました。

モバイル広告の世界に広がる“iAdsはだめだ”説 - TechCrunch JAPANという記事も出たので、サンプル数少なくて微妙ですが参考までに値を紹介します。データは、iAd版が動き始めた2/5から現時点までの約10日間です。

Requests Impressions Fill Rate
US 340 151 44.41%
UK 80 25 31.25%
FR 230 51 22.17%
DE 3,813 377 9.89%
JP 1,449 0 0.00%

日本は、「2011年の早い時期にiAdの配信が可能になります。」らしいので、早く早く!(今のリクエスト数だと日本来たところで全然儲かりませんがねw)

.stringsファイルが原因でエラー

.stringsファイルをテキストデータ用に使おうとしたのですが、どうやら用途が違うようで、エラーに遭遇しました(^^;
#昔は大丈夫だった

Command /Developer/Library/Xcode/Plug-ins/CoreBuildTasks.xcplugin/Contents/Resources/copystrings failed with exit code 1

.stringsファイルは、行の終端が';'で終わらないといけないようです。Localizable.stringsで使うあのフォーマットですね。
基礎的なことのような気がするのでちょっと恥ずかしい(^^;
↓ここで原因が判明。感謝感謝。
Copystrings failed with exit code 1? - iPhone Dev SDK Forum

UUIDを作る

アプリ内で作る要素に、ユニークなIDを振りたいので調べてみました。

How to create a GUID/UUID using the iPhone SDKより

+ (NSString *)GetUUID
{
  CFUUIDRef theUUID = CFUUIDCreate(NULL);
  CFStringRef string = CFUUIDCreateString(NULL, theUUID);
  CFRelease(theUUID);
  return [(NSString *)string autorelease];
}

ちなみに、CFUUIDCreateは、"Creates a Universally Unique Identifier (UUID) object."する関数。試しに10個ほど出してみた。

2010-10-29 11:02:07.508 GetUUID[912:207] 5D2094B9-D7B6-48E9-9299-9C7E8110DEC5
2010-10-29 11:02:07.510 GetUUID[912:207] FFF76ECC-6426-45D0-A3B7-274169091405
2010-10-29 11:02:07.514 GetUUID[912:207] B7CBA434-71F4-44EF-8227-28E0F267A6EC
2010-10-29 11:02:07.517 GetUUID[912:207] 2507EA18-C4EF-4E48-B0A4-2758864A5E7A
2010-10-29 11:02:07.517 GetUUID[912:207] B7C29873-88CA-4E95-9A3A-85280AE85C9A
2010-10-29 11:02:07.519 GetUUID[912:207] 2E913DAE-7B98-47E5-8FF9-AF941A06ADBA
2010-10-29 11:02:07.532 GetUUID[912:207] 0393A6B9-519B-4CA8-8767-3AA4DA2F7AE9
2010-10-29 11:02:07.534 GetUUID[912:207] 9A6B131D-02D3-440A-B2C7-5E103BCEC15B
2010-10-29 11:02:07.534 GetUUID[912:207] 13901570-6981-477A-A423-6A557E9CCB78
2010-10-29 11:02:07.535 GetUUID[912:207] 72A5892C-976C-4AAC-B165-1B28B3AE4DED

うん、ユニークだ。けど、本当にUniversallyユニークなのかなぁ。
今回はそこまでクリティカルじゃないから、調べずに信じとくけど。