2011年12月12日月曜日

[Titanium AdventCalendar 2011/12日目] バグ図鑑+optionPickerDialog.js


Titanium AdventCalendar 2011の12日目のエントリーです。
@astronaughtsさん! いつもお世話になっております。

好きなAPIは Titanium.UI.3DMatrixです。
やっと言えた! (ずっと言いたかった)

今回は、
  • Titaniumをやってて困ったところを、ホラー調でご紹介します(先に謝っておきます、申し訳ございません)
  • Titanium.UI.OptionDialog のPicker版、optionPickerDialog.jsをご紹介します
モジュールについて書こうと思ってましたがこんなことに...

予めお断りしておくと、私はiOSでしかTitaniumを使っておらず、Androidについては
確認等してませんのであしからず。

では、参りましょう...

その一. 凄惨!Titanium.UI.Pickerのクラッシュ!
SDK :  SDKというかiOS 4.3で確認、iOS 5.0では出現せず
JIRA: #TIMOB-5489

こんなコードをiOS 4.3で動かすと...
var window = Ti.UI.createWindow();
var picker = Ti.UI.createPicker({
 top:480
});
window.add(picker);

var button = Ti.UI.createButton({
 title:'push...', 
 width:80, 
 height:30
});
window.add(button);

var data = [];
data[0]=Ti.UI.createPickerRow({title:'Bananas',custom_item:'b'});
data[1]=Ti.UI.createPickerRow({title:'Strawberries',custom_item:'s'});
data[2]=Ti.UI.createPickerRow({title:'Mangos',custom_item:'m'});
data[3]=Ti.UI.createPickerRow({title:'Grapes',custom_item:'g'});

picker.selectionIndicator = true;
button.addEventListener('click', function(){
 picker.add(data);
 picker.animate({ top:240, duration:500 });
});
window.open();
もう二度と帰って来れなくなりますよ...
2011-12-11 16:35:59.776 TiAdventCalendarDemo[10891:13a03] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSMutableArray objectAtIndex:]: index 0 beyond bounds for empty array'
window.add()する前にpikcer.add()すれば助かります。

その二. 暗黒のTitanium.Media.openPhotoGallery...
SDK :  1.7.5 (多分1.7.5以前も...)
Appcelerator Q/A:http://developer.appcelerator.com/question/121924/ios-memory-warnings-unloads-app-black-screen-of-death

この画面から...
Titanium.Media.openPhotoGallery()を呼んで...
メモリ警告を発生させて...

Cancelを押して戻ってみると...
キャァーッ!!!目が...目が!!!

SDK 1.8になると多分もう出会えません。(1.8 CIでは治ってました)

その三. Titanium.UI.Toolbarで歪む空間...
SDK :  1.7.5 (多分1.7.5以前も...)
Appcelerator Q/A:http://developer.appcelerator.com/question/119529/toolbar-button-image-distortion

こんなコードを書いて...
var toolbarButton1 = Ti.UI.createButton({
 image:'photo_gallery.png'
});
var toolbarButton2 = Ti.UI.createButton({
 image:'filter.png'
});
var toolbarButton3 = Ti.UI.createButton({
 image:'tiltshift.png'
});
var toolbarButton4 = Ti.UI.createButton({
 image:'save.png'
});
var flexible = Ti.UI.createButton({
    systemButton:Ti.UI.iPhone.SystemButton.FLEXIBLE_SPACE 
});
var toolbar = Ti.UI.createToolbar({
 barColor:'#000',
 items:[toolbarButton1, flexible, toolbarButton2, flexible, toolbarButton3, flexible, toolbarButton4],
 bottom:0
});
window.add(toolbar);
デバイスの向きを横にしてみましょう...
私は今どこにいるの...

...ええと、ちゃんと表示したい場合はbackgroundImageプロパティに'none'を設定してあげるか、そもそも表示したい画像をbackgroundImageプロパティに設定してあげましょう。

楽しいですね!では、次。

Titanium.UI.optionPickerはご存知ですか?


こんなやつです。(doc-jaからコードを拝借しました)
画面の下からヌゥーっと出てきます。

選択肢が少ない場合はいいのですが、選択肢が多い場合は少し困ってしまいます。

そんなとき、optionPickerDialog.jsの出番です。
(どこかのブログで書かれていたのをきっかけで知ったのですが、どこだったかな...)

コードはこちら http://www.pastie.org/1494046

Bart Lewisさんという方が書いてくださったもので、使い方はこんな感じです。
// まあ、こうしないと始まりませんね
Ti.include('optionPickerDialog.js');
// titleとvalueというプロパティを持ったオブジェクトの配列を
// optionPickerDialog.setData()で設定します。
var data = [
    { title:'A', value:1 },
    { title:'B', value:10 },
    { title:'C', value:100 }, 
];
optionPickerDialog.setData(data);
// closeイベントで、doneかcancelか分かります。
// また、doneの場合、選択した内容にアクセス出来ます。
optionPickerDialog.addEventListener('close', function(e){
 if (e.done==true && e.selectedRow){
  alert(e.selectedRow.value);
 }
}); 
// open()でダイアログが下からヌゥーっと出ます
optionPickerDialog.open();
open()でこんなのが出てきます。













気をつけないといけないのは、optionPickerDialog.jsでTi.UI.currentWindowが使われています。
シングルコンテキストな場合は、ちょっと修正してあげないといけません。
(私はとりあえずcurrentWindowというグローバル変数を使うようにしました)

