Objective-C
iOS

タイル状のUIViewを動かしてみる

More than 5 years have passed since last update.

Letterpressという英単語陣取りゲームがおもしろいです。

こんな風な「タイルのドラッグ移動」をやったこと無かったので試し書きしてみました。


ZEViewController


#import "ZEViewController.h"
#import <QuartzCore/QuartzCore.h> // layer.shadowXXXを使うために。

@interface ZEViewController ()

@end

@implementation ZEViewController

- (void)viewDidLoad
{
[super viewDidLoad];

// 25個のUILabelを作る
NSMutableArray *tiles = [NSMutableArray array];
for( int i=0; i<25; i++ ){
float tileSize = self.view.bounds.size.width/5;
int indexX = i%5; // 横方向 0-4
int indexY = (int)i/5; // 縦方向 0-4
float centerX = tileSize*indexX+(tileSize/2);
float centerY = tileSize*indexY+(tileSize/2);

UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0,0, tileSize,tileSize)];
label.center=CGPointMake(centerX,centerY);
label.textAlignment=NSTextAlignmentCenter;
label.text=[NSString stringWithFormat:@"%d",i];
if( i%2 == 0 ){
label.backgroundColor = [UIColor whiteColor];
}else{
label.backgroundColor = [UIColor grayColor];
}
[tiles addObject:label];
[self.view addSubview:label];

// ホールドした際の挙動
label.userInteractionEnabled = YES;
UIPanGestureRecognizer* panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
[label addGestureRecognizer:panGesture];

}
//
}
- (void) handlePanGesture:(UIPanGestureRecognizer*) sender {
UIPanGestureRecognizer* pan = (UIPanGestureRecognizer*) sender;
UILabel *label = (UILabel *)pan.view;
CGPoint location = [pan translationInView:label];
NSLog(@"pan x=%f, y=%f", location.x, location.y);
if ([sender state] == UIGestureRecognizerStateEnded){
// 指を放したとき
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
// 元の場所に移動
int i = [label.text intValue];
float tileSize = self.view.bounds.size.width/5;
int indexX = i%5; // 横方向 0-4
int indexY = (int)i/5; // 縦方向 0-4
float centerX = tileSize*indexX+(tileSize/2);
float centerY = tileSize*indexY+(tileSize/2);
label.center = CGPointMake(centerX,centerY);
// 影を隠す
label.clipsToBounds=YES;
// 元のサイズに戻す
label.transform = CGAffineTransformIdentity;
[UIView commitAnimations];

}else{
// 前面に持ってくる
[self.view bringSubviewToFront:label];
// ちょっと大きくする&傾ける
label.transform = CGAffineTransformMakeScale(1.3, 1.3);
// label.transform = CGAffineTransformMakeRotation(M_PI*10.0/360.0);
// ↑ここをコメントアウトすると、拡大しなくなる
// 影を付ける
label.clipsToBounds=NO;
CALayer *layer = label.layer;
layer.shadowRadius = 3;
layer.shadowColor = [UIColor blackColor].CGColor;
layer.shadowOpacity = 0.5;
layer.shadowOffset = CGSizeMake(10, 10);
// めちゃくちゃ速くなるらしい方法
// http://7gano.tumblr.com/post/4379956470/calayer-shadow
// layer.shadowPath = [UIBezierPath bezierPathWithRect:self.bounds].CGPath;
// UIViewを移動
double x = sender.view.center.x + location.x;
double y = sender.view.center.y + location.y;
sender.view.center=CGPointMake(x, y);
[pan setTranslation:CGPointZero inView:label];
}
}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

@end



  • layer.shadowXXXをそのまま使うと遅いらしい。このサンプル程度だと違いは分からない。

  • -label.transformに複数の値を渡していて、後の値で上書きしているように見えてるけど、setterの中で値を個別に持っていれば問題ないのだろう、けど紛らわしい。- ここ間違い。後の値で上書きされている。

youtube