2010年4月29日木曜日

iPadアプリに挑戦中

運良くiPadを輸入して手に入れることができましたので、現在iPadアプリの作成にとりかかっています。最初はiPhoneと対して変わりあるまいと思って作っていたのですが、実機で動かしてみると様々な違いや問題が分かってきました。


■今作っている物とか課題とか

現在作っているのはiPad用の紙のノートです。



数年前からシステム手帳を持ち歩いていたのですが、実際スケジューリング等はすべてiPhoneで行っていました。それでも紙を手放せなかった唯一の理由がアイディア出しです。アナログ人間な物で、手で紙に書き付けないとアイディアが出てこないのです。iPhoneのスクリーンは明らかに小さすぎて手書きには不向きでした。

そこでiPadの大きくなった液晶を使えば紙の代わりができるのではないかと思って早速試して見ました。

ペンの色を4色、太さを4種類用意しています。二本指で左右にスワイプするとページをめくることができます。デバイスを横向きにすると、二ページ見開きの状態にすることができます。この見開きのままでも線を書いたりページをめくったりできます。



できるかぎり実際の紙に近づけたかったため、UIを一切排除しています。


■Gesture Recognizer

ページング処理やペン選択ツールの表示にはスワイプジェスチャを使用していますが、今回このジェスチャを実装するためiPhone OS 3.2より新しく搭載された UIGestureRecognizer というクラスを使用してみました。このクラスを使えば各種ジェスチャを自動的に認識してくれるので、自分でいちいちtapの位置を拾って前回のtapとの差分を検出し・・・ということをしなくても済むようになります。

// Add gesture recognizer to the paper view
UISwipeGestureRecognizer *toolPopoverGestureRecognizer = [[[UISwipeGestureRecognizer alloc] initWithTarget:self
action:@selector(handleToolPopover:)] autorelease];
toolPopoverGestureRecognizer.numberOfTouchesRequired = 2;
toolPopoverGestureRecognizer.direction = UISwipeGestureRecognizerDirectionDown | UISwipeGestureRecognizerDirectionUp;
[self.bookView addGestureRecognizer:toolPopoverGestureRecognizer];
しかしながらいくつか問題が。まず認識精度がそれほどよくないです。特に複数指のスワイプに関しては自分で実装した方が精度が出ると思います。また、ジェスチャは通常のタップとは別に検出されているようなので、二本指でタップしてジェスチャしたときには通常の線描画を切るような処理を含めないと、ジェスチャするたびに線が画面に増えてイライラします。


■他のお絵かきアプリのUI

予想通りというか、ふたを開けてみれば他にもたくさんのドロー系アプリがApp Storeにリリースされていたので、それらのUIを見て研究してみる事にしました。

Adobe ideas for iPad



二本指ドラッグでスクロール、ピンチ操作で拡大縮小。一本指で描画中に二本目が触れると即座に描画をキャンセルしてくれるため、誤ってキャンバスに線が増えてしまうということはありません。よく考えられています。

常に左横にツールバーが表示されているようになっています。ツールバーを置くのは邪魔だろうと思っていたのですが、キャンバスの拡大縮小や移動が自由にできればほとんど邪魔にはならないことがわかりました。むしろすぐアクセスできて便利です。

Autodesk SketchBook Pro



こちらも二本指ドラッグでスクロール、ピンチ操作で拡大縮小。一本指で描画中に二本目が触れると即座に描画をキャンセルしてくれるところも全く同じです。

ツールバーを表示するには、画面中央下の小さなポッチをタップするか、または指三本で画面にタップ。この方が画面を広く使えて嬉しい・・・と思っていたのですが、実際に試してみると意外とイライラします。三本指というのが直感的ではないのかもしれません。このへんは人によるのかもしれませんが、私は常にツールバーが表示されている方がスムーズに操作できました。

Penultimate