また、2つほどバグがありました。

  1. iOS 4.3でクラッシュしちゃう(上記のバグですね)
  2. デバイスを横向きにしたときのツールバーの位置がちょっとおかしい
勝手に修正してしておきました。コードはこちら http://pastie.org/2999293

以上、まとまりのないエントリーでしたが、読んでいただきましてありがとうございました。
明日は、@h5y1m141さんです。よろしくお願いします!


2011年11月14日月曜日

UIGestureRecognizerで複数のジェスチャを同時に認識する方法


UIGestureRecognizerを複数登録したとき、デフォルトでは同時に複数のジェスチャを認識してくれません。

一度ジェスチャが終了しないと新しいジェスチャを認識しないので、操作感が微妙だったりします。

そんなときには、UIGestureRecognizerDelegateの
gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:
の出番です。

<<こんな感じ>>

UIGestureRecognizer に delegate を設定してあげましょう。
 UIPinchGestureRecognizer *pinchGesture =[[UIPinchGestureRecognizer alloc] initWithTarget:self
                                                                                          action:@selector(handlePinchGesture:)];
 [self addGestureRecognizer:pinchGesture];

 /* ここ! */
 pinchGesture.delegate = self;
 [pinchGesture release];
gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: を実装しましょう。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    /* 無条件に、すべてのジェスチャを同時に認識します。 */
    return YES;
}
これでOK。簡単ですね。

2011年9月30日金曜日

Titanium Meet up Tokyo #13


Titanium Meet up Tokyo #13に参加してきました!
会場のDNP五反田ビル、すごく気持ちよい場所でした。

前半1時間は増井さんのCODESTRONG/Marketplaceのお話、
後半1時間はモクモクとコードを書く時間でした。

メモした事と増井さんから聞いた話、私の個人的な感想が混ざってますが、
とりあえず列挙しておきます。

参加した方で間違いや不足があったらご指摘いただけると嬉しいです。

CODESTRONG

  • 残念ながらビデオが間に合わず、後日となるそうです
  • キーノートでTi本が紹介されたそうです(^^)
  • ハッカソンは下準備されてる方が多かったようです(デザインの素材とか)
  • 来年のCODESTRONGでハッカソンに参加する場合は下準備が重要!?


Marketplace
  • モジュール/デザイン素材/フレームワークの売買ができます
  • モジュールはライセンスチェックされているので、不正に利用はできません(アプリ起動時にUnlicensed Moduleというエラーが発生する)
  • モジュールはsubmitしたらテストプログラムでチェックされるそうです(基本的に動かないモジュールが公開される事はない)
  • 月額利用のタイプはプロジェクト期間中のみ利用し、開発終了したら利用を止めても良い。(また必要になったらsubscribeすればいい)
  • Marketplaceはまだ若干バタバタしてるそうですw
  • tiapp.xmlに記述したのにUnlicensed Moduleが出る場合、Project->Cleanしてみて
  • ダウンロードしてすぐはUnlicensed Moduleが出るかも(30分程度経ったら解消する?)
  • モジュール作った事がある人はsubmitしてみて!
  • 作って欲しいモジュールがあったら、@appcelerator_jaまで!
  • モジュールのダウンロードからインストールまでまとめた日本語の情報を公開するとのこと
  • モジュールのインストール先はプロジェクトかグローバル
  • ただし、プロジェクトにインストールするとモジュールファイル自体がアプリにバンドルされちゃうので気になる方は注意!(詳細はTitaniumの自作モジュールをバンドルさせたくない時の対処法)
  • 画像フィルタとかTitaniumがサポートしていないところをどんどんモジュール化したい
  • 個人的にはInstagram 2みたいな事ができるモジュールを作りたいなあ...(誰か一緒にやりませんか、OpenGL ESでフィルタ)

Androidのv8対応

  • 1.8でv8に対応する予定だそう
  • Titanium Desktopもv8に対応するそう
  • v8に変わったらモジュール周りが変わっちゃうかもしれないので要注意!?



2011年9月25日日曜日

Titanium Mobileで回転&ピンチジェスチャ


iPhoneで回転とかピンチイン/アウトっていうジェスチャはマイナーなジェスチャで、あまり使う場面がありません。(UXとしても推奨されない部類?)

とはいえ、Titanium Mobileでこのジェスチャがサポートされていない(ですよね!?)のもどうかと思い、使われる事はないであろうと分かっていながらモジュールを作ってしまいました。

相変わらずiOSのみ対応です。

OpenCVでは有名なlenaさんの画像を回したり拡大したり縮小したりできるデモ。


Gesture Recognizer Demo from Atsushi Kataoka on Vimeo.

ViewにrotateGesture、pinchGestureというプロパティをtrueで設定すると、rotateとかpinchっていうイベントが発生します。
ジェスチャ終了時にはrotateend、pinchendっていうイベントが発生します。
んで、上のデモのソースコードはこんな感じ。

var window = Ti.UI.createWindow({
	orientationModes:[
			  Ti.UI.LANDSCAPE_LEFT,
			  Ti.UI.LANDSCAPE_RIGHT,
			  Ti.UI.PORTRAIT,
			  Ti.UI.UPSIDE_PORTRAIT
			 ]
});

var image = Ti.UI.createImageView({
    image:"lena_std.jpg",
    rotateGesture:true,
    pinchGesture:true
});
var lastAngle = 0.0;
var currentAngle = 0.0;

var lastScale = 1.0;
var currentScale = 1.0;

