iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど
毎度、知らない事を題材にしているので内容に自信はないのだが、今回は、特に自信がない。理解していない部分があるが、前に進む為に挑戦してみる。
今まで著者は、主に通常のビューに対する描画を扱ってきたが、今回はレイヤを使った描画に挑戦だ。
生成した画像やレイヤを管理する為のプロパティを用意した。
@interface LayerViewController : UIViewController
@property (strong, nonatomic) UIImage *backgroundImage;
@property (strong, nonatomic) UIImage *frontImage;
@property (strong, nonatomic) UIImage *rearImage;
@property (strong, nonatomic) CALayer *cardLayer;
@property (strong, nonatomic) CALayer *frontLayer;
@property (strong, nonatomic) CALayer *rearLayer;
@end
画面が表示される前に、背景とトランプ・カードのレイヤを追加。
@implementation LayerViewController
@synthesize backgroundImage = _backgroundImage;
@synthesize frontImage = _frontImage;
@synthesize rearImage = _rearImage;
@synthesize cardLayer = _cardLayer;
@synthesize frontLayer = _frontLayer;
@synthesize rearLayer = _rearLayer;
...
- (void)viewWillAppear:(BOOL)animated
{
DBGMSG(@"%s", __func__);
/* 背景レイヤに背景画像を設定 */
self.backgroundImage = [UIImage imageNamed:@"background.png"];
self.view.layer.contents = (id)self.backgroundImage.CGImage;
/* カードの表と裏の画像を用意 */
self.frontImage = [UIImage imageNamed:@"front.png"];
self.rearImage = [UIImage imageNamed:@"rear.png"];
/* 表面レイヤと裏面レイヤを一塊のカードとして扱う為のレイヤ */
CATransform3D perspactive = CATransform3DIdentity;
perspactive.m34 = -1.0 / 100.0; /* 遠近感をつける */
self.cardLayer = [CALayer layer];
self.cardLayer.bounds = CGRectMake(0.0, 0.0, 100.0, 100.0);
self.cardLayer.position = CGPointMake(100.0, 100.0);
self.cardLayer.sublayerTransform = perspactive;
self.cardLayer.name = @"card";
/* 表面レイヤ */
self.frontLayer = [CALayer layer];
self.frontLayer.bounds = CGRectMake(0.0, 0.0, 100.0, 100.0);
self.frontLayer.position = CGPointMake(50.0, 50.0);
self.frontLayer.contents = (id)self.frontImage.CGImage;
self.frontLayer.zPosition = 1; /* 表面レイヤを手前に配置 */
self.frontLayer.name = @"front";
/* 裏面レイヤ */
self.rearLayer = [CALayer layer];
self.rearLayer.bounds = CGRectMake(0.0, 0.0, 100.0, 100.0);
self.rearLayer.position = CGPointMake(50.0, 50.0);
self.rearLayer.contents = (id)self.rearImage.CGImage;
self.rearLayer.zPosition = 0;
self.rearLayer.transform = CATransform3DMakeRotation(M_PI, 0.0, 1.0, 0.0); /* 裏返す */
self.rearLayer.name = @"rear";
/* 表面レイヤと裏面レイヤをカード・レイヤのサブ・レイヤに設定 */
[self.cardLayer addSublayer:self.frontLayer];
[self.cardLayer addSublayer:self.rearLayer];
/* カード・レイヤを背景レイヤのサブ・レイヤに設定 */
[self.view.layer addSublayer:self.cardLayer];
}
...
@end
裏面のレイヤは裏返して、表面のレイヤと張り合わせている感じだ。
効率は悪いと思うが、レイヤの追加と削除の流れを確認する為、非表示になった際にレイヤを削っている。
- (void)viewDidDisappear:(BOOL)animated
{
DBGMSG(@"%s", __func__);
[self.frontLayer removeFromSuperlayer];
[self.rearLayer removeFromSuperlayer];
[self.cardLayer removeFromSuperlayer];
self.frontLayer = nil;
self.rearLayer = nil;
self.cardLayer = nil;
self.frontImage = nil;
self.rearImage = nil;
self.view.layer.contents = nil;
self.backgroundImage = nil;
}
トランプ・カードがタッチされたら反転させる。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
DBGMSG(@"%s", __func__);
UITouch *touch = [touches anyObject];
CGPoint position = [touch locationInView:self.view];
CALayer *layer = [self.view.layer hitTest:position]; /* 触ったレイヤ */
CALayer *containerLayer = layer.superlayer; /* 親レイヤ */
DBGMSG(@"layer name: %@", layer.name);
DBGMSG(@"container layer name: %@", containerLayer.name);
/* 親レイヤはカード・レイヤ? */
if ([containerLayer.name hasPrefix:@"card"]) {
DBGMSG(@"container layer is card");
containerLayer.zPosition = 10;
[CATransaction begin];
[CATransaction setAnimationDuration:1.0];
CATransform3D transform = CATransform3DIdentity;
transform.m34 = -1.0 / 100.0; /* 遠近感をつける */
/* 表に戻す */
if ([containerLayer.name hasSuffix:@"flipped"]) {
/* 裏返っていたら、名前の末尾に.flippedがついている */
transform = CATransform3DRotate(transform, 0.0, 0.0, 1.0, 0.0);
containerLayer.name = [containerLayer.name stringByDeletingPathExtension];
/* 名前の末尾の.flippedを削る */
}
/* 裏返す */
else {
transform = CATransform3DRotate(transform, - M_PI, 0.0, 1.0, 0.0);
containerLayer.name = [containerLayer.name stringByAppendingPathExtension:@"flipped"];
/* 裏返したら、名前の末尾に.flippedがつける */
}
containerLayer.sublayerTransform = transform;
[CATransaction commit];
}
}
実行。