iPhoneおじぎパネル

タップでパネルがおじぎ。そんな感じのiPhoneアプリのサンプルコードを描いてみます。タップした周りのパネルもウェーブみたいに連鎖で動くようにしています。正方形の周りにできる、正方形の位置を計算するいい方法があればもっとシンプルに書ける気がします。


サンプルを動画で確認

サンプルコード

#import “ViewController.h”

@interface ColorPanel : CALayer

@property int number;

@end

@implementation ColorPanel

@end

@interface ViewController ()

@end

@implementation ViewController

– (void)viewDidLoad

{

    [super viewDidLoad];

    

    [self createPanels];

}

– (void)createPanels

{

    for (int i=0; i<160; i++) {

        ColorPanel *l = [ColorPanel layer];

        l.number = i;

        float x = (i % 10) * 30 + 15;

        float y = (i / 10) * 30 + 30;

        l.frame = CGRectMake(x, y, 25, 25);

        l.backgroundColor = [UIColor colorWithHue:(arc4random() % 10) * 0.1 saturation:0.8 brightness:0.8 alpha:1.0].CGColor;

        l.shadowOffset = CGSizeMake(0, 0);

        l.shadowOpacity = 0.3;

        l.shadowRadius = 5.0;

        [self.view.layer addSublayer:l];

    }

}

– (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

    CGPoint p = [[touches anyObject] locationInView:self.view];

    ColorPanel *selected = (ColorPanel*)[self.view.layer hitTest:p];

    

    [self flipAroundAtCenter:selected.position fromCenterNumber:0];

}

– (void)flip:(CALayer*)layer

{

    if ([layer isKindOfClass:[ColorPanel class]]) {

        CABasicAnimation *flip = [CABasicAnimation animationWithKeyPath:@”transform.rotation.x”];

        flip.toValue = @(M_PI * 0.4);

        flip.fromValue = @(0);

        flip.repeatCount = 4;

        flip.duration = 0.5;

        flip.autoreverses = YES;

        [layer addAnimation:flip forKey:@”flip”];

    }

}

– (void)flipAroundAtCenter:(CGPoint)center fromCenterNumber:(int)fromCenter

{

    if (fromCenter < 2) {

        double delayInSeconds = 0.2;

        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));

        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

            [self flipAroundAtCenter:center fromCenterNumber:fromCenter + 1];

        });

    }

    

    if (fromCenter == 0) {

        CALayer *l = [self.view.layer hitTest:center];

        [self flip:l];

        return;

    }

    

    for (int i=0; i<fromCenter; i++) {

        // right

        for (int j=0; j<2; j++) {

            float y = center.y + (j ? i * 30.0 : – i * 30.0);

            CGPoint p = CGPointMake(center.x + fromCenter * 30.0, y);

            CALayer *l = [self.view.layer hitTest:p];

            [self flip:l];

        }

        

        // left

        for (int j=0; j<2; j++) {

            float y = center.y + (j ? i * 30.0 : – i * 30.0);

            CGPoint p = CGPointMake(center.x – fromCenter * 30.0, y);

            CALayer *l = [self.view.layer hitTest:p];

            [self flip:l];

        }

        

        // top

        for (int j=0; j<2; j++) {

            float x = center.x + (j ? i * 30.0 : – i * 30.0);

            CGPoint p = CGPointMake(x, center.y – fromCenter * 30.0);

            CALayer *l = [self.view.layer hitTest:p];

            [self flip:l];

        }

        

        // bottom

        for (int j=0; j<2; j++) {

            float x = center.x + (j ? i * 30.0 : – i * 30.0);

            CGPoint p = CGPointMake(x, center.y + fromCenter * 30.0);

            CALayer *l = [self.view.layer hitTest:p];

            [self flip:l];

        }

    }

    

    // corner

    CGPoint corners[] = {

        CGPointMake(center.x + 30 * fromCenter, center.y + 30 * fromCenter),

        CGPointMake(center.x30 * fromCenter, center.y + 30 * fromCenter),

        CGPointMake(center.x + 30 * fromCenter, center.y30 * fromCenter),

        CGPointMake(center.x30 * fromCenter, center.y30 * fromCenter),

    };

    for (int i=0; i<4; i++) {

        CALayer *l = [self.view.layer hitTest:corners[i]];

        [self flip:l];

    }

}

– (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

@end