2010年3月27日土曜日

iPhoneアプリでカメラからの入力をUIImagePickerControllerを使ってAR的に表示する2つの方法(※注 一つは禁断かも)

iPhoneアプリでカメラからの入力を表示するするにはUIImagePickerControllerを使うが、2つ方法あることがわかった。

モーダルで表示する

一つはUIViewController内でモーダルで表示する方法。これは「iPhone アプリケーションプログラミングガイド」(PDF)のP186に載っている基本の方法だ。

- (IBAction)onTouchUpInsideBtnShowCameraInput {
 UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
 ipc.sourceType = UIImagePickerControllerSourceTypeCamera;
 ipc.showsCameraControls = NO;
 [self presentModalViewController:ipc animated:NO];
}


この方法の問題の少なくとも一つは、モーダルのため必要なインターフェースがすべて隠れてしまうことにある。

インターフェース本体のUIViewをUIImagePickerController.cameraOverlayViewにセットすることでカメラ入力の上に必要なインターフェースを表示することができるが、UIViewControllerで読み込まれたviewをそのまま表示したい場合などには都合がよろしくない。

特に、元のUIViewControllerで管理していたデバイスの回転時の処理などがまったく無効になったりする。UIImagePickerControllerをモーダルで表示するということは、コントロールがUIImagePickerControllerに移るということなので当たり前だ。

では、UIImagePickerControllerを継承して独自のクラスを作ればいいじゃないか、というとそうでもないらしい。UIImagePickerController Class Referenceにはこうある。

Important: The UIImagePickerController class supports portrait mode only. This class is intended to be used as-is and does not support subclassing.・・・

つまり「サブクラス化はするな」と。


UIImagePickerController.viewをUIWindowに直接追加

調べると、アプリケーションのUIApplicationDelegate.applicationDidFinishLaunching()でUIImagePickerController.viewをUIWindowに直接追加する方法があるとわかった。
btobits Blog >> Camera as background using UIImagePickerController

- (void)applicationDidFinishLaunching:(UIApplication *)application {    
    
 NSLog(@"applicationDidFinishLaunching()");
 
 UIImagePickerController *ipc = [[[UIImagePickerController alloc] init] autorelease];
 ipc.sourceType = UIImagePickerControllerSourceTypeCamera;
 ipc.showsCameraControls = NO;
 
 [window addSubview:ipc.view];
 [window addSubview:viewController.view];
 [window makeKeyAndVisible];
 
}

こうすると、UIWindow上ではカメラの入力が下になり、viewControllerのviewが上になり、UIImagePickerControllerをモーダルで表示しているわけではないのでviewControllerの制御は保たれる。つまり、回転なども検知できる。

ただし、カメラ入力はviewControllerの制御下にはないので回転しない。回転させるためにはUIImagePickerController.cameraViewTransformが使えそうだが、試してはいない。

追記:試してみた。イケた。
琴線探査: iPhoneアプリでUIImagePickerControllerによるカメラ入力の表示を回転できるのか?


さらに実験した。同じ方法をUIViewController.viewDidLoad()でやったらダメなのか?ダメだねぇ。

[self.view insertSubview:imagePickerController.view atIndex:0];
ナビゲーションバーみたいのが出たが、カメラ入力が表示されず

[self.view.window insertSubview:imagePickerController.view atIndex:0];
[self.view.superview insertSubview:imagePickerController.view atIndex:0];
[sharedApplication.keyWindow insertSubview:imagePickerController.view atIndex:0];
全部真っ黒。

原因は不明。


この方法で一つ気にかかることがある。先程のリファレンスの注意書きには続きがある。

・・・The view hierarchy for this class is private and must not be modified, with one exception. In iPhone OS 3.1 and later, you can assign a custom view to the cameraOverlayView property and use that view to present additional information or manage the interactions between the camera interface and your code.

つまり「UIImagePickerControllerのview階層はプライベートなものなので変更するな」と。

さらに、上の「btobis Blog」の記事には次のようなコメントが!

Have you had your project of this kind of code to the App Store? Calling:
[window addSubview:[uip view]];
may be rejected by Apple. I have a similar project, but rejected:・・・

つまり「このコードを使うと承認許可がおりないかもしれない。自分は却下されたけど、君はどうだった?」と。

単にviewを取得してウインドウに追加しているだけだと思うのだが、これでも違反なのか?単なるコード上のテクニックじゃないのか?

実際にできるのにあれもダメ〜これもダメ〜じゃどうにもなりまへんわな。別に倫理的に違反してるワケじゃなし。何が悪いのかサッパリわからんです。ハイ。

まぁ、出してみないと分からないけど。Yeah, I'll give it a shot! やってみるさ。


ところで、「btobis Blog」に一言ありがとうを言いたくて、コメントしようとしたら承認のために「sum 2 to 5」を入力してよ、とある。

これは「2+3+4+5=14」かな?と思ったら「2+5=7」という事らしい。「5に対して2を合計せよ」ということだったのか。

ひとつひとつ、勉強勉強!