image.addEventListener('rotate', function(e){
    currentAngle = e.rotation / Math.PI * 180.0;
    image.transform = Ti.UI.create2DMatrix()
        .scale(lastScale*currentScale)
        .rotate(lastAngle+currentAngle);
});

image.addEventListener('rotateend', function(e){
    lastAngle = (lastAngle + currentAngle) % 360.0;
    currentAngle = 0.0;
});

image.addEventListener('pinch', function(e){
    currentScale = e.scale;
    image.transform = Ti.UI.create2DMatrix()
        .scale(lastScale*currentScale)
        .rotate(lastAngle+currentAngle);
});

image.addEventListener('pinchend', function(e){
    lastScale = (lastScale * currentScale);
    currentScale = 1.0;
});

window.add(image);
window.open();

MarketplaceにFreeで公開したいのですが、アイコンとイメージを作るのが面倒で止まっています。
アイコンとイメージは何の報酬もありませんが緩く募集します。

ソースコードは https://github.com/atsusy/Gesture-Recognizer

2011年8月24日水曜日

今更ですがTitanium MobileでCoffeeScriptしてみた(2)


Titanium Studio で CoffeeScriptが使えるようになったので、次はちょっとフレームワークっぽい物を作ってみたくなりました。

目標:TweetaniumをCoffeeScriptで置き換える

とりあえず...
  • 名前空間をサポート
  • ソースを分割して書ける
で、こんな感じになりました。名前はsyrup。

syrup.coffee

define_global_variable_js = (name) ->
  js = "if(typeof #{name} === 'undefined') \{ #{name}={} \} else \{ #{name} \}"
  return `eval(js)`

exports.namespace = (ns, block) ->
  names = ns.split '.'  

  # root namespace is assigned to global variable 
  target = define_global_variable_js names[0]
  
  for name in names.slice 1
    target[name] = {} if not target[name]
    target = target[name]     
  
  block target

exports.use = (ns) ->
  this.namespace ns, (exports) -> return exports
    
exports.include = (file) ->
  Ti.include("#{file}.js")

model/entity.coffee

syrup.namespace 'MYAPP.Model', (exports) ->
  class Entity
    sayHello: (name) ->
      alert "Hello,I'm #{name}"
      
  exports.Entity = Entity

model/person.coffee

syrup.namespace 'MYAPP.Model', (exports)->
  Entity = syrup.use 'MYAPP.Model.Entity'
  
  class Person extends Entity
    constructor: (@name) ->
    
    sayHello: ->
      super @name

  exports.Person = Person      

app.coffee

syrup = require 'syrup'

syrup.include '/model/entity'  
syrup.include '/model/person'
    
person = new MYAPP.Model.Person 'Coffee syrup'
person.sayHello()

あまり、意味のないサンプルコードで申し訳ないです...

プラグインを弄って、依存関係を手繰ってソースファイルをソートして、app.coffeeを自動で生成すれば、もっと楽になるかな? あとは、どうやってbootするかだな。

今更ですがTitanium MobileでCoffeeScriptしてみた(1)


なんだか巷では、CoffeeScriptいいね!ってことになってるようで、私もちょっと乗っかってみようと思い試してみました。

まずは、Titanium Studio上でCoffeeScriptを使えるようにするための環境作り。

Titanium CoffeeScript Pluginを入れてみます。
Mac OSX Lion / Titanium Studio 1.0.4 でしか確認していません。

  • 事前にnodeとかcoffeescriptをインストールしておいて下さい。
    また、上記サイトにも書いてますが、Titanium Studio上ではパスが通ってないので、
    $ sudo ln -s /usr/local/bin/node /usr/bin/node
    $ sudo ln -s /usr/local/bin/coffee /usr/bin/coffee
    
    などして、Titanium StudioからCoffeeScriptを実行可能にしてあげておく必要があります。

  • plugin.py を /Library/Application Support/Titanium/ti_coffee_plugin/1.0/にコピーします。

  • 適当にプロジェクトを作成します。
  • app.jsは必要ないので削除します。
  • tiapp.xml に 以下の記述を追加します。
    <ti:app>
        .
        .
        .
        <plugins>
            <plugin version="1.0">ti_coffee_plugin></plugin>
        </plugins>
    </ti:app>
    
  • app.coffeeを追加します。
これで、Titanium Studioでビルド時に、プラグインがapp.coffeeをapp.jsに変換するようになります。

CoffeeScript Pluginのプロジェクトテンプレートあったら楽だなあ...

2011年7月11日月曜日

Titanium Mobileで背景画像を繰り返し表示する


Titanium Mobileの背景画像を繰り返し表示する方法(タイル表示)がどうも標準で用意されていないようだったので、モジュールを作りました。

github: https://github.com/atsusy/tirepeatedbackgroundimage

<<はじめに>>
* iOS専用です
* githubからのクローン方法およびモジュールのビルド方法については割愛します

<<利用方法>>
1. 取り込みたいプロジェクトのtiapp.xmlの<modules>タグ内に以下を追記して下さい
<module version="1.0">jp.msmc.repeatedbackgroundimage</module>

2. タイル表示したいビューに以下のような感じでrepeatedBackgroundImageプロパティを設定して下さい
// ビューの場合
    var view = Titanium.UI.createView({
        repeatedBackgroundImage:'hoge.png' // 繰り返し表示したい画像を指定します
    });

3. ウィンドウも同様にrepeatedBackgroundImageプロパティに画像を設定する事でタイル表示できます


