본문 바로가기
프로그래밍/Xcode-iOS

UIView Animation 만들어보기

by Mr-후 2020. 7. 13.
반응형

앱을 만들면서 애니메이션 같은 기능들은 거의 필수적(?)으로 들어가는데 그런 애니메이션에 좀처럼 관심이 가지 않는건 그 내면의 복잡성을 잘 알기에 미리 차단하는것이 아닌가 싶다. 

매번 겨우겨우 땜빵식으로 위기를 모면하곤 하는데 주로 구글 검색이나 예제 소스가 모여 있는 사이트에서 도움을 얻는다. 이번에도 요구하는 기능의 애니메이션을 보고 듣고 리소스를 찾던 도중 거의 99% 동일한 형태의 애니메이션을 찾았다. 그런데 너무 복잡스럽다. 이건 내 스타일이 아니라는 생각이 들었고 차근차근 애니메이션의 형태를 떧어보면서 어쩌면 좀더 간단하고 심플하게 구현할 수 있겠다는 생각이 들어 어줍짢게 구현을 시도했다. 

 

애니메이션은 처음에는 돋보기 모습을 한 둥근 원 형태의 버튼에서 왼쪽으로 늘어지면서 펼쳐지는 버튼의 애니메이션을 한 다음 2초 뒤 다시 원래 모습으로 돌아오는 애니메이션을 구현하면 된다. 애니메이션 내부의 제어는 별도로 뷰 안에서 컨트롤하게 하고 자체  애니메이션 기능은 UIView AnimateWithDuration을 이용해서 구현했고 애니메이션 중의 뷰 변화는 CGRectMake를 통해 사이즈를 늘리고 줄이고 하는 방식 한 가지와 CGAffineTransFormScale을 통해 스케일을 줄이고 늘리는 애니메이션 방식을 같이 구현하도록 했다. 

- (void)drawRect:(CGRect)rect {
    [super drawRect:rect];
    if (NO == _isDrawRect) {
        _isDrawRect = YES;        
        self.icoArraw.frame = CGRectMake(196, 20, 6, 10);
        self.icoArraw.transform = CGAffineTransformScale(self.icoArraw.transform, 0, 0);
        
        self.btnExpandable.titleLabel.alpha = 0.0;
        self.btnExpandable.frame = CGRectMake(171, 0.0, 54.0f, 54.0f);
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, .5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void){
            [self startAnimate];
        });
    }
}

- (void)startAnimate {
    [UIView animateWithDuration:.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ //iwashere animation wrong iOS13. duration set to 10.0 for testing originally it was 0.2
        // Drawing code
        if (self.isExpand) {
            self.isExpand = NO;
            
            self.btnIcon.transform = CGAffineTransformScale(self.transform, 1, 1);
            self.icoArraw.transform = CGAffineTransformScale(self.transform, 0.1, 0.1);
            
            self.btnExpandable.titleLabel.alpha = 0.0;
            self.btnExpandable.frame = CGRectMake(171, 0.0, 54.0f, 54.0f);
        } else {
            self.isExpand = YES;
            self.btnExpandable.frame = CGRectMake(0.0, 0.0, 225.0f, 54.0f);
            self.btnExpandable.titleLabel.alpha = 1.0;
            
            self.btnIcon.transform = CGAffineTransformScale(self.transform, 0.1, 0.1);
            self.icoArraw.transform = CGAffineTransformScale(self.transform, 1, 1);
        }

    } completion:^(BOOL finished){
        if (finished) {
            if (self.isExpand) {
                [self startTimer];
                self.btnIcon.transform = CGAffineTransformScale(self.transform, 0.0, 0.0);
            } else {
                self.icoArraw.transform = CGAffineTransformScale(self.transform, 0.0, 0.0);
                [self stopTimer];
            }
        }
    }];
}

 

특별할건 없는 코드이고 좀 너져분해보이기까지 한 이 코드가 실행되는 모습은 나름 나쁘지 않다. 앞서 말했더니 이런 애니메이션을 복잡스럽게 구성하고 구현하는 일은 나에게 부담스러운 일이다. 그래도 나름 티테일까지 꼼꼼히 체크하면서 픽셀 작업을 한 것이고 많은? 시행착오를 거쳐 다듬어진 코드들이다. 

transform을 이용해서 scale을 줄일때는 바로 0.0 으로 할경우 아름답지 않은 애니메이션이되므로 꼭 최소값을 조금 남겨두고 마지막에 애니메이션을 끝났을 때 받는 이벤트에서 안보이도록 처리하는 것이 바람직하다. 

또 iOS13과 그 이전의 버전에서는 애니메이션 약간 다르게 작동한다는 사실도 알게 되어 그 어색함을 줄이기 이해 @availabel(iOS 13.0, *)구분을 이용 라벨의 글씨가 작아지거나 커질 때 생기는 변화를 조건으로 추가해주었다. 

스스로 닫히거나 열리게 하는 이벤트는 NSTimer를 이용해서 2초 후 닫히도록 하고, 스크롤이 끝날 때 다시 열리도록 하는 부분은 dispatch_after()를 이용해서 애니메이션이 시작되도록 처리를 했다. 

UIViewAnimationOptionCurveEaseInOut 이라는 옵션을 이용했는데 옵션에 따라 작동하는 애니메이션도 iOS13과 차이가 있는듯했고 이보다 더 간단하게 UIView를 사용해서 구현하는 애니메이션의 경우 완전 이상하게 동작하는 경우도 있었다. 정확하게 애니메이션 되는 동작을 확인하기 위해서는 Duration을 아주 길게 하고 애니메이션일 되는 순간순간을 눈으로 확인하면 재미있는 모습을 볼 수 있다. 

 

 

반응형