Dynamics에 대한 기본적인 구성과 사용에 대해서는 이전 블로그에서 정리를 하였고, 이번은 Dynamics를 가지고, UI를 좀더 사용자 친화적으로 꾸밀 수 있을 지 알아보겠습니다.
모든 UIKit에 물리적 성질을 추가 할 수 있는 것이 iOS7의 Dynamics 입니다.
그것을 이용해서, 초기 화면의 UILabel 들에 Dynamics를 적용해 보도록 하겠습니다.
이전에는 UIView Animation을 이용해서 하던 것을 Dynamics를 활용해서 만드는 것입니다.
버튼 밑에 설명 Label을 붙이고, 이 Label들이 모션에 의해서 흔들리도록 해보겠습니다.
아래에 사용된 이미지는 구글 이미지에서 찾은 것들로, 저작권은 전혀 저에게 있지 않습니다.( 원본은 아래에 링크를 넣었습니다.)
위 이미지에서 Travel 라벨이 그 위의 아이콘의 center와 UIAttachmentBehavior로 연결을 하고, CoreMotion으로 X,Y 값의 변화에 따라서 좌/우로 흔들리도록 UIPushBehavior를 이용했습니다.
각 컨트롤에 대해서, Property 연결 합니다.
source code
그리고, UIDynamicsAnimator, UIGravityBehavior 로 설정합니다.
각 UILabel에 대해서 UIAttachmentBehavior를 연결하고, Damping과 Frequency를 설정합니다.
이 두 값을 설정하더라도 적절하게 멈추는 것이 아니라, 자주 흔들리게 됩니다.
아래의 왼쪽이 Attachment만 적용한 것이고, 오른쪽이 UIDynamicItemBehavior로 마찰저항을 추가한 것입니다.
이제, CoreMotion을 추가해서, 기기가 좌우로 흔들릴 때 마다, PushBehavior를 추가하여, Label이 흔들리도록 하겠습니다.
먼저 CoreMotion을 추가합니다.
위에서, accelerometerData의 acceleration의 x,y 좌표 값을 가지고, Angle을 구하고, 그것을 바탕으로 PushBehavior의 Active를 YES로 입력합니다.
실제 Device에서 실행을 하면, 회전을 살짝하면, Label 들이 움직이게 됩니다.
[이미지 출처]
배경화면, 비행기, 책, 음식, 운동
참고 :
- WWDC 2013 : Getting started with UIKit Dynamics
: #206 세션으로, 다이나믹스에 대한 설명이 있음.
- UIKit Dynamics and iOS 7: Building UIKit Pong
: 다이나믹스를 이용해서, 바운싱을 예제로 설명하고 있는 곳.
- RayWenderlich의 UIKit Dynamics 강좌
모든 UIKit에 물리적 성질을 추가 할 수 있는 것이 iOS7의 Dynamics 입니다.
그것을 이용해서, 초기 화면의 UILabel 들에 Dynamics를 적용해 보도록 하겠습니다.
이전에는 UIView Animation을 이용해서 하던 것을 Dynamics를 활용해서 만드는 것입니다.
버튼 밑에 설명 Label을 붙이고, 이 Label들이 모션에 의해서 흔들리도록 해보겠습니다.
아래에 사용된 이미지는 구글 이미지에서 찾은 것들로, 저작권은 전혀 저에게 있지 않습니다.( 원본은 아래에 링크를 넣었습니다.)
위 이미지에서 Travel 라벨이 그 위의 아이콘의 center와 UIAttachmentBehavior로 연결을 하고, CoreMotion으로 X,Y 값의 변화에 따라서 좌/우로 흔들리도록 UIPushBehavior를 이용했습니다.
각 컨트롤에 대해서, Property 연결 합니다.
source code
@property (strong, nonatomic) IBOutlet UIImageView *travelImageView; @property (strong, nonatomic) IBOutlet UIImageView *bookImageView; @property (strong, nonatomic) IBOutlet UIImageView *workoutImageView; @property (strong, nonatomic) IBOutlet UIImageView *foodImageView; @property (strong, nonatomic) IBOutlet UILabel *travelLogLabel; @property (strong, nonatomic) IBOutlet UILabel *bookLogLabel; @property (strong, nonatomic) IBOutlet UILabel *foodLogLabel; @property (strong, nonatomic) IBOutlet UILabel *workoutLogLabel; @property (strong, nonatomic) UIDynamicAnimator *animator; @property (strong, nonatomic) UIGravityBehavior *gravityBehavior; @property (strong, nonatomic) UICollisionBehavior *collisionBehavior; @property (strong, nonatomic) UIPushBehavior *pushBehavior;
그리고, UIDynamicsAnimator, UIGravityBehavior 로 설정합니다.
- (void) setupDynamics { self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[self.travelLogLabel, self.bookLogLabel, self.foodLogLabel, self.workoutLogLabel]]; [self.animator addBehavior:self.gravityBehavior]; ... }
각 UILabel에 대해서 UIAttachmentBehavior를 연결하고, Damping과 Frequency를 설정합니다.
#pragma mark - Dynamics Setting - (void) setupDynamics { ... //Label들에 대해서, 마찰저항을 설정하고, 회전하지 않도록 설정 UIDynamicItemBehavior *labelItemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[self.travelLogLabel, self.bookLogLabel, self.foodLogLabel, self.workoutLogLabel]]; labelItemBehavior.resistance = 1.0f; labelItemBehavior.allowsRotation = NO; [self.animator addBehavior:labelItemBehavior]; // Travel Label에 대해서 AttchmentBehavior를 연결함. [self addAttachmentBehavior:self.travelLogLabel atPoint:CGPointMake(self.travelImageView.center.x, self.travelImageView.center.y) toAnimator:self.animator]; // Book Label에 대해서 AttachmentBehavior를 연결 [self addAttachmentBehavior:self.bookLogLabel atPoint:CGPointMake(self.bookImageView.center.x, self.bookImageView.center.y ) toAnimator:self.animator]; // Food Label에 대해서 AttachmentBehavior 연결 [self addAttachmentBehavior:self.foodLogLabel atPoint:CGPointMake(self.foodImageView.center.x, self.foodImageView.center.y ) toAnimator:self.animator]; // Workout Label에 대해서 AttachmentBehavior 연결 [self addAttachmentBehavior:self.workoutLogLabel atPoint:CGPointMake(self.workoutImageView.center.x, self.workoutImageView.center.y ) toAnimator:self.animator]; .... } - (void) addAttachmentBehavior:(UILabel *)label atPoint:(CGPoint)point toAnimator:(UIDynamicAnimator *)animator { UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:label attachedToAnchor:point]; attachment.damping = 1.0f; attachment.frequency = 100.0f; [animator addBehavior:attachment]; }
이 두 값을 설정하더라도 적절하게 멈추는 것이 아니라, 자주 흔들리게 됩니다.
아래의 왼쪽이 Attachment만 적용한 것이고, 오른쪽이 UIDynamicItemBehavior로 마찰저항을 추가한 것입니다.
이제, CoreMotion을 추가해서, 기기가 좌우로 흔들릴 때 마다, PushBehavior를 추가하여, Label이 흔들리도록 하겠습니다.
먼저 CoreMotion을 추가합니다.
@import CoreMotion; ... - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. _motionManager = [[CMMotionManager alloc] init]; [self startMonitoringAcceleration]; } ... #pragma mark - Dynamics Setting - (void) setupDynamics { ... self.pushBehavior = [[UIPushBehavior alloc] initWithItems:@[self.travelLogLabel, self.bookLogLabel, self.foodLogLabel, self.workoutLogLabel] mode:UIPushBehaviorModeInstantaneous]; //Instantaneous로 설정 self.pushBehavior.active = NO; float angle = arc4random() % 360; self.pushBehavior.angle = (angle*M_PI/180.0); self.pushBehavior.magnitude = 0.4f; [self.animator addBehavior:self.pushBehavior]; } #pragma mark - CoreMotion - (void)startMonitoringAcceleration { if (_motionManager.accelerometerAvailable) { //[_motionManager startAccelerometerUpdates]; NSLog(@"accelerometer updates on..."); [_motionManager setAccelerometerUpdateInterval:0.1f]; [_motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) { float angle = atan2f(-accelerometerData.acceleration.y, accelerometerData.acceleration.x); //NSLog(@"accelerometer:angle:%2.02f, x:%.02f, y:%.02f, z:%.02f", 180.0+angle*180.0/M_PI, accelerometerData.acceleration.x, accelerometerData.acceleration.y, accelerometerData.acceleration.z); NSLog(@"angle: %0.2f, %02.2f", angle, angle / M_PI * 180.0); if (angle > 100*M_PI/180.0) { angle = 100*M_PI/180.0; } if(angle < 80*M_PI/180.0){ angle = 80*M_PI/180.0; } self.gravityBehavior.angle = angle;// - 180.0 * M_PI / 180.0; } ]; }else{ NSLog(@"accelerometer Unavailable"); } } - (void)stopMonitoringAcceleration { if (_motionManager.accelerometerAvailable && _motionManager.accelerometerActive) { [_motionManager stopAccelerometerUpdates]; NSLog(@"accelerometer updates off..."); } } @end
위에서, accelerometerData의 acceleration의 x,y 좌표 값을 가지고, Angle을 구하고, 그것을 바탕으로 PushBehavior의 Active를 YES로 입력합니다.
실제 Device에서 실행을 하면, 회전을 살짝하면, Label 들이 움직이게 됩니다.
[이미지 출처]
배경화면, 비행기, 책, 음식, 운동
참고 :
- WWDC 2013 : Getting started with UIKit Dynamics
: #206 세션으로, 다이나믹스에 대한 설명이 있음.
- UIKit Dynamics and iOS 7: Building UIKit Pong
: 다이나믹스를 이용해서, 바운싱을 예제로 설명하고 있는 곳.
- RayWenderlich의 UIKit Dynamics 강좌