[Swift] - Animation 정리 1

2024. 3. 15. 13:35·개발일기/IOS
  • Animation은 우선 Closure기반으로 작성한다.
  • Animate가 실행되는 동안에는 user Information(터치 등)이 일시적으로 disabled되었다가, 끝나면 다시 enable된다.
  • UIView.animate를 사용한 애니메이팅은 자동으로 MainQueue(UI Queue)에서 동작한다.
    • 따라서 DispatchQueue.main.async를 사용하지 않아도 된다.
  • origin 값을 변경하는게 아니라 Transform을 변경하는 것이다.
    • Transform.identify를 이용하여 원래값을 얻을 수 있다.
  • 애니메이팅이 끝난 후, 동작하는 completionHandler가 존재한다.
    • Animation이 중간에 cancel되는 경우가 있어서 파라미터로 Bool변수를 받는다.
  • 애니메이션이 가능한 속성이 정해져있다
    • frame, bounds, center: 좌표, 레이아웃 관련값
    • transform: 모양관련값
    • alpha, backgroundcolor:색상 관련 값
UIView.animate(withDuration: TimeInterval,
               delay: TimeInterbal,
               options: UIView.AnimationOptions,
               animations: () -> Void,
               completion: ((Bool) -> Void)? )

✅ withDuration(필수)

몇초동안 애니메이션이 진행될지 결정한다.

2.0은 2초동안 애니메이션이 진행된다는 뜻

✅ delay

몇 초 이후에 시작할 지 딜레이를 결정한다.

3.0은 3초 이후에 이 애니메이션이 진행된다는 뜻

✅ options

애니메이션의 옵션을 결정한다.

배열을 사용해 동시에 옵션 지정이 가능하다.

[.repeat, .autoreverse]

⬇️ 자주 쓰이는 옵션

.allowUserInteraction

애니메이션 도중 터치 활성화

.repeat

애니메이션 무한 반복

.autoreverse

반대로도 실행가능, repeat랑 같이 사용해야 함

.curveEaseInOut(기본값) / .curveEaseln / .curveEaseOut

속도를 지정할 수 있는 옵션

UIView.AnimationOptions | Apple Developer Documentation

✅animations(필수)

실제로 애니메이션이 될 부분을 정의한다.

frame/bounds/center : 뷰의 위치와 크기

transform: 좌표 행렬값

alpha: 투명도

backgroundColor: 배경색

contentStretch: 확대/축소 영역

hidden과 같이 중간값 계산이 불가능한 속성은 애니메이션이 안된다.

✅completion

애니메이션이 다 종료된 이후(Duration동안의 애니메이션이 끝난뒤)에 실행되는 부분이다. 클로저형태로 작성이 가능하며, 없다면 nil !


4초동안 이미지뷰가 현재 전체뷰의 중심으로 이동하는 모습!

이미지 가로 세로 2배씩 늘어나는 모습

UIView.animate(withDuration: 4) {
	self.imageView.center = self.view.center
}
UIView.animate(withDuration: 4) {
	let scale = CGAffineTransform(scaleX: 2.0, y: 2.0) 
	self.imageView.transform = scale
}

180도 만큼 이미지가 돌아간다.

위치를 현재 x,y 좌표값에서 100,100만큼 더한 위치로 이동한다.

UIView.animate(withDuration: 4) {
	let scale = CGAffineTransform(rotationAngle: .pi) 
	self.imageView.transform = scale
}
UIView.animate(withDuration: 4) {
	let scale = CGAffineTransform(translationX: 2.0, y: 2.0) 
	self.imageView.transform = scale
}

CGAffineTransform에서는 concatenation을 활용해서 동시에 애니메이션을 묶을 수 있다.

다음과 같이 combine을 transform으로 넣어주면 정의한 3개가 동시에 진행된다.(2배 커지면서 180도만큼 회전하고 위치가 100,100 더한값으로 이동)