iWorkと非常に良く似た作りになっていて、しかも操作系はシンプルです。ジェスチャは一切なく、ボタンはツールバーとして常に表示。それはまったく問題ないのですが、画面がスクロールできず拡大縮小もないため、非常に画面が狭く感じ書きづらいです。いくらiPadが大画面とはいえ、ペン先が通常のペンに比べて太い(私が好んで使うペンは0.4mmですが、iPad上の指は10mmぐらい幅があるので、およそ25倍も大きい)ため、せいぜい数文字しか綺麗に書けません。

その他特筆として、ペンの書き味が素晴らしいです。描画速度が速く非常に追従性がよい。すらすら書けます。


■お絵かきアプリのUIまとめ

いくつか使ってみて、さらには自分でも作ってみて感じたのが以下のようなこと。
  • 紙ではなくてホワイトボードのメタファとして使用するとうまくいく
  • 拡大・縮小・スクロールは絶対必須 無いとアプリとして成立しない
  • ジェスチャを使ってメニューを出すのは思ったよりも効果的ではない
  • 書き味はや動作速度は大事、使っていて楽しくなる
まず一番目。ペン先が太く、消しゴム削除がたやすく、アンドゥリドゥもできるので、書いている間隔がホワイトボードに近い気がします。そのため紙ではなくてホワイトボードだと思って実装するとよさそうです。

二番目。ペン先がやたら太いわりには画面サイズが1024x768しかないので、拡大縮小スクロールできないと話になりません。逆にこれができれば事実上キャンバスサイズは無限大にできるわけで、デバイスサイズ以上の活躍をしてくれます。

三番目。ジェスチャ自体は上手く使えば非常に有効です。たとえばアンドゥリドゥなどの操作はジェスチャで行う方が直感的でした。しかしメニューは常時画面に表示していた方が良い気がします。

最後、四番目。動作速度は極めて大事だと感じました。特に描画速度は最も大事で、線を引くのがもっさりしてしまうとそのせいで綺麗な曲線にならなかったり、単純にイライラしたりします。実物のホワイトボードに書くぐらいの速さで描画ができるように目指したいです。

2010年4月1日木曜日

UIBarButtonItem の見た目を画像にしたいときのテクニック

iPhoneアプリでよく使われる、ナビゲーションバーに配置するボタン UIBarButtonItem の見た目を完全に画像にする時のテクニックです。
参考にしたページはこちら。
http://discussions.apple.com/thread.jspa?threadID=1505647
http://www.iphonedevsdk.com/forum/iphone-sdk-development/13809-uibarbuttonitem-customview-action.html
http://discussions.apple.com/thread.jspa?threadID=1546506&tstart=60


■作戦1:initWithImage
てか、 UIBarButtonItem には initWithImage あるからそれでいいんじゃないか、と思ってさっそく以下のコードを書いてみました。
UIBarButtonItem* buttonItem = [[UIBarButtonItem alloc]
initWithImage:[UIImage imageNamed:@"appstore.png"]
style:UIBarButtonItemStyleBordered
target:self
action:@selector(appstoreAction)];
self.navigationItem.rightBarButtonItem = buttonItem;
するとあら不思議、確かに画像は表示されたのですが、画像の周りにいつものボタンの枠が表示されてしまっています。styleを変更してもうまくいきません。どうやらこれはあくまでいつものボタンの中に画像を表示するだけのメソッドで、ボタンの見た目そのものをそっくりそのまま画像に入れ替える(ボタン画像を作ってさしかえる)用途には使えないようです。


■作戦2:initWithCustomViewとUIImageViewを組み合わせる
それなら initWithCustomView を使って画像を表示させてみましょう。
UIImageView* customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"appstore.png"]];
customView.userInteractionEnabled = YES;
UIBarButtonItem* buttonItem = [[UIBarButtonItem alloc] initWithCustomView:customView];
buttonItem.target = self;
buttonItem.action = @selector(appstoreAction);
self.navigationItem.rightBarButtonItem = buttonItem;
この方法だと、ボタンの縁が消えてappstore.pngがそのまま表示され、見た目は臨み通りの状態に表示させることができたのですが、今度は別の問題が。なんとボタンを押してもアクションが呼びだされません。海外のフォーラムでも同じような問題を抱えている投稿が見受けられました。


