複雑な 3D のものを構築するとき、独立した要素を整理できれば非常に便利です。たとえば、子供の腕を作成する場合、どの部分が子供の手首で、どの部分が子供の前腕で、どの部分が子供の肘で、どの部分が子供の上腕で、どの部分が子供の腕であるかを決定する必要があります。肩などを待ってください。
もちろん、各エリアは独立して移動することができます。肘を指すと、肩ではなく前腕と手が動きます。コア アニメーション レイヤを使用すると、2D ではこのような階層的な変換を簡単に行うことができますが、3D ではすべてのレイヤが子を 1 つのシーンに平坦化するため、これは不可能です (第 5 章「変換」で説明)。
CATransformLayer は、独自のコンテンツを表示できないという点でこの問題を解決します。これは、サブレイヤーをスコープできる変換がある場合にのみ実際に存在します。 CATransformLayer はサブレイヤーを平坦化しないため、私の腕の例などの階層 3D 構造の構築に使用できます。
コードを使用してアームを作成するには、かなりの量のコードが必要なので、簡単に説明します。第 5 章の立方体の例では、立方体のサンプル コードを使用する代わりに、カマラを回転することによって層の平面化の問題を解決します。サブレイヤトランスフォーム。これは非常に優れた手法ですが、シーンに 2 つの立方体が含まれている場合、この手法を使用してそれらを個別に回転することはできません。
それでは、CATransformLayer を試してみましょう。ここで最初の質問が生じます。第 5 章では、個別のレイヤーではなく複数のビューを使用してキューブを構築しました。既存のビュー階層を乱さずに、搭乗マップを持たないレイヤー内に搭乗マップ レイヤーを配置することはできません。 CATransformLayer でホストされる新しい UIView サブクラスを作成できます (+layerClass メソッドを使用)。ただし、ケースを単純化するために、ビューを使用する代わりに別のレイヤーを再作成するだけです。これは、第 5 章で行ったように立方体の表面にボタンやラベルを表示できないことを意味しますが、この機能は現在使用できません。
リスト 6.5 はコードです。第 5 章で使用したのと同じ基本ロジックを使用して立方体を配置します。ただし、前のようにキューブの面をコンテナ ビューのホスト レイヤに直接追加する代わりに、CATransformLayer にキューブの面を配置して別のキューブ オブジェクトを作成し、そのような 2 つのキューブをコンテナに配置します。立方体を区別するためにランダムに色を付けたので、区別するためにラベルや照明に頼る必要はありませんでした。図 6.5 は実行結果です。
リスト 6.5 CATransformLayer を使用して 3D レイヤー システムを組み立てる
@interface ViewController ()@property (nonatomic, weak) IBOutlet UIView *containerView; @end @implementation ViewController - (CALayer *)faceWithTransform:(CATransform3D)transform{ //create cube face layer CALayer *face = [CALayer layer]; face.frame = CGRectMake(-50, -50, 100, 100); //apply a random color CGFloat red = (rand() / (double)INT_MAX); CGFloat green = (rand() / (double)INT_MAX); CGFloat blue = (rand() / (double)INT_MAX); face.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0].CGColor; ?//apply the transform and return face.transform = transform; return face;} - (CALayer *)cubeWithTransform:(CATransform3D)transform{ //create cube layer CATransformLayer *cube = [CATransformLayer layer]; //add cube face 1 CATransform3D ct = CATransform3DMakeTranslation(0, 0, 50); [cube addSublayer:[self faceWithTransform:ct]]; //add cube face 2 ct = CATransform3DMakeTranslation(50, 0, 0); ct = CATransform3DRotate(ct, M_PI_2, 0, 1, 0); [cube addSublayer:[self faceWithTransform:ct]]; //add cube face 3 ct = CATransform3DMakeTranslation(0, -50, 0); ct = CATransform3DRotate(ct, M_PI_2, 1, 0, 0); [cube addSublayer:[self faceWithTransform:ct]]; //add cube face 4 ct = CATransform3DMakeTranslation(0, 50, 0); ct = CATransform3DRotate(ct, -M_PI_2, 1, 0, 0); [cube addSublayer:[self faceWithTransform:ct]]; //add cube face 5 ct = CATransform3DMakeTranslation(-50, 0, 0); ct = CATransform3DRotate(ct, -M_PI_2, 0, 1, 0); [cube addSublayer:[self faceWithTransform:ct]]; //add cube face 6 ct = CATransform3DMakeTranslation(0, 0, -50); ct = CATransform3DRotate(ct, M_PI, 0, 1, 0); [cube addSublayer:[self faceWithTransform:ct]]; //center the cube layer within the container CGSize containerSize = self.containerView.bounds.size; cube.position = CGPointMake(containerSize.width / 2.0, containerSize.height / 2.0); //apply the transform and return cube.transform = transform; return cube;} - (void)viewDidLoad{? [super viewDidLoad]; //set up the perspective transform CATransform3D pt = CATransform3DIdentity; pt.m34 = -1.0 / 500.0; self.containerView.layer.sublayerTransform = pt; //set up the transform for cube 1 and add it CATransform3D c1t = CATransform3DIdentity; c1t = CATransform3DTranslate(c1t, -100, 0, 0); CALayer *cube1 = [self cubeWithTransform:c1t]; [self.containerView.layer addSublayer:cube1]; //set up the transform for cube 2 and add it CATransform3D c2t = CATransform3DIdentity; c2t = CATransform3DTranslate(c2t, 100, 0, 0); c2t = CATransform3DRotate(c2t, -M_PI_4, 1, 0, 0); c2t = CATransform3DRotate(c2t, -M_PI_4, 0, 1, 0); CALayer *cube2 = [self cubeWithTransform:c2t]; [self.containerView.layer addSublayer:cube2];} @end
図 6.5 同じ視点からの異なる変換を持つ 2 つの立方体
CAGradientLayer は 2 つまたはより多くの色と滑らかなグラデーション。 Core Graphics を使用して CAGradientLayer をコピーし、そのコンテンツを通常のレイヤーのホスト グラフに描画することも可能ですが、CAGradientLayer の本当の利点は、描画にハードウェア アクセラレーションが使用されることです。
赤から青への単純な対角グラデーションから始めます (リスト 6.6 を参照)。これらのグラデーションの色は配列に配置され、colors プロパティに割り当てられます。この配列メンバーは CGColorRef 型の値 (NSObject から派生したものではない) を受け入れるため、適切なコンパイルを保証するためにブリッジ変換を使用する必要があります。
CAGradientLayer には、グラデーションの方向を決定する startPoint プロパティと endPoint プロパティもあります。これら 2 つのパラメータは単位座標系で定義されているため、左上隅の座標は {0, 0}、右下隅の座標は {1, 1} になります。コードの実行結果を図 6.6 に示します。
リスト 6.6 2 色の単純な斜めグラデーション
@interface ViewController ()@property (nonatomic, weak) IBOutlet UIView *containerView; @end @implementation ViewController - (void)viewDidLoad{ [super viewDidLoad]; //create gradient layer and add it to our container view CAGradientLayer *gradientLayer = [CAGradientLayer layer]; gradientLayer.frame = self.containerView.bounds; [self.containerView.layer addSublayer:gradientLayer]; //set gradient colors gradientLayer.colors = @[(__bridge id)[UIColor redColor].CGColor, (__bridge id)[UIColor blueColor].CGColor]; //set gradient start and end points gradientLayer.startPoint = CGPointMake(0, 0); gradientLayer.endPoint = CGPointMake(1, 1);} @end
図 6.6 CAGradientLayer の使用2色の単純な対角グラデーションを実装するには