[iOS]UIView Block 애니메이션 사용하기

2012/07/26 07:42

아이폰 UIKit 기반으로 개발하면 objective-c로 개발할 수 밖에 없다. 2년 아이폰 개발을 했지만 [] 형태의 언어 문법의 장점을 정말 모르겠다. 손도 많이 가고 코드도 길어진다. 불행중 다행인게 iOS 4.0부터 Block 함수를 쓸 수 있게 되어 프로세스 단위로 코딩이 좀 더 깔끔하게 짤 수 있게 되었다. Block 프로그래밍은 여러가지고 꽤 장점이 많기 때문에 다양하게 응용해볼 필요가 있다. 여기서는 UIView 애니메이션에서 제공하는 블록 함수를 사용해보는 것으로 블록 프로그래밍에 대해서 맛보기 해본다. 


전에 UIView에서 Animation기능은 너무 불편했다. 아래는 UIView 애니메이션의 인터페이스이다. 


@interface UIView(UIViewAnimation)

+ (void)beginAnimations:(NSString *)animationID context:(void *)context;  // additional context info passed to will start/did stop selectors. begin/commit can be nested
+ (void)commitAnimations;                                                 // starts up any animations when the top level animation is commited

// no getters. if called outside animation block, these setters have no effect.
+ (void)setAnimationDelegate:(id)delegate;                          // default = nil
+ (void)setAnimationWillStartSelector:(SEL)selector;                // default = NULL. -animationWillStart:(NSString *)animationID context:(void *)context
+ (void)setAnimationDidStopSelector:(SEL)selector;                  // default = NULL. -animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
+ (void)setAnimationDuration:(NSTimeInterval)duration;              // default = 0.2
+ (void)setAnimationDelay:(NSTimeInterval)delay;                    // default = 0.0
+ (void)setAnimationStartDate:(NSDate *)startDate;                  // default = now ([NSDate date])
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve;              // default = UIViewAnimationCurveEaseInOut
+ (void)setAnimationRepeatCount:(float)repeatCount;                 // default = 0.0.  May be fractional
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;    // default = NO. used if repeat count is non-zero
+ (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState;  // default = NO. If YES, the current view position is always used for new animations -- allowing animations to "pile up" on each other. Otherwise, the last end state is used for the animation (the default).

+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;  // current limitation - only one per begin/commit block

+ (void)setAnimationsEnabled:(BOOL)enabled;                         // ignore any attribute changes while set.
+ (BOOL)areAnimationsEnabled;

@end


이 인터페이스로 만들게 될때 콜백함수가 여러개 붙게 되면 프로세스를 따라가기가 얼마나 불편한지 모른다. 


iOS 4.0부터 지원하는 UIView의 Block 애니메이션 인터페이스는 다음과 같다.


@interface UIView(UIViewAnimationWithBlocks)

+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0);

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0); // delay = 0.0, options = 0

+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0); // delay = 0.0, options = 0, completion = NULL

+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0);

+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0); // toView added to fromView.superview, fromView removed from its superview

@end


이 인터페이스를 사용하면 아래와 같이 만들 수 있다. 


    button.transform=CGAffineTransformMakeScale(0.1, 0.1);
    button.alpha = 0;
    [UIView animateWithDuration:0.3 
                          delay:0
                        options:UIViewAnimationOptionBeginFromCurrentState
                     animations:(void (^)(void)) ^{
                         button.transform=CGAffineTransformMakeScale(1, 1);
                         button.alpha = 1;
                     }
                     completion:^(BOOL finished){
                         button.transform=CGAffineTransformIdentity;
                     }]; 


애니메이션 처리 후처리를 블로내에서 처리할 수 있게 되어 코드가 전보다 훨씬 간결해진다. 


이것을 사용해 버튼을 누르면 이미지가 확대되고 이 이미지를 누르면 없어지는 코드를 만들어보았다. 


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    
    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [button setFrame:CGRectMake(self.window.frame.size.width * 0.5 - 50, 40, 100, 30)];
    [button setTitle:@"터치" forState:UIControlStateNormal];
    [button addTarget:self action:@selector(_touched:) forControlEvents:UIControlEventTouchUpInside];
    [self.window addSubview:button];
    
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)_touched:(id)sender 
{
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    [button setImage:[UIImage imageNamed:@"iu.png"] forState:UIControlStateNormal];
    [button setFrame:CGRectMake(self.window.frame.size.width * 0.5 - 100, self.window.frame.size.height * 0.5 - 110, 200, 220)];
    [button setTitle:@"감추기" forState:UIControlStateNormal];
    [button addTarget:self action:@selector(_touched2:) forControlEvents:UIControlEventTouchUpInside];    
    [self.window addSubview:button];
    
    button.transform=CGAffineTransformMakeScale(0.1, 0.1);
    button.alpha = 0;
    [UIView animateWithDuration:0.3 
                          delay:0
                        options:UIViewAnimationOptionBeginFromCurrentState
                     animations:(void (^)(void)) ^{
                         button.transform=CGAffineTransformMakeScale(1, 1);
                         button.alpha = 1;
                     }
                     completion:^(BOOL finished){
                         button.transform=CGAffineTransformIdentity;
                     }];    
}

- (void)_touched2:(id)sender 
{
    UIView *view = (UIView*)sender;
    [UIView animateWithDuration:0.3 
                          delay:0
                        options:UIViewAnimationOptionBeginFromCurrentState
                     animations:(void (^)(void)) ^{
                         view.transform=CGAffineTransformMakeScale(0.1, 0.1);
                         view.alpha = 0;
                     }
                     completion:^(BOOL finished){
                         [view removeFromSuperview];
                     }];
}




BlockAnimationTest.zip


음... 하지만 저 애니메이션을 보여주기 위해서 저렇게 많은 코드를 써야한다니.... ㅡㅡ 


UIKit 기반 iOS 앱 개발은 암튼 코딩이 피곤하다. ㅎㅎ 


다음 글을 보면 Block 프로그래밍에 대해서 더 공부할 수 있겠다. 기존에 Selector만 넘겨주는 방식을 Block으로 바꾸면 훨씬 코드가 간결해질 수 있으므로 잘 활용해봐야겠다. 



보면 알겠지만 블록이 결국 closure라고 생각하면 된다는...


글쓴이 : 지돌스타(http://blog.jidolstar.com/831)


저작자 표시 비영리 동일 조건 변경 허락

iOS , , , , , ,