Notice
Recent Posts
Recent Comments
Link
관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - SwiftUI] 부모 뷰와 자식 뷰 사이의 애니메이션 동작 원리, geometryGroup(), transformEffect(.identity) 본문

iOS 응용 (SwiftUI)

[iOS - SwiftUI] 부모 뷰와 자식 뷰 사이의 애니메이션 동작 원리, geometryGroup(), transformEffect(.identity)

jake-kim 2025. 3. 19. 01:01

   부모 뷰와 자식 뷰 사이의 애니메이션 처리 원리

  • 토글 버튼이 있고 이걸 누를때마다 Text의 문자가fade효과를 내면서 새로 등장하는 애니메이션을 준다고 한 경우 아래처럼 작성이 가능
struct ContentView: View {
    @State var toggle = false

    var body: some View {
        VStack {
            Button("updown Toggle") {
                toggle.toggle()
            }
            
            Text(toggle ? "is toggled" : "not toggled")
                .animation(.smooth(duration: 1), value: toggle)
        }
    }
}

결과

  • 여기서 toggle 여부에 따라 height 조절해주고 싶은 요구사항이 생긴 경우?
struct ContentView: View {
    @State var toggle = false
    var sizeHeight: CGFloat {
        toggle ? 200 : 300
    }

    var body: some View {
        VStack {
            Button("updown Toggle") {
                toggle.toggle()
            }
            
            Text(toggle ? "is toggled" : "not toggled")
                .frame(height: sizeHeight) // <-
                .animation(.smooth(duration: 1), value: toggle)
        }
    }
}

결과) Text를 보면 제자리에서 사라지는 효과가 나와야하는데, 위치가 바뀐 후 사라지는 현상 발생

  • 기대 동작은 아래처럼 Text가 제자리에서 사라지는것이 목적

Text가 기대 동작대로 제자리에서 사라짐

  • 이런 현상은 뷰 업데이트 순서를 이해하면 알 수 있음

뷰의 업데이트 순서

  • height가 300 -> 200으로 변하는 순간 Text의 위치가 내려간 후 다시 올라오는 지점을 확인
var body: some View {
    VStack {
        Button("updown Toggle") {
            toggle.toggle()
        }
        
        Text(toggle ? "is toggled" : "not toggled")
            .frame(height: sizeHeight)
            .background(Color.gray.opacity(0.1)) // <- 가시성을 위해 추가
            .animation(.smooth(duration: 1), value: toggle)
    }
}

  • Text의 위치가 내려가는 이유?
    • 버튼을 누르는 순간 '바뀐 정보인 height 300 -> 200' 정보를 자식뷰가 수신하기전에 애니메이션이 업데이트됨
    • 자식뷰는 크기 300을 기준으로 보고 자기 자신을 업데이트 하는데 이미 부모 뷰의 크기는 200으로 반영되어 작아진 상태
    • 부모뷰는 200이라는 수치를 가지고 업데이트 -> 자식뷰는 300이라는 수치를 가지고 업데이트
    • 부모뷰가 작아진 상태에서 자식뷰를 업데이트 하려고하니 이런 현상 발생
    • 결국 애니메이션 특성 상 이전 상태를 유지하려는 특성 때문

해결 방법 - animationGroup() or transformEffect(.identity)

  • 자식뷰 입장에서 부모 뷰의 변경사항 정보를 먼저 수신하고난 후 업데이트하면 해결됨
  • 이 방법은 animationGroup()을 추가하거나 transformEffect(.identity)를 사용하는 것
    • 둘 다 자식뷰 입장에서 부모 뷰의 변경사항을 기다린다는 의미로 사용

https://developer.apple.com/documentation/swiftui/view/geometrygroup()

// geometryGroup()
Text(toggle ? "is toggled" : "not toggled")
    .geometryGroup() // <-
    .frame(height: sizeHeight)
    .background(Color.gray.opacity(0.1))
    .animation(.smooth(duration: 1), value: toggle)
    
// .transformEffect(.identity)
Text(toggle ? "is toggled" : "not toggled")
    ..transformEffect(.identity) // <-
    .frame(height: sizeHeight)
    .background(Color.gray.opacity(0.1))
    .animation(.smooth(duration: 1), value: toggle)

결과)

 

*전체 코드)

import SwiftUI

struct ContentView: View {
    @State var toggle = false
    var sizeHeight: CGFloat {
        toggle ? 200 : 300
    }
    
    var body: some View {
        VStack {
            Button("updown Toggle") {
                toggle.toggle()
            }
            
            Text(toggle ? "is toggled" : "not toggled")
                .transformEffect(.identity) // <-
                .frame(height: sizeHeight)
                .background(Color.gray.opacity(0.1))
                .animation(.smooth(duration: 1), value: toggle)
        }
    }
}

#Preview {
    ContentView()
}

* 참고

- https://developer.apple.com/documentation/swiftui/view/geometrygroup()

- https://fatbobman.com/en/posts/mastring-geometrygroup/

Comments