CMでよくあるあのスクラッチをiPhoneアプリで実現するにはどうするかを調べましたのでメモ
必要なフレームワークはCoreGraphicsです。
以下のヘッダをインポートしておきましょう
#import <CoreGraphics/CoreGraphics.h>
今回UIViewがもつ「drawRect」メソッドにて描画をおこなうため、
新しくUIViewを継承するクラスを作ります。
そしてメンバ変数に以下を追加しましょう
void* data;
CGContextRef context;
では、初期化関数内にて準備を行いましょう。
必要なメモリを確保します。
data = malloc(描画する幅 * 描画する高さ * 4);
※4は1x1のデータに必要なバイト数
コンテキストイメージハンドルを作成します
CGColorSpaceRef colorRef = CGColorSpaceCreateDeviceRGB();
context = CGBitmapContextCreate(data, 描画する幅, 描画する高さ
, 描画色ビット数, 1行あたりのデータサイズ, colorRef, kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(colorRef);
これでイメージ描画ハンドルの準備は終わりです。
んで、以下の関数を作ります。
- (void)drawRect:(CGRect)rect {
CGImageRef imageRef = CGBitmapContextCreateImage(context);
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextDrawImage(currentContext, rect, imageRef);
CGImageRelease(imageRef);
}
これでコンテキストに登録している画像を描画処理が終わりです。
初期準備処理完了後に以下の処理を明記しておくと、プログラム起動後図1のように起動します。
CGContextSetRGBFillColor(context, 0.5, 0.5, 0.5, 1);
CGContextFillRect(context, self.bounds);
図1

はい、のっぺりグレー一色で描画されます。
今回iPhoneの画面いっぱいにまでFillRectするように
Rectをself.bounds指定している点を参考の際注意してください。
そして、スクラッチのように画像を削るため、
UIViewのタッチイベントをオーバーライドします。
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
CGPoint p = [[touches anyObject] locationInView: self];
CGPoint q = [[touches anyObject] previousLocationInView: self];
CGContextSetLineCap(context, kCGLineCapRound);
CGContextBeginPath(context);
CGContextMoveToPoint(context, q.x, q.y);
CGContextAddLineToPoint(context, p.x, p.y);
CGContextStrokePath(context);
[self setNeedsDisplay];
}
上記処理はコンテキスト内にて鉛筆のように指でなぞった部分にラインを引く処理です。
ただそれだけなのです。
では、スクラッチのような表現にはどのように+αするのか
それは以下の設定をいれておきます。
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextSetLineWidth(context, 15);
BlendModeでクリアするようにしておき、
SetLineWidthにてライン描画の太さを指定します。
ラインの色は関係ないようです。
ブレンドモードにて強制透過するようです。
以上の処理をいれて、指で画面をなぞってみた結果が図2です。
図2

机の上にあったガムのボトルが写っているのがわかりますか?
こんな感じでスクラッチの表現ができました。ちゃんちゃん
![]() 【送料無料】iOS SDK Hacks |
すいませんが、詳しく教えていただいていいですか。
行ったサンプルをいただければ幸いです。
まずViewの登録順はどうなっていますか?
UIWondow
┗UIViewController.view
┗UIView(サンプルプログラムのView)
┗UIImageView(ボトルガムの画像)
こんな感じで行なっていますでしょうか?
登録順は、なっております。
UIViewには、新たに新規クラスを作成し、その中にプログラムを埋めこんでおります。
初期化関数内とは、viewDidLoadのことでしょうか。
すいませんが、プログラムを埋め込む場所を教えていただけないでしょうか。
宜しくお願いします。
プログラムを添付しますので、お手数ですが、間違っている箇所を教えて頂けないでしょうか。
ViewController.hに
#import <CoreGraphics/CoreGraphics.h>を追加
クラスを作成、クラスをViewController.hのクラスに登録。
・・・.hの@interfaceに下記を入力。
void* data;
CGContextRef context;
・・・.mの初期設定に
self = [super initWithFrame:frame];
if (self) {
// Initialization code
data = malloc(300 * 300 * 4);
CGColorSpaceRef colorRef = CGColorSpaceCreateDeviceRGB();
context = CGBitmapContextCreate(data, 300, 300
, 200, 30, colorRef, kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(colorRef);
CGContextSetRGBFillColor(context, 0.5, 0.5, 0.5, 1);
CGContextFillRect(context, self.bounds);
}
return self;
を追加します。
- (void)drawRect:(CGRect)rectに
CGImageRef imageRef = CGBitmapContextCreateImage(context);
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextDrawImage(currentContext, rect, imageRef);
CGImageRelease(imageRef);
を追加。
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event に
CGPoint p = [[touches anyObject] locationInView: self];
CGPoint q = [[touches anyObject] previousLocationInView: self];
CGContextSetLineCap(context, kCGLineCapRound);
CGContextBeginPath(context);
CGContextMoveToPoint(context, q.x, q.y);
CGContextAddLineToPoint(context, p.x, p.y);
CGContextStrokePath(context);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextSetLineWidth(context, 15);
CGContextSetRGBStrokeColor(context, 1, 1, 1, 0);
[self setNeedsDisplay];
を追加実行するとエラーになりました。
すいませんが、サンプルファイルがありましたら、
頂けないでしょうか。
お手数おかけいたしますが、宜しくお願いいたします。
この時のサンプルプロジェクトが紛失してしまったので、もう一度作りなおさないと検証ができない状態になってしまいました。
週末などにXCodeを使うことができれば、検証してみますね。
みたところ、コードに問題はなさそうですが
エラーというのは実行時にエラーで落ちるのでしょうか?
<Error>: CGBitmapContextCreateImage: invalid context 0x0
と表示されます。
画面をスライドさせると
<Error>: CGContextSetLineCap: invalid context 0x0
<Error>: CGContextBeginPath: invalid context 0x0
<Error>: CGContextMoveToPoint: invalid context 0x0
とtouchesMovedで宣言したのが
エラーになってしまいました。
CGBitmapContextCreateImageが間違えているんでしょうか。
他に設定する部分があるのでしょうか。
すいませんが、宜しくお願いいたします。
http://hiiro-game.seesaa.net/article/200815366.html
こちらの記事にサンプルビューのソースをアップしています。
とりあえずシミュレーターで動作確認をしています。
allocしてinitWithFrameしてaddSubviewしてみてください。
画面サイズ分でグレー色表示し、指でなぞるとなぞった部分が透明になって下のビューが表示されます。