タイル表示したい画像(hoge.png[75x75])

var window = Ti.UI.createWindow({
 repeatedBackgroundImage:'hoge.png'
});
window.open();
app.js


こんな感じになります

2011年6月17日金曜日

Ti.Devs.Meeting vol.0.1に参加しました


関西のTitanium Mobileに興味がある人が集まるTi.Devs.Meetingというのに参加して
お話をしてきました。

* セッションの内容
YQLを使ってRSSフィードを取得し、フィードの一覧からpodcastを
ストリーミング再生するアプリを作ったのでそれについて簡単にお話ししました。

* 感想
- 久しぶりに人前で話をしたので緊張しました!
- もっとおもしろくできればよかった!(面白くなくて申し訳ないです)
- もっと人に伝わるような話をしないといけませんね

* スライド

2011年5月27日金曜日

Titanium MobileのOpenGL ESモジュールで3D物理エンジン!


Titanium MobileのOpenGL ESモジュールですが、相変わらずパフォーマンスは今ひとつのままです。

にもかかわらず、オープンソースの3D物理エンジンであるBulletを組み込んでみました。
さあ、収拾がつかなくなって参りました。いい加減ブラッシュアップしていかないと...

とにかく、100個の立方体を降らしてみました。
シミュレーターで動かすとこんな感じです。

Unable to display content. Adobe Flash is required.

Core i7のMacbook Proだと50FPSは出ますが、
iPhone4の実機だと20FPSくらいまで落ち込んでしまいます...
剛体でこれだから、弾性体はもっと重いんでしょう。

というわけで、これはまだ未コミットです。

BulletをiOSで最適化する記事が
http://www.aorensoftware.com/blog/2011/03/31/bullet-physics-optimization-for-ios
にあるので試してみようかな。

あと、OpenGL ES 2.0でGPGPUする試みの数々ってのもすごいなあ。

2011年5月7日土曜日

Titanium MobileのOpenGL ESモジュールでパーティクル!


Titanium MobileのOpenGL ESモジュールですが、まだあきらめずに地味に頑張っています。
疲れたので、ちょっと気分転換にパーティクルを組み込んでみました。

Particle Designerというパーティクルのデザインを簡単に行えるMacのアプリがあるのですが、それにOpenGL ESのパーティクルエンジンのソースが同梱されていましたので、これをOpenGL ESモジュールに取り入れさせていただきました。(ライセンス的には問題ないと思うのですが...どうなのかな)

ちなみにParticle Designerは有償のソフト(7.99US$)です。(ライセンスを購入しない場合でもデザインを保存できないのみで、それ以外の機能は使用できます)

また、作成したパーティクルを投稿することもできるので、すでにいろいろなパーティクルが利用可能になっています。

シミュレーター上で実行した感じはこんな感じです。

Unable to display content. Adobe Flash is required.

*ダウンロード
git@github.com:atsusy/tiopengles.git

*使用方法
Particle Designerでデザインしたパーティクルはxmlで保存できます。suffixがpexなのでpexファイルと呼ぶことにします。

// モジュールの読み込み
var opengles = require('com.tiopengles');
// OpenGL ESビューの作成
var view = opengles.createView();
// パーティクルの読み込み
var particle = opengles.loadpex("pexファイルのパス");
// ビューにパーティクルを追加
view.addParticleEmitter(particle);
// 表示位置を変更することができます
particle.sourcePosition = {x:100.0,y:100.0};
// 表示のオン/オフができます
particle.active = false; //オフ
particle.active = true; // オン

2011年4月27日水曜日

名言botの名言をひたすら表示するWebサイト


名言botの名言をただひたすらに表示し続けるサイトを作ってみました。
Macの方がフォントがきれいでよいです。

疲れた時とかにただ眺めてると元気になることもあるかも?

http://meigenlighting.appspot.com

2011年4月25日月曜日

Titanium Mobileでパーティクルっぽいことをしてみたけど失敗。


JavaScriptのパーティクルエンジンをたまたま発見したので、そのままTitanium Mobileで使えないかと思って試してみました。

元ネタはこちら

Unable to display content. Adobe Flash is required.

WebView内のcanvasにパーティクルを描画しています。
この動画で150個のパーティクルです。
まあ、この動画はCore i7のMacbook Proでの動きで、iPhone4の実機で動かすとせいぜい20-30個程度でしかまともに動きませんでした。

というわけで実験失敗。

2011年4月23日土曜日

iOS 4.3にしたらOpenCV 2.2が動かなくなった方は


iOS 4.3になって、OpenCV 2.2が動かない!って方はいらっしゃいませんか。

Accelrate.frameworkをリンクされている場合、代わりにOpenCV 2.2のlibopencv_lapack.aをリンクしてみて下さい。

元ネタはこちら

OpenCV2.2のiOS向けなユニバーサルバイナリを作るための最も簡単な方法


以前、OpenCV 2.2のiOS向けなユニバーサルバイナリを作るってのを書きましたが、もーっと簡単にarmv6/armv7/i386のユニバーサルバイナリを作る手順がありました。

1) https://github.com/BloodAxe/OpenCV-iOS-build-script から、BuildOpen.shをダウンロードします。
2) OpenCV 2.2 のソースをダウンロードします。
3) sh BuildOpen.sh <OpenCVのソースディレクトリ> <ビルド出力先ディレクトリ>

以上。かんたんですね!

2011年4月7日木曜日

