トップ «前の日記(2012-05-08) 最新 次の日記(2012-05-12)» 編集

Cocoa練習帳

iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど

2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|

2012-05-11 [iOS]CoreAnimation (レイヤ)

毎度、知らない事を題材にしているので内容に自信はないのだが、今回は、特に自信がない。理解していない部分があるが、前に進む為に挑戦してみる。

今まで著者は、主に通常のビューに対する描画を扱ってきたが、今回はレイヤを使った描画に挑戦だ。

生成した画像やレイヤを管理する為のプロパティを用意した。

@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];
    }
}

実行。

layer

_ ソースコード

GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/ios/CoreAnimation - GitHub

_ 関連情報

Core Animation for Mac OS X and the iPhone
Creating Compelling Dynamic User Interfaces
Core Animationプログラミングガイド
アニメーションのタイプとタイミング
iOS Developer Libraryの翻訳文書だ。
15歳からはじめるiPhoneわくわくゲームプログラミング教室
分かりやすく無駄がない説明。
OpenGLの神髄
CoreAnimatonの理解の助けになった。
iPhoneソーシャルゲーム開発
理解不足の箇所があるので参考になった。
Core Animation for Max OS X and the iPhone
Creating Compelling Dynamic User Interfaces

トップ «前の日記(2012-05-08) 最新 次の日記(2012-05-12)» 編集