clyne의 개발 기록

[Swift] 회전 애니메이션 (180도, 90도, 45도, 반시계방향) 본문

iOS/Swift

[Swift] 회전 애니메이션 (180도, 90도, 45도, 반시계방향)

clyne_dev 2021. 5. 2. 16:58

안녕하세요.

iOS 개발자 CNOO 입니다.

오늘은 시계방향 및 반시계방향으로 회전하는 애니메이션에 대해서 작성해보려고 합니다.왜냐면...

 

제가 개발할 때, 반시계방향 회전때문에 고생했던 기억이 있어서....

여러분은 그러지 마시라고 공유드립니다.

 

먼저, 결과물을 보고 시작하겠습니다.


이미지 뷰 회전 결과


180도 ~ 45도 까지의 버튼을 눌러 한바퀴 도는 예제입니다.

버튼이 눌리는 것을 보여드리기 위해, Ripple효과를 추가했는데,  이것은 이번 포스팅에서 다루지는 않을거예요! 

(혹시 원하시는 분 있으시면  리플 효과에 대해서도 포스팅을 작성해보겠습니다 ㅎㅎ)

 

자, 그럼 코드를 보겠습니다.

 

 

 


1. 뷰 생성 및 배치

(뷰들을 세팅하고, 클릭 이벤트를 넣는 등의 작업에는 RxSwift, RxGesture, Then, Snapkit 모듈을 활용했지만,  굳이 이거 안쓰셔도 됩니다! 그냥 스토리보드에 뷰 그려서 하셔도 돼요!  이번 포스팅의 핵심은 바로 회전이니까요!)


lazy var imageView1 = UIImageView().then {
    $0.image = UIImage(systemName: "swift")
    $0.tintColor = .black
}

lazy var rotate180Button = UIButton().then {
    $0.setTitle("180도", for: .normal)
    $0.backgroundColor = .black
}

lazy var rotate180CounterButton = UIButton().then {
    $0.setTitle("-180도", for: .normal)
    $0.backgroundColor = .brown
}

lazy var rotate90Button = UIButton().then {
    $0.setTitle("90도", for: .normal)
    $0.backgroundColor = .red
}

lazy var rotate45Button = UIButton().then {
    $0.setTitle("45도", for: .normal)
    $0.backgroundColor = .blue
}

뷰객체 생성한 후에, 

viewDidLoad에 배치하도록 합시다.


override func viewDidLoad() {
    super.viewDidLoad()
    
    self.view.addSubview(imageView1)
    imageView1.snp.makeConstraints {
        $0.center.equalToSuperview()
        $0.width.height.equalTo(120)
    }
    
    let stackView = UIStackView(arrangedSubviews: [rotate180Button,
                                                   rotate180CounterButton,
                                                   rotate90Button,
                                                   rotate45Button])
    stackView.spacing = 5
    stackView.distribution = .fillEqually
    
    self.view.addSubview(stackView)
    stackView.snp.makeConstraints {
        $0.trailing.leading.bottom.equalTo(view.safeAreaLayoutGuide)
        $0.height.equalTo(56)
    }
    
    // add Gesture
    Observable.merge([
        rotate180Button.rx.tapGesture().when(.recognized).map{_ in 1},
        rotate180CounterButton.rx.tapGesture().when(.recognized).map{_ in 2},
        rotate90Button.rx.tapGesture().when(.recognized).map{_ in 3},
        rotate45Button.rx.tapGesture().when(.recognized).map{_ in 4},
    ])
    .bind(onNext: rotateImage)
    .disposed(by: disposeBag)

}


private func rotateImage(tag: Int){
    switch tag {
    case 1:
        imageView1.rotate180()
    case 2:
        imageView1.rotate180CounterClock()
    case 3:
        imageView1.rotate90()
    case 4:
        imageView1.rotate45()
    default:
        print("error")
    }
}

짜잔~  뷰 다 그려주고, 클릭했을 때 동작까지 잘 추가해주었습니다.

그러면 이제 , rotateImage 메서드에 있는    rotate함수들에 대해서 보도록 합시다.

 

 


2. 이미지 회전 확장함수

이번에도  UIImageView의 확장함수로 만들어서 쓸 거예요.

 

extension UIImageView {

    // 180도 회전
    func rotate180(duration: TimeInterval = 0.25){
        UIView.animate(withDuration: duration, animations: {
            self.transform = self.transform.rotated(by: .pi)
        })
    }
    
    
    // 180도 반시계방향 회전
    func rotate180CounterClock(duration: TimeInterval = 0.25){
        UIView.animate(withDuration: duration, animations: {
            self.transform = self.transform.rotated(by: -(.pi*0.999999999999999))
        })
    }
    
    // 90도 회전
    func rotate90(duration: TimeInterval = 0.25){
        UIView.animate(withDuration: duration, animations: {
            self.transform = self.transform.rotated(by: .pi/2)
        })
    }

    // 45도 회전
    func rotate45(duration: TimeInterval = 0.25){
        UIView.animate(withDuration: duration, animations: {
            self.transform = self.transform.rotated(by: .pi/4)
        })
    }

}

이렇게 UIImageView 확장함수로 각 회전 방법에 대한 함수를 만들어주시면 됩니다.

 

그런데, 조금 이상한 코드가 보이지 않나요??

네,  반시계방향을 돌 때,  pi값에 (180도)  *0.99999... 이 되어있어요.

 

왜 넣었을까요?

 

바로,  transform함수는  회전 애니메이션을 적용할 때,  더 가까운 쪽으로 회전방향이 결정되게 되어있어요.

즉, 180도 돌라고 시키면 기본값으로 시계방향으로 회전을 하는데요,

-180도를 돌라고 해도, 결국 도착지는 180도의 도착지와 동일하기 때문에 시계방향으로 돕니다.

그래서  180도를 돌리는 것이 아닌,   180도*0.999999  즉, 179.99999 도를 돌게끔 세팅해준 것입니다.

그러면 반대쪽으로 도는 것이 더 가까우니까, 우리의 이미지뷰는 왼쪽으로 돕니다!!

 

신기하죠?

애플 개발자분들의 섬세함이 돋보이는 대목이네요...

ㅎㅎ

 

그럼 오늘도  좋은하루 되세요~~

 

 

 

 

 


ps. 이걸로 저는 아래쪽에 있는 동영상과 같이 chevron.down 이미지를 돌리는 것을 구현했답니다.

렛터디 스터디메인화면