UIView.animate(withDuration: 3) {
	let scale = CGAffineTransform(scaleX: 2.0, y: 2.0) 
	let rotate = CGAffineTransform(rotationAngle: .pi) 
	let move = CGAffineTransform(translationX: 2.0, y: 2.0) 

	let combine = scale.concatenating(rotate).concatenating(move)
	self.imageView.transform = combine
}

애니메이션이 끝나고 다시 원상태로 돌리고 싶다면 completion 블록에다가 .identify를 넣어주면 원래 위치로 다시 돌아온다.

UIView.animate(withDuration:3) {
	let scale = CGAffineTransform(scaleX: 2.0, y: 2.0) 
	let rotate = CGAffineTransform(rotationAngle: .pi) 
	let move = CGAffineTransform(translationX: 2.0, y: 2.0) 

	let combine = scale.concatenating(rotate).concatenating(move)
	self.imageView.transform = combine
} completion: { finished in
		UIView.animate(withDuration: 2.0) {
			self.imageView.transform = .identify
		}
}

레이아웃을 조정하는 애니메이션같은 경우, layoutIfNeeded라는 메서드를 사용한다.

해당 메서드를 호출하게 되면 즉시, 수정된 레이아웃 뷰를 다시 그려줘! 라는 신호가 전달된다. 이 해당메서드를 animate클로저 내부에 넣어주면 된다

@objc func tapStartBtn() {
	self.imageViewTopConstraint.constant = 400
	UIView.animate(withDuration: 3) {
		self.view.layoutIfNeeded()
		self.imageView.alpha = 0.5
	}
}

UIViewPropertyAnimator

최신 API로, 애플에서도 권장하는 애니메이션 API

애니메이션이 완료되기 전에 동적으로 수정할 수 있다. 처음부터 끝까지 동작시키던가 도중에 인터렉션애니메이션으로 전환해서 타이밍을 조절할 수 있다.

프레임, 중심, 알파 및 변환 특성과 같은 뷰의 애니메이터 속성에 대해 작동한다.

애니메이션 객체를 만들고 startAnimation()을 통해서 애니메이션을 시작할 수도 있고, runningPropertyAnimator를 이용해서 즉시 애니메이션이 실행될수있도록 할 수도 있다.

기존 애니메이션 사용

func uiViewAnimate() {
	UIView.animate(withDuration: duration, delay:0, options: [.curveEaseInOut]) {
		self.sampleView1.frame = .ini(x:100, y:0, width: 150, height:200)
	}
}

UIViewPropertyAnimator 사용

func uiViewPropertyAnimator() {
	// 방법1: 애니메이션 즉시 실행
	UIViewPropertyAnimator.runningPropertyAnimator(withDuration: duration, delay: 0, options: [.curveEaseInOut]) {
		self.sampleView2.frame = .init(x:100, y:300, width:150, height:200)
	}
	
	// 방법2: startAnimation() 호출
	let animation = UIViewPropertyAnimator(duration: duration, curve:. easeIntOut) {
		self.sampleView2.frame = .init(x:100, y:300, width:150, height:200)
	}
	animation.startAnimation()
}

⇒ UIView.animate와 UIViewPropertyAnimator 결과는 같지만 속성이나 부가적인 기능이 더 많다.

Animation State는 start,pause를 하면 active상태가 되고, inactive상태가 되면 애니메이션 객체가 해제될 수도 있다.

addAnimations

위의 함수를 통해서 정의해준 애니메이션에 추가적으로 애니메이션을 혼합해서 사용할 수 있다.

let anmation = UIViewPropertyAnimator(duration: duration, curve: .easeInOut) {
	self.sampleView2.frame = .init(x:100, y:300, width: 150, height: 200)
}

animation.addAnimations {
	self.sampleView2.frame = .init(x:100, y:500, width:150, height: 200)
}

animation.startAnimation()

addAnimations(delayFactor:)

animation.addAnimations({
	self.sampleView2.backgroundColor = .blue
}, delayFactor: 0.5)

처음부터 색이 변경되지 않고 중간부터 변경된다. delayFactor은 0.0~1.0사이의 값을 넣을 수 있고 총 애니메이션 시간에 비례한 값이다.

