관리 메뉴

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

[iOS - SwiftUI] 뷰에서 if, else 구분해야할때 id 활용하는 방법 (SwiftUI의 id) 본문

iOS 응용 (SwiftUI)

[iOS - SwiftUI] 뷰에서 if, else 구분해야할때 id 활용하는 방법 (SwiftUI의 id)

jake-kim 2025. 2. 19. 22:32

if, else 문을 쓰는 케이스

  • 만약 아래처럼 버튼을 눌렀을 때 특정 뷰에 애니메이션을 주어야하는 경우?

  • 구현 아이디어
    • 뷰를 만들 때 if, else문이 없이 아래처럼 animation을 주는 방법도 존재
    • 버튼이 눌릴때마다 isFlipped 값을 변경
@State var isFlipped = false

Text("🚀 SwiftUI Power!")
    .font(.largeTitle)
    .fontWeight(.bold)
    .foregroundColor(isFlipped ? .blue : .purple)
    .scaleEffect(isFlipped ? 1.5 : 0.5)
    .rotationEffect(.degrees(isFlipped ? 360 : -180))
    .opacity(isFlipped ? 1 : 0.5)
    .animation(.spring(response: 0.6, dampingFraction: 0.5), value: isFlipped)
  • 하지만 transition을 사용하여 구현된 상태에서는 뷰가 새로 그려질때인 if, else 문일때만 동작하는데, 이 때 아래처럼 사용하는 경우가 있음
@State private var isFlipped = false

if isFlipped {
    animationText
} else {
    animationText
}

var animationText: some View {
    Text("🚀 SwiftUI Power!")
        ...
        .transition(.asymmetric(insertion: .scale.combined(with: .opacity),
                                removal: .opacity))
        .animation(.spring(response: 0.6, dampingFraction: 0.5), value: isFlipped)
}
  • if, else 문 둘 다 동일한 뷰를 반환하기 때문에 이상한 코드처럼 보일 수 있으므로 이 경우는 if, else가 아닌 id를 활용하는것이 더욱 명확

id 개념

  • SwiftUI에서 id라는 메서드가 View의 extension으로 있는데, 이 id를 사용하면 위 문제 해결이 가능
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
extension View {

    /// Binds a view's identity to the given proxy value.
    ///
    /// When the proxy value specified by the `id` parameter changes, the
    /// identity of the view — for example, its state — is reset.
    @inlinable public func id<ID>(_ id: ID) -> some View where ID : Hashable

}
  • id는 단어 그대로 뷰에 id를 부여하는 것이며 id값이 달라지면 동일한 샘김새일 지라도 다른 뷰라고 판단됨
    • 즉, if, else문에서 동일한 뷰를 반환하는 것보단 단순히 같은 뷰에 id를 다르게 달아주면 되는 것
    • ID는 Hashable 타입이면 되므로 String, Bool과 같은 primitive type들은 모두 사용 가능
  • 아래 코드를 id를 활용하여 변경
if isFlipped {
    animationText
} else {
    animationText
}

변경 후)

  • if, else로 표현하는 것보다 "이 뷰는 동일한 구현으로 되어있지만 isFlipped에 따라 다른 뷰를 사용한다"라는 의미가 명확하게 됨
animationText
    .id(isFlipped)

전체 코드)

struct ContentView: View {
    @State var toggle = false
    
    var body: some View {
        AnimatedTextView()
    }
}

struct AnimatedTextView: View {
    @State private var isFlipped = false
    
    var body: some View {
        VStack {
            if isFlipped {
                animationText
            } else {
                animationText
            }
            
            animationText
                .id(isFlipped)
            
            Spacer().frame(height: 50)
            
            Button(action: {
                withAnimation {
                    isFlipped.toggle()
                }
            }) {
                Text("Change Text")
                    .padding()
                    .background(Color.black)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
        }
    }
    
    var animationText: some View {
        Text("🚀 SwiftUI Power!")
            .font(.largeTitle)
            .fontWeight(.bold)
            .foregroundColor(.blue)
            .scaleEffect(1.5)
            .rotationEffect(.degrees(360))
            .opacity(1)
            .transition(.asymmetric(insertion: .scale.combined(with: .opacity),
                                    removal: .opacity))
            .animation(.spring(response: 0.6, dampingFraction: 0.5), value: isFlipped)
    }
}
Comments