さて、前回は画像の名称変更を可能にしました。今回からは「画像の対称処理(シンメトリー処理)」の解説に突入します。画像を直接操作するために、順次CoreGraphicsやQuartzCore Frameworkの話が出てきます。
iPhoneアプリで何らかの描画をする(ペンを使う)場合には、先んじて描画先(ホワイトボード)を用意しなくてはいけません。その土台となるのはウィンドウ(UIWindow)なのですが、Macアプリの場合とは異なり、通常のiPhoneアプリではウィンドウは1つ(キーウィンドウと呼ぶ)しか用意されません(複数用意してもOKです...)。iPhoneアプリの主役は、ウィンドウ上に配置されるビュー(UIViewクラス)と、それを制御しているビューコントローラ(UIViewControllerクラス)のペアと言うことになります。
例えば本アプリでは、画像ライブラリーから取り込んだ画像を表示するのために、ビューコントローラであるImageViewControllerクラスを用意しました。このnibファイルをInterface Builderで編集する時に、下部のツールバー(UIToolBar)を除いた領域いっぱいにUIImageViewを配置しました。このビューが画像表示用のホワイトボードとして機能しているわけです。

UIViewは、その上で画像や図形の描画が行えるだけではなく、ユーザからのタッチイベント(マルチタッチも可能)を受け取ることも可能な「矩形領域」です。iPhoneアプリで利用する多くのユーザインターフェースやコントロールも、このUIViewクラスを継承しています。そう言う意味では「ビューとビューコントローラのペアを制するものがiPhoneアプリを制する」と言っても過言ではないでしょう(笑)。そこで、実際の描画APIを使いこなす前に、まずはこの両者についてもう一度おさらいをしておきたいと思います。
UIViewクラスには多数のプロパティが用意されており、それに適切な値を代入することでビューの表示状態をダイナミックに変化させることが可能です。以下は、プロパティのほんの一例です。詳細はUIView.hを参照してみてください。
@property(nonatomic) CGRect frame; // 親ビューに対する表示枠
@property(nonatomic) CGRect bounds; // ローカル座標矩形枠
@property(nonatomic) CGPoint center; // 親ビューに対する中心位置
@property(nonatomic) CGAffineTransform transform; // 表示用の変換行列
@property(nonatomic,retain)UIColor *backgroundColor; // ビュー背景色
@property(nonatomic) CGFloat alpha; // アルファ値(透明度)
例えば、centerプロパティの値(CGPoint)の(x,y)値を変更すれば、ビューは即座に新しい位置に移動します。こうしたビューは、親ビュー(スーパービュー)に複数貼り付けて階層化することで、さらに応用範囲を広げることが出来ます。例えば、view1とview2という2つのビューがあり、view1上にvie2を配置したい場合には、addSubview:メソッドを使います。この場合、view1がview2のスーバービューとなりview2はview1のサブビュー(子ビュー)となります。
[view1 ddSubview:view2]; // view1上にview2を配置する
これで、view1が移動すればview2も一緒に移動します。ペイントアプリにおけるグループ化のようなものです。 この時、view1のどの位置にview2を貼り付けるかを保持しているのがview2のframeプロパティです。また、逆にview1側のframe(矩形枠)が拡大や縮小されれば、以下のautoresizingMaskプロパティに保持されているルールに従いview2も再配置されます。
@property(nonatomic) UIViewAutoresizing autoresizingMask; // リサイズルール
このUIViewAutoresizingはマスク用のビット値として以下のように定義されています。
enum {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
typedef NSUInteger UIViewAutoresizing;
Interface Buildreでは、このautoresizingMaskプロパティをビジュアルを見ながら設定することができます。

右側の白い領域がスーパービューで赤い領域がサブビューを表しています。また、左側の2つの赤い矢印と4つのバーのON/OFFが、上記マスクビット値のON/OFFに一致しています。例えば、スーパービューとサブビューのサイズ比をそのまま保ちながらビュー全体を拡大するには、すべてのビットをONにします。赤い矢印やバーをON/OFFし、スーパービューのサイズ変更でサブビューの位置やサイズがどう変化するのかを一度確認してみてください。
逆に、view1からview2を外す場合にはremoveFromSuperviewメソッドを利用します。この処理ではスパービューから外されるだけでなく、view2にreleaseメッセージが送られます。また同時に、view2に配置してあるサブビュー(この場合はview1の孫ビューにあたる)にも同様にreleaseが送られますのでご注意ください。
[view2 removeFromSuperview]; // スーパービューからview2を外す
では、すべてのビューの大元となる親玉ビューは、どのように用意するのでしょうか?実はiPhoneの場合にはウィンドウ(UIWindow)もビュー(UIView)から継承されたクラスとなっています(Macの場合は違う)。ですから、まず最初にすべてのビューの土台となるウィンドウをひとつ作ります。
本アプリでは、nibファイルのMainWindow.xibにこのウィンドウが用意されており、これをSymmetryAppDelegateクラス(アプリケーションデリゲート)からIBOutletとして参照します。続いて最初に使うビューコントローラを用意します。本アプリでは、複数のビューコントローラを切り替えるためにUINavigationControllerを用いますが、それが相当します。これらはすべてMainWindow.xibにまとめられています。
ビューコントローラが制御するビューは、UIViewControllerクラスのviewプロパティとして参照できます。
@property(nonatomic,retain) UIView *view; // コントローラが制御するビュー
Interface Builderでビューコントローラを作成する場合、このviewプロパティにすべての作業用ビューの大元となるビューをリンクしておきます。 そうすれば、後はこのビューの制御はビューコントローラが引き受けてくれますので、それに配置されたサブビューも同様に扱われることになります。

ここまできたら、アプリケーションデリゲートのapplicationDidFinishLaunching:の中でUINavigationControllerが制御するビューをウィンドウに配置し、最後にウィンドウをキーウィンドウとすることで、ホワイトボードの土台作りは無事完了です。
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
ところが、本アプリではホワイトボード作るためにもう一段階の工程が必要となります。MainWindow.xibのNavigatinoControllerオブジェクトには、それにより最初に呼ばれるビューコントローラ(RootViewController)が登録されています。

つまりRootViewControllerが自動的に呼び出され、そのviewプロパティに設定されているビューがナビゲーションコントローラが制御しているビューの代わりに配置されるわけです。本アプリでは、起動時に表示されるのはRootViewControllerのviewにリンクされているテーブルビュー(UITableView)となります。これでやっとアプリの初期画面が現れることになります。RootViewControllerとそれにリンクされたテーブルビューについては、nibファイルであるRootViewController.xibに保存されています。

次回は「ペン」の話に移る前に、もう少し「ホワイトボード」の方を解説をしたいと思います。UIImageViewで画像を表示する場合の注意点や、QuartzCore(CoreAnimation)の利用などについて解説してみたいと思います。