Non-Fiction(Remix Version)
音楽とプログラミングと武侠ものがメイン。
不滅のブロガー
例えばこんなプログラムを考えてみる。
・定期的にニュースサイトなり、特定のブログなりを巡回して、記事の要約を持ってくる。
・そのときに、そのプログラムの”興味”の対象になっているかを、キーワード分析なり、要約機能なりを駆使してフィルターをかける。
・そうやって選んだ記事をつかって、適当に自分のエントリーを生成し、投降する。
・人の記事を引用した時には、ちゃんとトラックバックを飛ばす。
・トラックバックが来たら、そっちのブログに飛んで、内容をチェックする。
・もし、相手のブログの記事内容が、設定してある”興味”の範囲にある程度ヒットしたら、巡回ブログリストに加える。
・巡回ブログでも、”興味”の対象になる記事が減ってきたら、リストから削除する。
で、このプログラムをサーバで動作させて、適当な間隔でエントリーをアップしつづけるように設定しておく。毎日きっちりエントリーあげたりしてると、機械っぽくなるので、たまにはさぼったりして。
これだと、コメント欄が結構やっかいだな。人工無脳を置いておく、というのも手だけれど。コメントは受け付けないようにした方がいいかもしれない。
議論とかふっかけられると、一発でバレそうだけど、そこは”私はそう感じました!”で逃げさせよう(^^; もしくは、当たり障りのない話題ばっかり選ぶようにしておくとか。
……これで、自分が書いてるやつより人気が出たりしたら、やだなぁ(笑)
・定期的にニュースサイトなり、特定のブログなりを巡回して、記事の要約を持ってくる。
・そのときに、そのプログラムの”興味”の対象になっているかを、キーワード分析なり、要約機能なりを駆使してフィルターをかける。
・そうやって選んだ記事をつかって、適当に自分のエントリーを生成し、投降する。
・人の記事を引用した時には、ちゃんとトラックバックを飛ばす。
・トラックバックが来たら、そっちのブログに飛んで、内容をチェックする。
・もし、相手のブログの記事内容が、設定してある”興味”の範囲にある程度ヒットしたら、巡回ブログリストに加える。
・巡回ブログでも、”興味”の対象になる記事が減ってきたら、リストから削除する。
で、このプログラムをサーバで動作させて、適当な間隔でエントリーをアップしつづけるように設定しておく。毎日きっちりエントリーあげたりしてると、機械っぽくなるので、たまにはさぼったりして。
これだと、コメント欄が結構やっかいだな。人工無脳を置いておく、というのも手だけれど。コメントは受け付けないようにした方がいいかもしれない。
議論とかふっかけられると、一発でバレそうだけど、そこは”私はそう感じました!”で逃げさせよう(^^; もしくは、当たり障りのない話題ばっかり選ぶようにしておくとか。
……これで、自分が書いてるやつより人気が出たりしたら、やだなぁ(笑)
RubyCocoaでアニメーション:もっとRubyらしく
前にもちょっと書いたけれど、RubyCocoaのバージョンが上がって、CocoaのオブジェクトをRubyの様に使えるようになったり、RubyのオブジェクトをCocoaで使えるようにするのが簡単になったりした。
そしてこの新しいバージョンのRubyCocoaはこの間のOSアップデート(10.5.2)には含まれているそうだ。
ということで、早速使ってみた。まずは、簡単なところから。awakeFromNIbでフィルターに値を設定している箇所である。
今まではsetValueの時にはNSNumberオブジェクトに変換するために
と書いてやらなければならなかったのだが、これが
と数字の後ろに".to_ns"と書けば良くなった。こういう書き方は、数値でも何でもオブジェクトになっているRubyならではだね。
このto_nsはかなり強力で、Rubyの配列をCocoaのNSArrayに変えることもできる。だからこの後で、filterの配列をレイヤーにセットするところでも
とこのように、Rubyの配列として作ってあげて、プロパティに設定するときに最後に".to_ns"をつけて変換してやればいい。
また、これとは逆にCocoaのNSArrayやNSDisctionaryをRubyの配列やハッシュのように使うこともできる。だから、doAnimationでレイヤーを取ってくるコードは今までは、
と書いていたところ、
と書ける。またchangeContentsでアクションを登録していた場所では、
が
と書けるようになった。
これは、単純に書かなければいけないコードが少なくなったというのもあるけれど、それよりも、よく似た概念なのに、アクセスするために全然別のコードを書かなくても良くなったという方が大きい。結構こういうのってストレス溜まるんだよね。間違いも起きやすいし。
そしてこの新しいバージョンのRubyCocoaはこの間のOSアップデート(10.5.2)には含まれているそうだ。
ということで、早速使ってみた。まずは、簡単なところから。awakeFromNIbでフィルターに値を設定している箇所である。
filter = OSX::CIFilter.filterWithName_('CIBloom')
filter.setDefaults
filter.setValue_forKey_((0.0).to_ns, 'inputIntensity')
filter.setValue_forKey_((5.0).to_ns, 'inputRadius')
filter.setName_('plusFilter')
今まではsetValueの時にはNSNumberオブジェクトに変換するために
OSX::NSNumber.numberWithFloat_(0.0)と書いてやらなければならなかったのだが、これが
(0.0).to_nsと数字の後ろに".to_ns"と書けば良くなった。こういう書き方は、数値でも何でもオブジェクトになっているRubyならではだね。
このto_nsはかなり強力で、Rubyの配列をCocoaのNSArrayに変えることもできる。だからこの後で、filterの配列をレイヤーにセットするところでも
filterArray = [filter,filter2]
transitionLayer.setFilters_(filterArray.to_ns)とこのように、Rubyの配列として作ってあげて、プロパティに設定するときに最後に".to_ns"をつけて変換してやればいい。
また、これとは逆にCocoaのNSArrayやNSDisctionaryをRubyの配列やハッシュのように使うこともできる。だから、doAnimationでレイヤーを取ってくるコードは今までは、
layer = @view.layer.sublayers.objectAtIndex_(0)と書いていたところ、
layer = @view.layer.sublayers[0]と書ける。またchangeContentsでアクションを登録していた場所では、
layerActions = OSX::NSMutableDictionary.alloc.init
layerActions.setObject_forKey_(transition,'contents') が
layerActions = OSX::NSMutableDictionary.alloc.init
layerActions['contents'] = transitionと書けるようになった。
これは、単純に書かなければいけないコードが少なくなったというのもあるけれど、それよりも、よく似た概念なのに、アクセスするために全然別のコードを書かなくても良くなったという方が大きい。結構こういうのってストレス溜まるんだよね。間違いも起きやすいし。
タグ : RubyCocoa
RubyCocoa 0.13.0
リリースされていたことに今更気づいたorz
この版の改修って結構大きい。特に
•NSArray、NSDictionary が Ruby の Array、Hash のように扱えるようになった。
とか
•Ruby の値クラスを to_ns で Cocoa クラスに変換できるようになった。
とかは、NSArrayやNSDictionaryの出番が多いCoreAnimationを使うとなると重宝しそう。やっぱりこの辺のコレクションクラスはRubyの方が強力だからね。今までのコードは基本的にObjective-Cの部分を文法的にRubyに代えただけだったから、いまいちRubyCocoaでやる利点が見えない
ところがあったんだが、これで少し変わるかも。
つうか、もうちょっとRubyのことも勉強しないとダメなんだが(^^;
この版の改修って結構大きい。特に
•NSArray、NSDictionary が Ruby の Array、Hash のように扱えるようになった。
とか
•Ruby の値クラスを to_ns で Cocoa クラスに変換できるようになった。
とかは、NSArrayやNSDictionaryの出番が多いCoreAnimationを使うとなると重宝しそう。やっぱりこの辺のコレクションクラスはRubyの方が強力だからね。今までのコードは基本的にObjective-Cの部分を文法的にRubyに代えただけだったから、いまいちRubyCocoaでやる利点が見えない
ところがあったんだが、これで少し変わるかも。
つうか、もうちょっとRubyのことも勉強しないとダメなんだが(^^;
RubyCocoaでアニメーション:レイヤーの階層構造を作る
昨日うまくいかなかった移動しながらの画像の押し出し効果だが、今日提供されたOSのアップデータをかけてもそのままであった(^^; しかたがないので、なんとかうまく表示できないか、考えてみることにする。
動きをよく見ると、どうも移動途中のレイヤーの座標がうまくとれていなくて、押し出される側の画像を、レイヤーが最初にいた位置に表示してしまっているようである。
そこで、画像を表示してるレイヤーの親レイヤーを作って、移動のアニメーションはそちらで行なうようにする。そうすると、画像を切り替えている方のレイヤーは全く動いていないことになるので、表示する位置がずれるということはなくなるはずだ。図で表わすと、こんな感じになる。

では、コードを書いて行こう。まず、awakeFromNibで表示するレイヤーを背景レイヤーに入れている箇所
を消して、以下のように書き換える。
このコードでは、新しくtransitionLayerを作り、その中に、いままでのレイヤーをaddSublayerで加えている。そして背景レイヤーには新しく作ったtransitionLayerの方を入れているのだ。
続いて、画像切り替えのcangeContentsの方にも手を入れよう。contentsの中身を入れ替えるレイヤーは一つ階層が深くなっているのだから、最初にレイヤーを取得するコードを
から
に変更する。
これで、アニメーションしながら押し出しの効果を実行しても、おかしな表示にはならないはずだ。
しかし、移動のアニメーションはちゃんと動作するものの、フィルターのアニメーションが動かなくなっている。アニメーションがtransitionLayerの方についているが、フィルターはもとのlayerの方についているため、フィルターのアニメーションが利かなくなっているのだ。
そこで、awakeFromNibでfilterをつけるレイヤーをtransitionLayerの方に変えてやる。
を
こうかえるわけだ。
これで、思った通りの動きをするようなっているはずだ。
動きをよく見ると、どうも移動途中のレイヤーの座標がうまくとれていなくて、押し出される側の画像を、レイヤーが最初にいた位置に表示してしまっているようである。
そこで、画像を表示してるレイヤーの親レイヤーを作って、移動のアニメーションはそちらで行なうようにする。そうすると、画像を切り替えている方のレイヤーは全く動いていないことになるので、表示する位置がずれるということはなくなるはずだ。図で表わすと、こんな感じになる。

では、コードを書いて行こう。まず、awakeFromNibで表示するレイヤーを背景レイヤーに入れている箇所
backgroundLayer.addSublayer_(layer)を消して、以下のように書き換える。
transitionLayer =OSX::CALayer.layer()
transitionLayer.frame = layer.frame
transitionLayer.addSublayer_(layer)
transitionLayer.masksToBounds=true
backgroundLayer.addSublayer_(transitionLayer)
このコードでは、新しくtransitionLayerを作り、その中に、いままでのレイヤーをaddSublayerで加えている。そして背景レイヤーには新しく作ったtransitionLayerの方を入れているのだ。
続いて、画像切り替えのcangeContentsの方にも手を入れよう。contentsの中身を入れ替えるレイヤーは一つ階層が深くなっているのだから、最初にレイヤーを取得するコードを
layer = @view.layer.sublayers.objectAtIndex_(0)から
transitionLayer = @view.layer.sublayers.objectAtIndex_(0)
layer=transitionLayer.sublayers.objectAtIndex_(0)に変更する。
これで、アニメーションしながら押し出しの効果を実行しても、おかしな表示にはならないはずだ。
しかし、移動のアニメーションはちゃんと動作するものの、フィルターのアニメーションが動かなくなっている。アニメーションがtransitionLayerの方についているが、フィルターはもとのlayerの方についているため、フィルターのアニメーションが利かなくなっているのだ。
そこで、awakeFromNibでfilterをつけるレイヤーをtransitionLayerの方に変えてやる。
layer.setFilters_(filterArray)を
transitionLayer.setFilters_(filterArray)こうかえるわけだ。
これで、思った通りの動きをするようなっているはずだ。
タグ : CoreAnimation RubyCocoa
RubyCocoaでアニメーション:表示している画像を入れ替える
今度は、表示している画像を入れ替えてみよう。そのためには、レイヤーのcontents属性を変えてやればいい。新しくchangeボタンを追加して、このボタンがクリックされたら別の画像に変化するようにしてみる。
まずは、AppController.rbにインターフェースとなるib_actionを宣言する。
ここでAppController.rbを保存し、MainMenu.nibをダブルクリックしてインターフェースビルダーで、画面にchangeボタンを配置し、AppController.rbとの間にコネクションを貼る。ここまで終わったら、再びXCodeに戻って、changeContentsに以下のコードを記述する。
見れば分かる通り、単純に別のファイルから新しいimageを作ってレイヤーのcontents属性に代入しているだけである。これでchangeボタンを押せば画像が新しいものに入れ替わる。フィルターの効果もそのまま残っているのが分かるはずだ。
で、フィルターがあるから若干分かりづらいのだが、切り替わるときに短い時間だがフェードの効果がかかっている。実はこのcontents切り替わり時の効果もプログラムで変更することが出来る。これにはアクションという機能を利用する。詳細な説明は例によってアップルのドキュメントを参照して欲しい。
Core Animationプログラミングガイド;アクション
いまいち分かりにくいかもしれないが、簡単に言ってしまうと、何かレイヤーの属性を変化させるような操作を行ったときに、自動的に発動するプログラムを登録しておくことが出来るしくみ、と言えばいいのだろうか。今回は、この機能を使って自分で定義した切り替え効果を実行する。
まずは、使用する切り替え効果を作成する。これはトランジションアニメーションと呼ばれている。詳しい説明はリンク先を読んでもらうとして、さっそく使ってみよう。先ほど作成したchangeContentsで、レイヤーのcontentsにimageを代入している文の直前に、以下のコードを追加する。
これは、1.5秒かけてふるい画像を新しい画像が右から押し出して行く、という効果になる。次にこれをレイヤーのcontentsが変化したときのアクションとして登録する。
これでビルドして実行し、changeボタンをクリックすると、画像が押し出されながら切り替わるようになるはずだ。
……ところが、これでめでたしめでたしとはならないのが厄介なところ。止まっているときにはこれでOKなのだが、アニメーションしている最中にchangeボタンをクリックするとおかしな動きをしてしまう。どうもOS側のバグのようなのだが……。
まずは、AppController.rbにインターフェースとなるib_actionを宣言する。
ib_action :changeContents
ここでAppController.rbを保存し、MainMenu.nibをダブルクリックしてインターフェースビルダーで、画面にchangeボタンを配置し、AppController.rbとの間にコネクションを貼る。ここまで終わったら、再びXCodeに戻って、changeContentsに以下のコードを記述する。
def changeContentsbitmapImage = OSX::NSBitmapImageRep.imageRepWithContentsOfFile_(end
'/Users/takayukiu/Documents/P1000342.jpg')
image = bitmapImage.CGImage()
layer = @view.layer.sublayers.objectAtIndex_(0)
layer.contents=image
見れば分かる通り、単純に別のファイルから新しいimageを作ってレイヤーのcontents属性に代入しているだけである。これでchangeボタンを押せば画像が新しいものに入れ替わる。フィルターの効果もそのまま残っているのが分かるはずだ。
で、フィルターがあるから若干分かりづらいのだが、切り替わるときに短い時間だがフェードの効果がかかっている。実はこのcontents切り替わり時の効果もプログラムで変更することが出来る。これにはアクションという機能を利用する。詳細な説明は例によってアップルのドキュメントを参照して欲しい。
Core Animationプログラミングガイド;アクション
いまいち分かりにくいかもしれないが、簡単に言ってしまうと、何かレイヤーの属性を変化させるような操作を行ったときに、自動的に発動するプログラムを登録しておくことが出来るしくみ、と言えばいいのだろうか。今回は、この機能を使って自分で定義した切り替え効果を実行する。
まずは、使用する切り替え効果を作成する。これはトランジションアニメーションと呼ばれている。詳しい説明はリンク先を読んでもらうとして、さっそく使ってみよう。先ほど作成したchangeContentsで、レイヤーのcontentsにimageを代入している文の直前に、以下のコードを追加する。
transition = OSX::CATransition.alloc.init
transition.duration = 1.5
transition.type =OSX::KCATransitionPush
transition.subtype = OSX::KCATransitionFromRight
これは、1.5秒かけてふるい画像を新しい画像が右から押し出して行く、という効果になる。次にこれをレイヤーのcontentsが変化したときのアクションとして登録する。
layerActions = OSX::NSMutableDictionary.alloc.init
layerActions.setObject_forKey_(transition,'contents')
layer.actions=layerActions
これでビルドして実行し、changeボタンをクリックすると、画像が押し出されながら切り替わるようになるはずだ。
……ところが、これでめでたしめでたしとはならないのが厄介なところ。止まっているときにはこれでOKなのだが、アニメーションしている最中にchangeボタンをクリックするとおかしな動きをしてしまう。どうもOS側のバグのようなのだが……。
タグ : CoreAnimation RubyCocoa
RubyCocoaでアニメーション:レイヤーにフィルタを適用する
CoreAnimationには、アニメーション以外にも強力な機能がある。前回の最後にリンクを貼ったドキュメントにも記載があったのだが、レイヤーに対してはCore Imageのフィルタが適用できるのだ。
と、いきなり言われてもピンと来ないかもしれない。とりあえず実際に試して見よう。画像をセピア調に換えるフィルターを使ってみることにする。そのためにはAppController.rbのawakeFromNibに、以下のコードを追加する。
これでビルドして実行すると、画像がセピア調になる。このようにCIFilterを作成して、レイヤーのfilters属性に設定してやるだけで、画像にフィルターがかかるのだ。このフィルター、OSで用意されているものだけでもかなり多い。さらに、自分で新しいフィルターを作ることもできるし、サードパーティが作成したフィルターがインストールされているなら、それを使うこともできる。
OSにあらかじめ用意されているフィルターの一覧は、下のページから見ることができる。
Core Image プログラミングガイド:Core Image フィルタ
ところで、この属性がfiltersとなっていることに気がついただろうか? 引数として配列を渡すようになっていることからも分かるかもしれないが、複数のフィルターを設定することができる。セピア調にしながら、ブルームフィルターをかける、なんてことも可能なのだ。さらに適用したフィルターのパラメータにアニメーションを設定してやると、フィルターの効果を時間によって変化させることができる。
実際に試してみよう。先ほどのコードで、レイヤーにフィルターを設定していた、
の部分を消して、以下のように書き換える。
これで、二つのフィルターがレイヤーに適用されるようになる。(ただし、この時点ではブルームフィルターのinputIntensityが0なので、セピア調フィルターの効果しか現われていない)
続いて、フィルターのアニメーションをさせるために、doAnimationに以下のコードを書き加える
ここでは二行目のkeyPathに注目して欲しい。
'filters.bloomFilter.inputIntensity'とある。これはawakeFromNibでフィルターを作成したときに、
と書いて付けた名前を使って、どのフィルターにアクセスするかを指定している。当然、セピア調フィルターのパラメータを変化させようと思ったらこの部分は'filters.sepiaFilter.xxxx~'となるわけだ。
これでビルドして実行すると、画像がセピア調になったまま、輝きを増したり減じたりという表示になるはずだ。もちろん、移動のアニメーションはそのままである。
と、いきなり言われてもピンと来ないかもしれない。とりあえず実際に試して見よう。画像をセピア調に換えるフィルターを使ってみることにする。そのためにはAppController.rbのawakeFromNibに、以下のコードを追加する。
filter = OSX::CIFilter.filterWithName_('CISepiaTone')
filter.setDefaults
filter.setName_('sepiaFilter')
layer.setFilters_(OSX::NSArray.arrayWithObject_(filter))
これでビルドして実行すると、画像がセピア調になる。このようにCIFilterを作成して、レイヤーのfilters属性に設定してやるだけで、画像にフィルターがかかるのだ。このフィルター、OSで用意されているものだけでもかなり多い。さらに、自分で新しいフィルターを作ることもできるし、サードパーティが作成したフィルターがインストールされているなら、それを使うこともできる。
OSにあらかじめ用意されているフィルターの一覧は、下のページから見ることができる。
Core Image プログラミングガイド:Core Image フィルタ
ところで、この属性がfiltersとなっていることに気がついただろうか? 引数として配列を渡すようになっていることからも分かるかもしれないが、複数のフィルターを設定することができる。セピア調にしながら、ブルームフィルターをかける、なんてことも可能なのだ。さらに適用したフィルターのパラメータにアニメーションを設定してやると、フィルターの効果を時間によって変化させることができる。
実際に試してみよう。先ほどのコードで、レイヤーにフィルターを設定していた、
layer.setFilters_(OSX::NSArray.arrayWithObject_(filter))
の部分を消して、以下のように書き換える。
# ブルームフィルターを作成する
filter2 = OSX::CIFilter.filterWithName_('CIBloom')
filter2.setDefaults
filter2.setValue_forKey_(OSX::NSNumber.numberWithFloat_(0.0), 'inputIntensity')
filter2.setValue_forKey_(OSX::NSNumber.numberWithFloat_(5.0), 'inputRadius')
filter2.setName_('bloomFilter')
# セピア調フィルタとブルームフィルターを配列にして、レイヤーに設定
filterArray = OSX::NSMutableArray.arrayWithObject_(filter)
filterArray.addObject_(filter2)
layer.setFilters_(filterArray)
これで、二つのフィルターがレイヤーに適用されるようになる。(ただし、この時点ではブルームフィルターのinputIntensityが0なので、セピア調フィルターの効果しか現われていない)
続いて、フィルターのアニメーションをさせるために、doAnimationに以下のコードを書き加える
pluseAnimation = OSX::CABasicAnimation.animation
pluseAnimation.keyPath='filters.bloomFilter.inputIntensity'
pluseAnimation.fromValue = OSX::NSNumber.numberWithFloat_(0.0)
pluseAnimation.toValue = OSX::NSNumber.numberWithFloat_(1.5)
pluseAnimation.duration = 1.0
pluseAnimation.repeatCount = 1e100
pluseAnimation.autoreverses = true
layer.addAnimation_forKey_(pluseAnimation,'bloom')
ここでは二行目のkeyPathに注目して欲しい。
'filters.bloomFilter.inputIntensity'とある。これはawakeFromNibでフィルターを作成したときに、
filter2.setName_('bloomFilter')
と書いて付けた名前を使って、どのフィルターにアクセスするかを指定している。当然、セピア調フィルターのパラメータを変化させようと思ったらこの部分は'filters.sepiaFilter.xxxx~'となるわけだ。
これでビルドして実行すると、画像がセピア調になったまま、輝きを増したり減じたりという表示になるはずだ。もちろん、移動のアニメーションはそのままである。
タグ : CoreAnimation RubyCocoa
RubyCocoaでアニメーション:自分でアニメーションを設定する
前回やった方法で、一応アニメーションさせることはできたが、実際に自分のプログラムで使おうと思ったら、スピードを変えたり、何回も繰り返したりとか細かい制御をしたいことが多くなるだろう。
そんな場合は、自分でアニメーションオブジェクトを作ってアニメーションさせたいレイヤーに加えてやればいい。
そのために、前回作成したプログラムのdoAnimationを次のように変更する。
アニメーションさせるレイヤーを変数layerに代入するところまでは前回と同じ。その後で、theAnimationという名前でアニメーションオブジェクトを作成する。そしてkeyPathにアニメーションさせたいlayerの属性(この場合は、レイヤーの位置=position)を入れる。durationには再生時間を、toValueには最後の値(この場合は目的地の座標)を入れる。
ここで注意しないといけないことは、アニメーションオブジェクトのtoValueに入れる値はNSValueというオブジェクトにする必要があるということだ。前回のコードと同じ感じで、
と書いてしまうとエラーになってしまう。
ここまでできたら、またビルドして動かして見よう。ゆっくり時間をかけて画像が左下から右上に動くはずだ。さらに、theAnimationにいろいろと値を設定することで、アニメーションの動きを変更することができる。例えば同じ動きを繰り返す場合は、
とrepaatCountに回数を代入する。また、動いた後に元の位置にアニメーションしながら戻ってくるようにするには、
と指定する。また、timingFunctionを指定すると、アニメーションの加速/減速を指定することもできる。以下は、加速と減速を指定した場合である。この設定を追加すると、動き始めはゆっくりで次第に加速し、停止するときに再び減速するアニメーションが表示できる。
このとき、ひとつ注意しておくことがある。
OSX::KCAMediaTimingFunctionEaseInEaseOutというのは、CoreAnimationが用意している定数なのだが、Objective-CではkCAMediaTimingFunctionEaseInEaseOutと先頭は小文字で定義されている。だが、Rubyの言語仕様では、定数は先頭一文字が大文字にしないとならない。そして、XCodeでコード補完機能を使っていると、小文字で書かれてしまい、そのまま実行するとそこでエラーになってしまう。私はこれでずいぶん悩んだ(^^;
今回と前回は位置の移動をアニメーションしてみたが、CoreAnimationでできるのはこれだけじゃない。例えば透明度を変化させたい場合は、
とkeyPathに'opacity'を入れてやり、toValueに変化させたい値を入れればよい。
アニメーションできる属性にどんなものがあり、それぞれどんな意味をもっているかはアップルの次のドキュメントを参照するといい。
Core Animationプログラミングガイド: アニメーション化可能プロパティ
Core Animationプログラミングガイド: レイヤスタイルプロパティ
そんな場合は、自分でアニメーションオブジェクトを作ってアニメーションさせたいレイヤーに加えてやればいい。
そのために、前回作成したプログラムのdoAnimationを次のように変更する。
def doAnimation(sender)layer = @view.layer.sublayers.objectAtIndex_(0)
# アニメーションを作成する
theAnimation = OSX::CABasicAnimation.animation
theAnimation.keyPath='position'
theAnimation.duration=5.0
theAnimation.toValue = OSX::NSValue.valueWithPoint_(
OSX::NSPointFromCGPoint(OSX::CGPointMake(400,300)))
# 作成したアニメーションをレイヤーに追加する
layer.addAnimation_forKey_(theAnimation,'move')
end
アニメーションさせるレイヤーを変数layerに代入するところまでは前回と同じ。その後で、theAnimationという名前でアニメーションオブジェクトを作成する。そしてkeyPathにアニメーションさせたいlayerの属性(この場合は、レイヤーの位置=position)を入れる。durationには再生時間を、toValueには最後の値(この場合は目的地の座標)を入れる。
ここで注意しないといけないことは、アニメーションオブジェクトのtoValueに入れる値はNSValueというオブジェクトにする必要があるということだ。前回のコードと同じ感じで、
theAnimation.toValue =OSX::CGPoitnMake(400,300)
と書いてしまうとエラーになってしまう。
ここまでできたら、またビルドして動かして見よう。ゆっくり時間をかけて画像が左下から右上に動くはずだ。さらに、theAnimationにいろいろと値を設定することで、アニメーションの動きを変更することができる。例えば同じ動きを繰り返す場合は、
theAnimation.repeatCount=3
とrepaatCountに回数を代入する。また、動いた後に元の位置にアニメーションしながら戻ってくるようにするには、
theAnimation.autorevers=true
と指定する。また、timingFunctionを指定すると、アニメーションの加速/減速を指定することもできる。以下は、加速と減速を指定した場合である。この設定を追加すると、動き始めはゆっくりで次第に加速し、停止するときに再び減速するアニメーションが表示できる。
theAnimation.timingFunction =
OSX::CAMediaTimingFunction.functionWithName_(
OSX::KCAMediaTimingFunctionEaseInEaseOut)
このとき、ひとつ注意しておくことがある。
OSX::KCAMediaTimingFunctionEaseInEaseOutというのは、CoreAnimationが用意している定数なのだが、Objective-CではkCAMediaTimingFunctionEaseInEaseOutと先頭は小文字で定義されている。だが、Rubyの言語仕様では、定数は先頭一文字が大文字にしないとならない。そして、XCodeでコード補完機能を使っていると、小文字で書かれてしまい、そのまま実行するとそこでエラーになってしまう。私はこれでずいぶん悩んだ(^^;
今回と前回は位置の移動をアニメーションしてみたが、CoreAnimationでできるのはこれだけじゃない。例えば透明度を変化させたい場合は、
theAnimation.keyPath='opacity'
theAnimation.duration=5.0
theAnimation.toValue = OSX::NSNumber.numberWithFloat(0.5)
とkeyPathに'opacity'を入れてやり、toValueに変化させたい値を入れればよい。
アニメーションできる属性にどんなものがあり、それぞれどんな意味をもっているかはアップルの次のドキュメントを参照するといい。
Core Animationプログラミングガイド: アニメーション化可能プロパティ
Core Animationプログラミングガイド: レイヤスタイルプロパティ
タグ : CoreAnimation RubyCocoa