メインスレッドで実行させるマクロに目からウロコ


Titanium Mobileのモジュールを作っているときに、あるメソッドをメインスレッドで実行する必要があったのですが、Titanium MobileのSDKにマクロが定義されています。

そのマクロが「いいね!」だったのでご紹介。
(すごいベタな手法なのかもしれませんが...)

#define ENSURE_UI_THREAD_1_ARG(x) ¥
if (![NSThread isMainThread]) { ¥
[self performSelectorOnMainThread:_cmd withObject:x waitUntilDone:WAIT_UNTIL_DONE_ON_UI_THREAD modes:[NSArray arrayWithObject:NSRunLoopCommonModes]]; ¥
return; ¥
} ¥

メインスレッド以外から実行された場合、自分自身をメインスレッドで呼び直します。
呼び直された際、[NSThread isMainThread]がTRUEなので、マクロ以降のコードが実行されると。

ちなみに_cmdってのが、実行中のメソッドのセレクタとなる暗黙な変数だそうで(知らなかった...)
詳しくはこちらを参照してください

使い方は、

- (void)hoge:(id)args
{
    ENSURE_UI_THREAD_1_ARG(args);

    // 以降はメインスレッドで実行される
}

他にも、メインスレッドで実行するためのマクロが用意されていますので、
ヘッダを参照してみて下さい。

勉強になった。

2011年4月6日水曜日

CALayerを使って独自のプロパティをアニメーションさせる


元ネタはこちら

OpenGL ESのシーン管理でカメラやら照明やらモデルやらをアニメーションするのに使えないかなと。
あと、角度をプロパティで定義して時計の針を表示したりとかにも使えますね。

[簡単な手順] (簡単すぎてすいません)

- CALayerを継承して独自のプロパティを追加したクラスの作成 -
1) CALayerを継承したクラスを作成する(例としてクラス名をCustomLayerとします)

2) 独自のプロパティを定義する

3) drawInContext:をオーバーライドし、独自のプロパティに従った描画を行うロジックを記述

4) needsDisplayForKey:をオーバーライドし、独自のプロパティに対してYESを返すようにしてあげる。独自のプロパティ以外はsuperにお任せする

5) initWithLayer:をオーバーライドし、アニメーションさせるプロパティをコピーするようにしてあげる
(これはアニメーションする際にレイヤーをコピーする?処理が含まれるため必要)

@implementation CustomLayer
@synthesize hoge;

- (id) initWithLayer:(id)layer {
    NSLog(@"initWithLayer called.");
    if((self = [super initWithLayer:layer])) {
        if([layer isKindOfClass:[CustomLayer class]]) {
            CustomLayer *other = (CustomLayer*)layer;
                self.hoge = other.hoge;
        }
    }
    return self;
}

- (void)drawInContext:(CGContextRef)ctx
{
    // self.hogeの内容が変わりながら呼び出される
}

+ (BOOL)needsDisplayForKey:(NSString *)key {
    if ([key isEqualToString:@"hoge"]) {
        return YES;
    }
    else {
       return [super needsDisplayForKey:key];
    }
}
@end

- UIViewに作成したレイヤーを登録する -
1) 適当なタイミングでレイヤーオブジェクトを生成し、子レイヤーとして登録する
UIViewControllerのviewDidLoadでやってみる場合
- (void)viewDidLoad
{
    [super viewDidLoad];
    customLayer = [[CustomLayer alloc] init];
    customLayer.bounds = self.view.bounds;
    [self.view.layer addSublayer:customLayer];
}

2) アニメーションの定義
- (void)animateHoge{
 CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"hoge"];
 anim.duration = 3.0;
 anim.fromValue = [NSNumber numberWithDouble:50.0];
 anim.toValue = [NSNumber numberWithDouble:150.0];
 anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    
        // これでアニメーションが開始される
 [customLayer addAnimation:anim forKey:@"animateHoge"];
    
 customLayer.hoge = 150.0;
}

3) animateHogeを呼んでみると、CustomLayerのdisplayが自動でぶわーっと呼び出され、
displayからdisplayContext:が呼び出され、アニメーションしながら表示されるという寸法ですね。

こんな感じで、カメラ/照明/モデルの回転とか移動とかをアニメーションしながらシーン描画できたらなあと。あ、もちろん表示の更新はCADisplayLink使ってやるつもりですが。んーなんかちょっと無理あるか?

2011年4月1日金曜日

Castmarkというアプリをリリースしました


先日、「TOEICを勉強するついでにアプリを作る」と言っていましたが、こないだAppStoreにリリースされました!

*こんなアプリ
- ブラウザからpodcastのフィードを選んで登録
- プレイリストから聴きたいコンテンツを選んで再生
- 再生中にメモを記録!スペルチェックできて英英辞書も引けます!
- あとで再生するときに記録したメモが記録した時間に表示されます

2011年3月28日月曜日

Titanium mobileのOpenGL ESモジュール!(続報)


Titanium mobileのOpenGL ESモジュールですが、なかなか苦戦をしております。
少しですが進捗したので、githubにpushしました。

ソースは、以下からダウンロードしてください。
git@github.com:atsusy/tiopengles.git

*出来るようになった事
- 3dsファイルを読み込んでモデルを表示
モジュールのload3dsメソッドでパスを指定して読み込みます。
テクスチャは3dsファイルと同じディレクトリに配置しておけば、自動で読み込みます。

- カメラの位置と角度
カメラの位置と角度を設定できるようにしました。