예를 들어 애니메이션이 5초동안 동작한다고했을 때, delayFactor에 0.5를 넣어주면 2.5초부터 실행되는 애니메이션임을 뜻한다.

주의할점은 클래스를 생성하고 함수안에 애니메이션 동작이 완료되면 자동으로 해제가 되기 때문에 에러가 날 수 있음.

그러므로 재사용하거나 타이밍을 조정하고 싶다면 함수밖에 정의하고 사용하는걸 권장!(아래 코드처럼!)

class SomeVC {
	var animation: UIViewPropertyAnimator?
	func animation() {
		animation = UIViewPropertyAnimator(.....) {
			self.sampleView2.frame =  .init(x:100, y:500, width:150, height: 200)
		}
	}
}

pauseAnimation

이 함수를 호출하면 inactive에 있던 애니메이션이 active상태가 되며 애니메이션을 일시정지하는 코드이다. 다시 재생하려면 startAnimation()을 호출하면 된다.

stopAnimation(withoutFinishing:)

withoutFinishing에는 Bool값을 넣어줄 수가 있는데 true인경우 finishAnimation을 사용하지 않겠다는 뜻이다. inactive상태가 되고 현재 위치에 멈춰있는 상태가 된다.

반대로 false를 넣어준 경우, stopAnimation이후 finishAnimation을 사용해서 원하는 포지션으로 움직일 수가 있다. UIViewAnimatingPosition타입을 넣어줄 수가 있고, 옵션으로 .start, .current, .end가 있다.

.start를 넣어준 경우 stop을 호출하면 멈추고 애니메이션이 최초시작된 상태로 변한다. .current면 그자리 그대로 있으며, .end면 원래 재생하려던 애니메이션 끝까지 쭉실행된다.

이때 넣어준 start, current는 addCompletion에 들어올 position값으로 이용할 수 있다.

DispatchQueue.main.asyncAfter(deadline: .now()+0.5) {
	animation.pauseAnimation()
	DispatchQueue.main.asyncAfter(deadline: .now()+0.7) {
		animation.startAnimation()
		DispatchQueue.main.asyncAfter(deadline: .now()+0.5 {
			animation.stopAnimation(false)
			animation.finishAnimation(at: .start)
		}
	}
}

0.5초후 일시정지

0.7초후 다시시작

0.5초후 정지

끝나는 애니메이션은 처음으로 이동!해서 끝날 때 애니메이션이 처음위치로 돌아온다.

 

- 참고

[Swift] UIViewPropertyAnimator

728x90
저작자표시 변경금지 (새창열림)

'개발일기 > IOS' 카테고리의 다른 글

[Swift] - View의 Cycle  (0) 2024.03.15
[Swift] - Animation 정리 2  (0) 2024.03.15
[Swift] - CollectionView 정리  (0) 2024.03.15
[Swift] - ViewController 화면전환  (0) 2024.03.15
[Swift] - ViewController 생명주기  (0) 2024.03.15
'개발일기/IOS' 카테고리의 다른 글
  • [Swift] - View의 Cycle
  • [Swift] - Animation 정리 2
  • [Swift] - CollectionView 정리
  • [Swift] - ViewController 화면전환
코딩하는빵친자
코딩하는빵친자
안녕하세요 코딩하는 빵친자입니다. 말그대롭니다.
  • 코딩하는빵친자
    코딩하는 빵친자의 블로그
    코딩하는빵친자
  • 전체
    오늘
    어제
    • 분류 전체보기 (55)
      • 개발일기 (41)
        • Python (9)
        • Swift (2)
        • DataBase (0)
        • 알고리즘 (0)
        • IOS (30)
      • 데보션 영 (4)
      • 코테 (10)
        • Swift (10)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    ios개발
    Rosetta
    uikit
    추적권한
    pod
    settransition
    IOS
    제스처인식
    ios스와이프
    delegate패턴
    buildsetting
    universalapp
    SWIFT
    뷰관련메서드
    아웃링크
    arm7
    podlock
    podinstall오류
    uipangesture
    xcode
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
코딩하는빵친자
[Swift] - Animation 정리 1
상단으로

티스토리툴바