増刷かかりました。
買ってくれた人、どうもありがとう!
ということで、感謝を込めて、おまけシリーズ。
本ではNSTimerやUIViewのカスタム化の学習を目的(もちろんInstrumentsのProfiler機能紹介のためのサンプルでもある)として花火を打ち上げたわけだけど、UIViewだらけになるのを気にしなければ、NSTimerとか使わなくても、花火の火の玉ひとつひとつをUIViewにして、FireworkViewのサブビューにしてbeginAnimation使ってアニメーションさせることでも実現できるんですな。
![$テン*シー*シー-a4](https://stat.ameba.jp/user_images/20110426/00/xcc/f5/6e/j/o0268017311187949398.jpg?caw=800)
ただ、さすがに火の玉ひとつにUIViewひとつ、てのはUIResponderチェーンとか負荷かけすぎでしょなわけでして、そんな時のために用意されたCALayerを今回使ってみます。
CALayerっていうのは、UIViewに一個存在する表示用の層(レイヤー)なんですが
![$テン*シー*シー-a0](https://stat.ameba.jp/user_images/20110426/00/xcc/78/7d/j/o0142015811187908613.jpg?caw=800)
UIView同様にCALayer同士を入れ子にもできるんですな。
![$テン*シー*シー-a5](https://stat.ameba.jp/user_images/20110426/00/xcc/69/9f/j/o0264018211187964004.jpg?caw=800)
そのうえ矩形とか背景色も設定できたりして、まんまUIViewていうか、なんでわざわざUIViewはCALayerとか持ってるの?
てことになるんですが、どうもUIViewは画面の表示をCALayerを使ってやってるみたいで、本で書いたdrawRect:メソッドは結局CALayerに描き込んでるっぽいんですわ。
UIViewのアニメーションはCALayerによって支えられてるんじゃないかと…
画面出力用のパーツってとこでしょうか。
わざわざ出力と断ったのは、CALayerはタッチ関係のイベントを感知しないわけでして、そこらへんはUIViewが対応してるみたいっす。その点でUIResponderチェーンとか絡まなくて軽快なわけです。
ま、実際Appleのドキュメントでも、何百でもどんとこい!とか書かれてるし、期待してみようかと…
興味がわいた人は、まずはこれを見るのじゃ。日本語訳あります↓
Core Animationプログラミングガイド(PDF)
というわけで、今回のサンプルは、単に火の玉が指の場所で広がるんじゃなく
というものです。
下の図のように、入れ子になったCALayerの親側のCALayerが上に動く場合に
![$テン*シー*シー-a1](https://stat.ameba.jp/user_images/20110426/00/xcc/e0/30/j/o0359018411187899830.jpg?caw=800)
子供側のCALayerが横に動くと
![$テン*シー*シー-a2](https://stat.ameba.jp/user_images/20110426/00/xcc/16/e7/j/o0296010011187902485.jpg?caw=800)
結果的に子供側のCALayerは斜めに動くってのを利用してます。
![$テン*シー*シー-a3](https://stat.ameba.jp/user_images/20110426/00/xcc/b8/2f/j/o0150018411187904336.jpg?caw=800)
使うテンプレートプロジェクトはWindow-based Application
![$テン*シー*シー-2](https://stat.ameba.jp/user_images/20110425/11/xcc/1b/ff/j/o0440022211186497030.jpg?caw=800)
View-basedでもいいんですが、それは本でやってるので、今回はUIViewController使わないバージョンです。
いきがけの駄賃にiPad/iPhoneユニバーサルにしちゃう。
![$テン*シー*シー-3](https://stat.ameba.jp/user_images/20110425/11/xcc/64/10/j/o0433017611186499469.jpg?caw=800)
次にFireworkLayerView.m/hを追加。
File>New>New File…メニュー選んで出てくるウィンドウでCocoa TouchのObjective-C class選びます。
![テン*シー*シー-4](https://stat.ameba.jp/user_images/20110425/11/xcc/e9/bd/j/o0433021211186507642.jpg?caw=800)
で、Nextボタンで次ぎに出てくる画面でUIViewを選択。
![テン*シー*シー-5](https://stat.ameba.jp/user_images/20110425/11/xcc/27/c6/j/o0433009511186507643.jpg?caw=800)
最後の保存ダイアログでFireworkLayerViewと名前を付けておしまい。
![$テン*シー*シー-6](https://stat.ameba.jp/user_images/20110425/12/xcc/72/4f/j/o0416037111186513411.jpg?caw=800)
こんな感じ。
![$テン*シー*シー-7](https://stat.ameba.jp/user_images/20110425/12/xcc/08/17/j/o0281032511186514753.jpg?caw=800)
で、今回はCALayer使うのでフレームワークの追加が必要です。
プロジェクトアイコン選んでTARGETSのFireworkLayer、Build Phasesタブ選んで表示される画面でLinke Binary With Librariesのデスクロージャを開いて、そこにある「+」ボタン押しましょう。
![$テン*シー*シー-8](https://stat.ameba.jp/user_images/20110425/12/xcc/47/a3/j/o0462019811186517563.jpg?caw=800)
そうするとフレームワーク選択画面がでるんでQuartzCoreを選択してAddボタン。
![$テン*シー*シー-9](https://stat.ameba.jp/user_images/20110425/12/xcc/bb/bc/j/o0340047411186520986.jpg?caw=800)
検索ボックスに qu とかいれるとフィルタリングされて表示されるんで便利
用意ができたら、まずはFireworkLayerAppDelegate.h.mの変更。FireworkLayerViewを作ってwindowにaddSubviewします。背景色は当然黒。
これでFireworkLayerViewを使う準備ができたので、今度はFireworkLayerViewクラスの実装。まずはFireworkLayerView.hでlastPosを追加。
FireworkViewではstaticで用意したけど、今回はインスタンスメソッドにします。FireworkLayerView.m側はtouchesMoved:withEvent:メソッドの実装。指の動きを感知して花火打ち上げるのは同じなんだけど、今回はstarLayerてのをインスタンス化して、自分のレイヤーにaddSublayer:します。
今回の主役はこのstarLayerクラスでして、こいつはCALayerをカスタム化したクラスで、花火の核になります。でもって広がる火の玉をCALayerインスタンスとして20個作成し、自分のサブレイヤーとしてaddSublayer:します。
そこらへんをやってるのが
で、火の玉を広げるアニメーションを指定してるのが
ってことになります。
本来CALayerのpositionやbackgroundColorプロパティは、設定すると自動的にアニメーションをともなって変更してくれるんで、
で囲む必要はないんですが、アニメーションの時間を調整したい場合は、こうしないと駄目なんですな。
あと、火の玉が予定した大きさまで広がったら、自分自身を親のレイヤーから切り離すためにアニメーション完了時に処理をするようにする
も必要だったわけです。
ここで使ってる
なんかiOS 4.0からはこれでいくでー、ちゅー感じで、ばんばん使われてます。
ま、実際便利だしな。
日本語訳あります↓
Blocksプログラミングトピックス(PDF)
そんな感じで、あとは本の41ページで紹介したクイックヘルプ使って、調べてみてね~。
![$テン*シー*シー-x](https://stat.ameba.jp/user_images/20110426/01/xcc/35/a3/j/o0580076011188005080.jpg?caw=800)
iPadでも動くお
------------
サンプルプロジェクト:FireworkLayer.zip
買ってくれた人、どうもありがとう!
ということで、感謝を込めて、おまけシリーズ。
本ではNSTimerやUIViewのカスタム化の学習を目的(もちろんInstrumentsのProfiler機能紹介のためのサンプルでもある)として花火を打ち上げたわけだけど、UIViewだらけになるのを気にしなければ、NSTimerとか使わなくても、花火の火の玉ひとつひとつをUIViewにして、FireworkViewのサブビューにしてbeginAnimation使ってアニメーションさせることでも実現できるんですな。
![$テン*シー*シー-a4](https://stat.ameba.jp/user_images/20110426/00/xcc/f5/6e/j/o0268017311187949398.jpg?caw=800)
ただ、さすがに火の玉ひとつにUIViewひとつ、てのはUIResponderチェーンとか負荷かけすぎでしょなわけでして、そんな時のために用意されたCALayerを今回使ってみます。
CALayerっていうのは、UIViewに一個存在する表示用の層(レイヤー)なんですが
![$テン*シー*シー-a0](https://stat.ameba.jp/user_images/20110426/00/xcc/78/7d/j/o0142015811187908613.jpg?caw=800)
UIView同様にCALayer同士を入れ子にもできるんですな。
![$テン*シー*シー-a5](https://stat.ameba.jp/user_images/20110426/00/xcc/69/9f/j/o0264018211187964004.jpg?caw=800)
そのうえ矩形とか背景色も設定できたりして、まんまUIViewていうか、なんでわざわざUIViewはCALayerとか持ってるの?
てことになるんですが、どうもUIViewは画面の表示をCALayerを使ってやってるみたいで、本で書いたdrawRect:メソッドは結局CALayerに描き込んでるっぽいんですわ。
UIViewのアニメーションはCALayerによって支えられてるんじゃないかと…
画面出力用のパーツってとこでしょうか。
わざわざ出力と断ったのは、CALayerはタッチ関係のイベントを感知しないわけでして、そこらへんはUIViewが対応してるみたいっす。その点でUIResponderチェーンとか絡まなくて軽快なわけです。
ま、実際Appleのドキュメントでも、何百でもどんとこい!とか書かれてるし、期待してみようかと…
興味がわいた人は、まずはこれを見るのじゃ。日本語訳あります↓
Core Animationプログラミングガイド(PDF)
というわけで、今回のサンプルは、単に火の玉が指の場所で広がるんじゃなく
花火用のCALayerを作って、UIViewの持ってるレイヤーにaddSublayerして、打ち上げて、その中に火の玉用のCALayerをサブレイヤーとして配置して四方に分散させる
というものです。
下の図のように、入れ子になったCALayerの親側のCALayerが上に動く場合に
![$テン*シー*シー-a1](https://stat.ameba.jp/user_images/20110426/00/xcc/e0/30/j/o0359018411187899830.jpg?caw=800)
子供側のCALayerが横に動くと
![$テン*シー*シー-a2](https://stat.ameba.jp/user_images/20110426/00/xcc/16/e7/j/o0296010011187902485.jpg?caw=800)
結果的に子供側のCALayerは斜めに動くってのを利用してます。
![$テン*シー*シー-a3](https://stat.ameba.jp/user_images/20110426/00/xcc/b8/2f/j/o0150018411187904336.jpg?caw=800)
使うテンプレートプロジェクトはWindow-based Application
![$テン*シー*シー-2](https://stat.ameba.jp/user_images/20110425/11/xcc/1b/ff/j/o0440022211186497030.jpg?caw=800)
View-basedでもいいんですが、それは本でやってるので、今回はUIViewController使わないバージョンです。
いきがけの駄賃にiPad/iPhoneユニバーサルにしちゃう。
![$テン*シー*シー-3](https://stat.ameba.jp/user_images/20110425/11/xcc/64/10/j/o0433017611186499469.jpg?caw=800)
次にFireworkLayerView.m/hを追加。
File>New>New File…メニュー選んで出てくるウィンドウでCocoa TouchのObjective-C class選びます。
![テン*シー*シー-4](https://stat.ameba.jp/user_images/20110425/11/xcc/e9/bd/j/o0433021211186507642.jpg?caw=800)
で、Nextボタンで次ぎに出てくる画面でUIViewを選択。
![テン*シー*シー-5](https://stat.ameba.jp/user_images/20110425/11/xcc/27/c6/j/o0433009511186507643.jpg?caw=800)
最後の保存ダイアログでFireworkLayerViewと名前を付けておしまい。
![$テン*シー*シー-6](https://stat.ameba.jp/user_images/20110425/12/xcc/72/4f/j/o0416037111186513411.jpg?caw=800)
こんな感じ。
![$テン*シー*シー-7](https://stat.ameba.jp/user_images/20110425/12/xcc/08/17/j/o0281032511186514753.jpg?caw=800)
で、今回はCALayer使うのでフレームワークの追加が必要です。
プロジェクトアイコン選んでTARGETSのFireworkLayer、Build Phasesタブ選んで表示される画面でLinke Binary With Librariesのデスクロージャを開いて、そこにある「+」ボタン押しましょう。
![$テン*シー*シー-8](https://stat.ameba.jp/user_images/20110425/12/xcc/47/a3/j/o0462019811186517563.jpg?caw=800)
そうするとフレームワーク選択画面がでるんでQuartzCoreを選択してAddボタン。
![$テン*シー*シー-9](https://stat.ameba.jp/user_images/20110425/12/xcc/bb/bc/j/o0340047411186520986.jpg?caw=800)
検索ボックスに qu とかいれるとフィルタリングされて表示されるんで便利
用意ができたら、まずはFireworkLayerAppDelegate.h.mの変更。FireworkLayerViewを作ってwindowにaddSubviewします。背景色は当然黒。
#import "FireworkLayerAppDelegate.h"
#import "FireworkLayerView.h"
@implementation FireworkLayerAppDelegate
@synthesize window=_window;
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
FireworkLayerView* v = [[FireworkLayerView alloc]
initWithFrame:self.window.bounds];
v.backgroundColor = [UIColor blackColor];
[self.window addSubview:v];
[v release];
[self.window makeKeyAndVisible];
return YES;
}
#import "FireworkLayerView.h"
@implementation FireworkLayerAppDelegate
@synthesize window=_window;
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
FireworkLayerView* v = [[FireworkLayerView alloc]
initWithFrame:self.window.bounds];
v.backgroundColor = [UIColor blackColor];
[self.window addSubview:v];
[v release];
[self.window makeKeyAndVisible];
return YES;
}
これでFireworkLayerViewを使う準備ができたので、今度はFireworkLayerViewクラスの実装。まずはFireworkLayerView.hでlastPosを追加。
@interface FireworkLayerView : UIView {
CGPoint lastPos;
}
@end
CGPoint lastPos;
}
@end
FireworkViewではstaticで用意したけど、今回はインスタンスメソッドにします。FireworkLayerView.m側はtouchesMoved:withEvent:メソッドの実装。指の動きを感知して花火打ち上げるのは同じなんだけど、今回はstarLayerてのをインスタンス化して、自分のレイヤーにaddSublayer:します。
/**
* 10ポイント以上指の移動があれば1発、花火を打ち上げる。
*/
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint pos = [(UITouch*)[touches anyObject] locationInView:self];
float dx = pos.x - lastPos.x;
float dy = pos.y - lastPos.y;
if ((dx * dx + dy * dy) < 10*10) {
return;
}
lastPos = pos;
starLayer* star = [starLayer layer];
[star setpos:pos];
[self.layer addSublayer:star];
// 直に呼ぶとアニメーションがかからないのでこのようにする。
// ただし間をあける必要は無いので afterDelay:0 とする
[star performSelector:@selector(launch) withObject:nil afterDelay:0];
}
* 10ポイント以上指の移動があれば1発、花火を打ち上げる。
*/
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint pos = [(UITouch*)[touches anyObject] locationInView:self];
float dx = pos.x - lastPos.x;
float dy = pos.y - lastPos.y;
if ((dx * dx + dy * dy) < 10*10) {
return;
}
lastPos = pos;
starLayer* star = [starLayer layer];
[star setpos:pos];
[self.layer addSublayer:star];
// 直に呼ぶとアニメーションがかからないのでこのようにする。
// ただし間をあける必要は無いので afterDelay:0 とする
[star performSelector:@selector(launch) withObject:nil afterDelay:0];
}
今回の主役はこのstarLayerクラスでして、こいつはCALayerをカスタム化したクラスで、花火の核になります。でもって広がる火の玉をCALayerインスタンスとして20個作成し、自分のサブレイヤーとしてaddSublayer:します。
そこらへんをやってるのが
-(void)setpos:(CGPoint)pos
で、火の玉を広げるアニメーションを指定してるのが
-(void)bang
ってことになります。
本来CALayerのpositionやbackgroundColorプロパティは、設定すると自動的にアニメーションをともなって変更してくれるんで、
[CATransaction begin];
[CATransaction commit];
[CATransaction commit];
で囲む必要はないんですが、アニメーションの時間を調整したい場合は、こうしないと駄目なんですな。
あと、火の玉が予定した大きさまで広がったら、自分自身を親のレイヤーから切り離すためにアニメーション完了時に処理をするようにする
[CATransaction setCompletionBlock:^(void){
[self removeFromSuperlayer];
}];
[self removeFromSuperlayer];
}];
も必要だったわけです。
ここで使ってる
^(void){…}
てのは、AppleではBlocksと読んでる、その場限りの一時的な関数を作れる機構なんですが、説明するとややこしいんで、がんばってドキュメント読んでください。なんかiOS 4.0からはこれでいくでー、ちゅー感じで、ばんばん使われてます。
ま、実際便利だしな。
日本語訳あります↓
Blocksプログラミングトピックス(PDF)
そんな感じで、あとは本の41ページで紹介したクイックヘルプ使って、調べてみてね~。
![$テン*シー*シー-x](https://stat.ameba.jp/user_images/20110426/01/xcc/35/a3/j/o0580076011188005080.jpg?caw=800)
iPadでも動くお
------------
サンプルプロジェクト:FireworkLayer.zip