詳しくはexample/app.jsを見て下さい。

どこぞでダウンロードしてきたR2D2を表示し、カメラ操作を(無理矢理ですが)行えるようにしたサンプルとなっています。


Freeな3dsのモデルは探せば結構あるようですので、いろいろ試してみていますが中には正しく読み込めないのもあるようです。(local coordinate system絡み?)

後はアニメーションが出来れば...(遠い目)

2011年3月23日水曜日

Titanium mobileで360度の回転アニメーション


Titanium mobileでは、表示要素のアニメーションをコードで書くことができるのですが、
回転は-180度から180度までしか指定できません。(指定しても反対側に回転してしまう?)

https://appcelerator.lighthouseapp.com/projects/32238/tickets/416-animation-cant-rotate-360-degrees
http://developer.appcelerator.com/question/87441/rotate-360-degrees-does-not-work

でも、どうしてもpodcastの30秒巻き戻しボタンみたいなのをやりたくて、かなり無理矢理ですがやってみました。

まず、通常の画像を用意します。(A.png)


次に、180度回転させた画像を用意します。(B.png)

そして、以下のコード(iOSでしか確認してません)
var rewind = Ti.UI.createImageView({
    left:100,
    top:100,
    width:32,
    height:32,
    image:'A.png'
});

var animateRewinding = function(){
    rewind.image = 'A.png';
    rewind.transform = Ti.UI.create2DMatrix();
 
    var r = Ti.UI.create2DMatrix();
    r = r.rotate(-180);
    rewind.animate({transform:r,duration:500,opacity:0.0}, function(){
         rewind.image = 'B.png';
         var r = Ti.UI.create2DMatrix();
         rewind.animate({duration:0,transform:r}, function(){
               var r = Ti.UI.create2DMatrix();
               r = r.rotate(-180);
               rewind.animate({duration:500,transform:r, opacity:1.0}, function(){
                    animateRewinding();
               });
         });
     });
};

何かすごく嫌な書き方なのですが動くには動きました。
しかし、Retina用の画像も用意するとなれば4種類の画像を用意せねばいけないという...

2011年3月18日金曜日

TOEICを勉強するついでにアプリを作る


唐突ですがTOEICの試験を受けてみることにしました。

主にpodcastを聞いて勉強をしているのですが、ただ聞いていても聞き流すだけになってしまったり、ある単語の意味が分からないために途中から訳が分からなくなる事が多いです。

というわけで、英語の学習用にiPhoneアプリを作っています。(もちろんTitanium mobile!)
完成したら無料で公開しようかなと思っています。

機能はこんな感じです。

*podcastのフィードを登録する
*フィードからコンテンツの一覧を表示する
*一覧から選択してpodcastを再生する
*再生中にテキスト入力を行い、その内容を辞書で検索する(とりあえず英英辞書)
*テキスト入力時にスペルチェックを行い、入力候補を表示し入力しやすくする
*入力したテキストの再生時間を覚えておいて、再生中に表示するようにする(ニコ動の音声版みたいな)
*ユーザ同士で同じコンテンツに登録したテキストを共有できればおもしろいかな

英語だけじゃなくて、それ以外のコンテンツでも使えそうな気がしてきました(podcastラジオにツッコミ入れたりとか)

テキストの共有以外はだいたい出来ているので、あとひと頑張りってとこです。
自身でデザインが出来ないので、無骨なものしか出来ないのが悩みの種です。

2011年3月16日水曜日

Ti.UI.ButtonBarのenabledを設定する


Titanium mobile の ButtonBar ですが、各ボタンのenabledを制御しようとして
以下のコードを試してみましたがうまく行きませんでした。

var operationButtons = [{title:'Back',enabled:false}, {title:'Forward',enabled:false}];
var operationBar = Titanium.UI.createButtonBar({
 labels:operationButtons,
 style:Ti.UI.iPhone.SystemButtonStyle.BAR
});

var operationButtons = [{title:'Back',enabled:false}, {title:'Forward',enabled:false}];
var operationBar = Titanium.UI.createButtonBar({
 labels:operationButtons,
 style:Ti.UI.iPhone.SystemButtonStyle.BAR
});
operationBar.labels = operationButtons; // labelsプロパティを再設定してみる

var operationButtons = [{title:'Back',enabled:false}, {title:'Forward',enabled:false}];
var operationBar = Titanium.UI.createButtonBar({
 labels:operationButtons,
 style:Ti.UI.iPhone.SystemButtonStyle.BAR
});
// windowオープン後にenabledプロパティを変えてみる
window.addEventListener('open', function(e){
 operationButtons[0].enabled = false;
});

格闘した結果、以下のコードだとうまくいきます。

var operationButtons = [{title:'Back',enabled:false}, {title:'Forward',enabled:false}];
var operationBar = Titanium.UI.createButtonBar({
 labels:operationButtons,
 style:Ti.UI.iPhone.SystemButtonStyle.BAR
});

// windowオープン後にlabelsプロパティを再設定してみる
window.addEventListener('open', function(e){
 operationBar.labels = operationButtons;
});

ま、そういうことです。(どういうこと??)

2011年3月10日木曜日

Xcode 4になってArchiveが変わってしまったようだ


Xcode 4がリリースされましたね。とりあえずダウンロードしてみました。
確認していると、気になった点がありました。

アプリをアーカイブする機能(メニュー:Product-Archive)があるのですが、
アーカイブした結果がXcode 3とかなり異なっています。

