안녕하세요
iOS공부를 하고있는 주니오스라고 합니다.
최근에 제가 혼자 프로젝트를 진행하고 있는데요. 한 스크린에 여러가지 뷰들이 상화작용하여 움직이는 형태를 구현하려 했습니다.
각 뷰의 애니메이션 상태를 중앙집중식으로 관리하기 위해 아래 사진과 같은 구조를 선택했습니다.
이구조의 장점은 다음과 같습니다.
- View들 담고있는 Screen에서 상태변화를 발생시킬 경우 바인딩을 통해 뷰들을 관리할 수 있다.
- 구조적인 애니메이션 구현이 가능하다.
뷰의 상태를 관리하기 위해 각 뷰마다 자신의 애니메이션 상태를 저장하는 ViewState타입이 존재합니다.
아래 코드는 실제로 구현한 ViewState코드 입니다.
아래코드는 Screen코드의 일부입니다.
State랩퍼로 각 뷰의 상태를 저장하고 Binding관계를 형성한 것을 확인할 수 있습니다.
ScreenState가 변경될 경우 아래 코드를 보시면 각기다른 함수를 호출하는 것을 확인할 수 있습니다.
함수를 자세히 보시면 ViewState에 저장된 animTime 연산 프로퍼티를 활용하는 것을 확인 할 수 있는데요
이렇게 ViewState타입에 해당 애니메이션에 대한 정보를 저장하면 Screen에서 편하게 스케쥴링을 할 수 있니다.
자, 이렇게 구성한 화면이 어떻게 동작하는 지 직접 확인해 보시죠!😆😆
상태변화에 효율적으로 대체하기
애니메이션 실행동작이 한번에 여러개가 들어오면 어떻게 될까요?
실행중이던 애니메이션이 끊겨 다소 부자연스러운 동작이 발생할 수 있습니다.
저는 이 문제를 해결하기 위해 뷰내부에 뷰만의 스케쥴링 기법을 구현하였습니다.
아래코드는 앞서 보여드린 GIF내 앱의 타이틀(이름)을 표시하는 뷰입니다.
isAnimationWorking이라는 프로퍼티를 주목해 주세요.
isAnimationWorking 프로퍼티는 애니메이션 실행시 true로 설정되고
애니메이션 진행 시간이 지난 후 animWorkingOn함수에 의해 false로 설정됩니다.
ViewState의 상태가 변경되어도 해당 프로퍼티 값에 따라 애니메이션 실행을 보류합니다.
실행이 보류된 상태는 nextState에 저장되는 것을 확인할 수 있습니다.
nextState에 저장된 상태는 isAnimationWorking프로퍼티의 변화에 따라 두번째 onChange수정자에 의해 viewState에 할당됩니다.
하지만 이렇게만 구현하면 문제가 발생하지요
상황을 가정해 보겠습니다.
idle상태에서 upward상태로 변경된 직후 다시 idle상태를 요청했다고 가정하겠습니다.
- 첫번째 상태 -
viewState = .idle
isAnimationWorking = false
nextSatae = nil
- 두번째 상태 -
viewState = .upward
isAnimationWorking = true
nextSatae = nil
- 세번째 상태 -
viewState = .idle
isAnimationWorking = true
nextSatae = .idle
이상태에서 viewState변화에 따른 onChange는 무시됩니다.
- 네번째 상태 -
viewState = .idle
isAnimationWorking = false
nextSatae = nil
isAnimationWorking이 변경되어 두번째 onChange의 클로져가 호출됩니다.
하지만
viewState = nextSatae 배정연산이 발생하여도 onChange가 호출되지 않아 idle상태로 전환되지 않습니다.
왜냐하면 viewState는 세번째 상태와 네번째 상태에서 동일하기 때문입니다.
따라서 애니메이션 실행중에 새로운 상태가 요청될 경우를 표시할 수 있는 새로운 상태가 필요했습니다.
그것이 ViewState타입 코드에서 확인할 수 있는 congestion상태입니다.
감사합니다~!!
전체코드 정보는 아래와 같습니다. 🥹
https://github.com/J0onYEong/Project-Helper/commit/7052cdcf65ec51cad939cdd04519ff15982610c8
'SwiftUI' 카테고리의 다른 글
[SwifUI] IgnoreSafeArea수정자 정확하게 이해하기 (2) | 2023.11.28 |
---|---|
[SwiftUI] View좌표계이해를 통한 addArc사용 (0) | 2023.09.09 |
[SwiftUI] Transition사용법 심층정리 - 주니오스의 iOS어드벤쳐 (0) | 2023.06.27 |
[SwiftUI] UIViewRepresentable사용 (0) | 2023.06.22 |