■作戦3:initWithCustomViewとUIButtonを組み合わせる
それならということで、カスタムビューを UIImageView から UIButton に変更してみることにしました。
UIButton *customView = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 95, 33)];
[customView setBackgroundImage:[UIImage imageNamed:@"appstore.png"]
forState:UIControlStateNormal];
[customView addTarget:self action:@selector(appstoreAction) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem* buttonItem = [[UIBarButtonItem alloc] initWithCustomView:customView];
self.navigationItem.rightBarButtonItem = buttonItem;
ビルドして試してみると、見た目は作戦2と同様に綺麗に表示され、さらにタップするときちんとアクションが実行されるようになりました!

2010年3月31日水曜日

Flash の埋め込みパラメータ wmode で発生したトラブルいろいろ

Flashまわりの仕事をしていて wmode パラメータで躓いたのでメモ。


■事の発端
開発機のMac上では正常に動作していたコンテンツが、Windows機のFirefoxでテストを開始したとたん以下のような症状に見舞われてしまいました。
  • TextFieldにフォーカスを合わせて日本語をタイプするとTextFieldとは全然違うとんちんかんな位置に入力中の文字列が表示される
  • しかも入力した日本語が文字化けする
ちょっと調べてみて、どうやら wmode パラメータが悪さをしているのではないかということが分かりました。
http://www.326studio.net/blog/2009/10/firefox.html
http://fukata.org/2009/11/29/1905/

ということで早速 wmode パラメータを消してみたところ上手く動作しました。


■そのときのSkype上での会話(一部改変)
登場する皆様ご紹介
 akisute: そもそもテキストボックス内に入力が表示されないのが普通な気がしてきた
easy: あいうえお=0B0D0F0H
akisute: http://www.326studio.net/blog/2009/10/firefox.html
akisute: こいつだな
wozozo: なんでその指定してたんだっけ
AE35: > htmlにswfファイルを呼び出すときにwmodeの指定でtransparent,opaqueの指定をするとこの現象が起きます。
akisute: http://fukata.org/2009/11/29/1905/
akisute: ということでをぞぞんよろしくお願いします
wozozo:
{
id : 'externalswf',
quality : 'high',
wmode : 'transparent',
allowScriptAccess : 'always',
width: 100,
height: 100,
flashvars: 'abesi hidebu tawaba'
});
wozozo: いまこうなってます。
wozozo: wmodeごと削除?
feiz: お、そこは以前のプロジェクトでぶつかった問題ですね
feiz: wmode=transparentを付けると
feiz: flash上にhtmlのダイアログを表示したりしたときにflashが上に出てしまう問題が回避できます
feiz: ただし日本語が化けます。
wozozo: e
wozozo: じゃあこれ消していいの
feiz: 両方いっぺんに回避する方法はあったっけ・・・
wozozo: でもいま
feiz: ああ、無いんだった
wozozo: flashの上にhtmlを表示するときには、
wozozo: embedされてるdivごと hide してる
feiz: あ、それが正しいはず
feiz: 以前のプロジェクトでもそうした。
wozozo: naru
wozozo: じゃあ消す。
feiz: ちなみに二つの問題は両方とも特定ブラウザ限がついてたはず。
feiz: どうでもいいけど。
akisute: それはすごい面白いネタなので
akisute: メモってBlogる


■さらに調査

調べれば調べるほどこの wmode には問題だのバグだのが山盛りだと言うことが分かって驚愕。
http://blog.graffiti-web.org/archives/2006/04/wmode.html
http://chabudai.org/blog/?p=34
http://d.hatena.ne.jp/jedisystemer/20090227/1235754536
http://3ping.org/2004/05/15/1441
Flash Player 10では修正されているらしいのですが、上記のバグはFlash Player 10で発生してますし、うーん。これは触らぬ神にたたり無しですね。


■結論
wmode は指定しないようにしましょう、と。Flash Player 9以下ではIEでフレームレートが落ちる問題がありますが、そもそも9を使っている人も少なくなりましたし問題ないと思います。