何が困るかって、Titanium mobileでDistributionの際にbuilder.pyでアーカイブ処理を行っているのです。(もちろん Xcode 3の仕様で)
Titanium mobile は SDK 1.6.1で対応済みです(2011/3/20追記)
そのため、Xcode 4のOrganizer-Archivesに出てきません。

リリースノートとか見れば、仕様が記述されているかもしれないのですが、
探すのが面倒だったのでとりあえず比較してみました。

(1) 保存先のディレクトリ
Xcode 3:
/Users/<ユーザ名>/Library/MobileDevice/Archived Applications/
Xcode 4:
/Users/<ユーザ名>/Library/Developer/Xcode/Archives/<日付>/

(2) アーカイブの内容
Xcode 3:
<保存先のディレクトリ>/
        ArchiveInfo.plist
        .app
        .app.dSYM

Xcode 4:
<保存先のディレクトリ>/
         <アプリの名前> <日付>.xcarchive/
                dSYM/
                        .app.dSYM
                Info.plist
                Products/
                        .app

(3) Info.plistの内容
Xcode 4:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>ApplicationProperties</key>
 <dict>
  <key>ApplicationPath</key>
  <string>Applications/アプリ名.app</string>
  <key>CFBundleIdentifier</key>
  <string>アプリのID</string>
  <key>IconPaths</key>
  <array>
   <string>Applications/アプリ名.app/Icon.png</string>
  </array>
 </dict>
 <key>ArchiveVersion</key>
 <real>1</real>
 <key>CreationDate</key>
 <date>2011-03-10T07:09:28Z</date>
 <key>Name</key>
 <string>アプリ名</string>
 <key>SchemeName</key>
 <string>アプリ名</string>
</dict>
</plist>

一応、Xcode4のアーカイブの仕様にしたがってbuilder.pyを修正してみたところ、うまくいったのですが... まあ、そのうち対応版がリリースされるのを待った方が良さそうですね。

Titanium mobileのOpenGL ESモジュール!(を実験中)


Titanium mobileでARマーカーを検出できるようになると、必然的にマーカーの上に3Dなオブジェクトを乗せたくなります。

そこで、Titanium mobileでOpenGL ESを扱えるようなモジュールを作ってみようかと思っています。

とりあえず途上ですが(まだ作業2日目)、少し動いたので公開します。
git@github.com:atsusy/tiopengles.git から cloneしてください。

*はじめに
- iOSのモジュールです。Androidでは使用できません。
- OpenCVを使用しています。
- シミュレータでも動作します。(まだデバイスでの動作が確認できてません)
- 現時点では、SDKバージョン1.6.0以上としています。
- 最終的に使えるものになるかどうか不明です...

*動かし方(Macの場合です、すいません)
~/.profileに、以下を追記して下さい。
alias titanium='/Library/Application\ Support/Titanium/mobilesdk/osx/1.6.0/titanium.py'

チェックアウトしたディレクトリで
titanium run
でシミュレーターが起動し、実行されます。


*今できること
example/app.js をご参考ください。

- プロジェクションの設定(zNear, zFar, fieldOfView[画角])
- 照明の設定(ambient, specular, diffuse, position, direction)
- モデルを読み込む(インタフェースのみで実装は立方体のモデルを固定で定義)
- モデルの移動と回転

*これからやりたいこと
- 3dsフォーマットのモデルデータを読み込む(頂点、法線、テクスチャ)
- カメラの設定(位置と向き)
- カメラ、照明、モデルのアニメーション


******つづきはこちら******

2011年3月7日月曜日

Titanium mobileのARマーカー検出モジュール!


*** iOS 4.3 で動作するようになりました、githubから最新をpullしてください ***

Titanium mobileで ARマーカーを検出するモジュールを作りました。

っても、いろんな記事を大いに参考にさせていただきました。
よって、こっ恥ずかしいのですが、公開します。

git@github.com:atsusy/tiarmarker.git からcloneしてください。

*はじめに
- iOSのモジュールです。Androidでは使用できません。
- OpenCVを使用しています。
- シミュレータでは動きません。デバイスでしか動きません。(iPhone 3G/3GS/4 で動作確認)
- 現時点では、SDKバージョン1.6.0以上としています。

*ARマーカーって?
AR(Augmented Reality) [拡張現実] の実現手法の一つです。
マーカーという定型のマークをカメラで認識し、位置や姿勢、コードを検出します。

A-Z と 0-9 を ARマーカーにするとこんな感じです。文字でなくてもいいです。
最終的には4x4の16bitのコードとして認識します。


マーカーにアプリケーションで物体等をオーバーレイしたりすると、
カメラを通してARを体験することができるというものです。

やったことないんですが、ラブプラスなんかでも使われてるんですね。

*インストール方法
事前に、サンプル動作用にTitanium mobile SDK 1.6.0のプロジェクトを作成しておいて下さい。

cloneしたソースのディレクトリで、
./build.py
を実行し、モジュールをビルドします。
ビルドが完了すると、com.armarkerti-iphone-0.1.zip というファイルが出来上がっているはずです。

com.armarkerti-iphone-0.1.zipを、サンプル動作用に作成したプロジェクトのディレクトリにコピーして下さい。

モジュールのインストールは以上です。

*サンプルの実行
example/app.jsを、サンプル動作用に作成したプロジェクトのResourceディレクトリにコピーして下さい(プロジェクトが作成したapp.jsを上書きします)

