目的
UIViewが表示する画像は、実際はプロパティlayerが管理している事を理解する。

主要クラス
UIView,CALayer

使用テンプレートプロジェクト
Window-based Application

プロジェクトの名称
Draw


サンプル実装説明


 このドリルでは「カスタムUIViewの内容部を独自に描画する」で作成したプロジェクトを拡張する。
 元々のDrawView.mのinitWithFrame:メソッドに以下を追加する。このメソッドを扱うために
QuartzCore/QuartzCore.h

 が必要。
#import <QuartzCore/QuartzCore.h>
 ・
 ・
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.layer.contentsRect = CGRectMake(0, 0, 0.5, 0.5);
}
return self;
}

 実行すると、以下のような表示となる。

$テン*シー*シー-1

 オリジナルの状態と見比べると、左上1/4の領域が表示されている。
 いったい
self.layer

 とは、なんなのか?
 答えを先に言えば、UIViewが、必ず一つ持つiPhone画面に表示するオフスクリーン画像管理クラスであるCALayerクラスまたはその継承クラスのインスタンスということになる。
 実は、UIViewのdrawRect:メソッドはiPhone画面上に描画するのではなく、このself.layerが管理しているオフスクリーンへの描画だった。
 そして
self.layer.contentsRect = CGRectMake(0, 0, 0.5, 0.5);

 とは、そのオフスクリーン画像のどの領域を抜き出して表示するかという指定になる。

$テン*シー*シー-2

 contentsRectに指定するオフスクリーンの矩形は縦長、横長にかかわらず0~1.0の範囲に正規化したものを使う。

$テン*シー*シー-3

 そのため
0, 0, 0.5, 0.5

 は画像の左上1/4の矩形を表示する指定になる。
self.layer.contentsRect = CGRectMake(0.3, 0.5, 0.5, 0.5);

 など、いろいろ値を変えて結果を確認してみて欲しい。

 次に、self.layerがdrawRect:メソッドの描画対象になっている事を確認するために以下のdrawLayer:inContext:メソッドを実装する。

- (void)drawRect:(CGRect)rect {
printf("current context %p\n", UIGraphicsGetCurrentContext());
[[UIColor blueColor] setFill];
UIRectFill(CGRectInset(self.bounds, 10, 50));
}

-(void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context
{
printf("arg layer = %p, layer = %p and context %p\n", layer, self.layer, context);
[super drawLayer:layer inContext:context];
}

 実行するとコンソール(コンソールの表示はコンソールを表示するを参照)には同じアドレスが表示されている事がわかる。
arg layer = 0x6927d30, layer = 0x6927d30 and context 0x6929370
current context 0x6929370

 UIViewにこのメソッドが実装されている事は、UIView Referenceのlayer プロパティの説明からわかる。UIViewは自身のlayerのデリゲートとしても機能している。
 ちなみにUIViewインスタンスを、他のCALayerのデリゲート(モーダルビューを表示する(2)を参照)として渡す事が禁じられている点は非常に重要。Technical Q&A QA1637も興味深い。


プロジェクト


検討

 UIResponderを継承せず、タッチイベントをレポートしない事を考えると、CALayerインスタンスはUIViewの画面描画担当インスタンスと考えることが出来る。
 また、UIViewは、必ず一つCALayerを持つが、CALayer自体はUIView同様、入れ子状態にできる。
 うまくCALayerを入れ子状にして管理すれば、効率的な表示やアニメーションが実現できることになる。
 次回のドリルでは、この入れ子になったCALayerを使ったアニメーションを学習する。