tiapp.xmlを編集し、modulesタグ内に、ARマーカー検出モジュールを使用する事を宣言して下さい。
<modules>
   <module version="0.1">com.armarkerti</module>
 </modules>

後は、プロビジョニングファイルを用意してデバイス上で実行して下さい。

起動するとカメラの入力映像が表示されますので、example/marker.pngを印刷するか、PCに表示してください。

"A"のマーク(左上)をカメラで見て、その上に"a"という文字がマーカーに合わせて表示されれば正しく動作しています。

*ビューをオーバーレイさせるには
まずは、example/app.jsを参考にして下さい。

1) com.armarker.ti : createCameraView() で、カメラの映像を表示するビュー(cameraView)を生成する
2) オーバーレイしたいビューを作成する
その際、center:{x:0, y:0}, visible:false としておく
3) オーバーレイしたいビューをcameraViewにaddする
4) cameraViewのdetectedイベントで、検出したマーカーすべての コード(code)/中心位置(moment)/射影行列(transform)にアクセスできるので、目的のマーカーがあるかチェック

オーバーレイしたいビューを animate({transform:マーカーへの射影行列の3DMatrix, duration:0}) すると、マーカー上にビューがオーバレイ表示される。目的のマーカーが存在しない場合は、オーバーレイしたいビューのvisibleをfalseにする。

*足りないところ
- フレームレートが低い!(3GSとかで動くのかな?)
- 検出精度がまだまだ!(認識してくれない事がまああります)
- create3DMatrixの初期値に、m11-m44のディクショナリを渡したい(試したけど無理だった)
- 3Dオブジェクトをオーバーレイさせたい!

*参考にした記事
OpenCVで遊ぼう!
iPhoneでOpenCVを使う方法

2011年2月21日月曜日

OpenCV 2.2のiOS向けなユニバーサルバイナリを作る


iPhoneでOpenCVを利用したい!と検索したところ

OpenCV/Using OpenCV 2.2 on iOS SDK 4.1

のようなありがたい記事がありましたので、OpenCV 2.2 を iOS向けにビルドしてみました。

まずは上記の記事内容を読んでください。

その際に、armv6/armv7/i386のバイナリをユニバーサルバイナリにしてしまえば便利なんじゃないかと思い、適当に作り上げました。pythonが必要です。

*** もっといい方法がありました ***

iOS向けのパッチが当たっていて、
OpenCV-2.2.0とniw-iphone_opencv_test-4ab0572が同じディレクトリに存在するものとします。

各アーキテクチャ向けのライブラリの作成

1) パッチファイルの保存
opencv_cmake.sh.patchをniw-iphone_opencv_test-4ab0572に保存する

2) opencv_cmake.shにパッチを当てる
patch -p1 opencv_cmake.sh << opencv_cmake.sh.patch




3) ライブラリのビルド/インストール
cd niw-iphone_opencv_test-4ab0572

mkdir build_device_armv6
cd build_device_armv6
../opencv_cmake.sh Device ../../OpenCV-2.2.0 armv6
make -j 4
make install
cd ..

mkdir build_device_armv7
cd build_device_armv7
../opencv_cmake.sh Device ../../OpenCV-2.2.0 armv7
make -j 4
make install
cd ..

mkdir build_simulator
cd build_simulator
../opencv_cmake.sh Simulator ../../OpenCV-2.2.0
make -j 4
make install
cd ..

niw-iphone_opencv_test-4ab0572/opencv_simulator
niw-iphone_opencv_test-4ab0572/opencv_device_armv6
niw-iphone_opencv_test-4ab0572/opencv_device_armv7
に、インストールされます。

ユニバーサルバイナリの作成

1) スクリプトファイルの保存
archive_libraries.pyをniw-iphone_opencv_test-4ab0572に保存します

2) ユニバーサルバイナリの作成
mkdir opencv_universal
python archive_libraries.py

niw-iphone_opencv_test-4ab0572/opencv_universal に ユニバーサルバイナリとなったOpenCVが出来上がってます。

2011年2月3日木曜日

TotalFinderのタブ移動をキーボードで!


TotalFinderはFinderをタブ化してくれるのですが、
タブの移動するキーボードショートカットがデフォルトではちょっと面倒なので、
SafariStandっぽくします。

システム環境設定のキーボードからFinderのキーボードショートカット
を登録するだけの簡単なお仕事です。


メニュータイトル:前のタブを選択 キーボードショートカット:^, (control + ,)
メニュータイトル:次のタブを選択 キーボードショートカット:^. (control + .)

で登録しておくとSafariStandっぽくなります。
ちなみに、Chromeも同じように登録してます!

TotalFinderをBetterTouchToolでより便利にする


MacのFinderをいい感じに拡張してくれるTotalFinderというツールを購入しました。

Finderをタブ化したり、デュアルモードで2つのフォルダを同時に表示したりと便利です。

なかでも、[バイザー]という、キーボードショートカットでTotalFinderをいつでも呼び出せる機能が便利なんです。

どうせなら、トラックパッドのジェスチャで呼び出せたらもっと便利なんじゃないかということで、BetterTouchToolの出番です。

まずは、TotalFinderでバイザーを有効にしておきます。

TotalFinderをインストールすると、Finderの環境設定にTotalFinderの設定項目が現れます。
ここで、バイザーを有効にします。ホットキーの設定はお好みで。


BetterTouchToolをインストールして、設定をします。
バイザーのホットキーをお好みのジェスチャで登録すれば、ほら便利に。