programing

Swift UI에서 전환 애니메이션이 제대로 작동하지 않음

telecom 2023. 8. 8. 20:03
반응형

Swift UI에서 전환 애니메이션이 제대로 작동하지 않음

버튼을 눌러 화면 중앙에 메시지를 표시/숨기는 매우 간단한 전환 애니메이션을 만들려고 합니다.

struct ContentView: View {
    @State private var showMessage = false
    
    var body: some View {
        ZStack {
            Color.yellow
            
            VStack {
                Spacer()
                Button(action: {
                    withAnimation(.easeOut(duration: 3)) {
                        self.showMessage.toggle()
                    }
                }) {
                    Text("SHOW MESSAGE")
                }
            }                
            if showMessage {
                Text("HELLO WORLD!")
                    .transition(.opacity)
            }
        }
    }
}

의 문서에 따르면..transition(.opacity)애니매이션

삽입 시 투명에서 불투명으로 전환되고 제거 시 불투명에서 투명으로 전환됩니다.

메시지는 다음과 같이 사라져야 합니다.showMessage상태 속성이 true가 되고 false가 되면 페이드아웃됩니다.이것은 제 경우에는 사실이 아닙니다.메시지는 페이드 애니메이션과 함께 표시되지만 애니메이션이 전혀 없는 상태로 숨습니다.아이디어 있어요?

편집: 다음에서 결과를 확인합니다.gif아래는 시뮬레이터에서 찍은 것입니다.

enter image description here

문제는 ZStack에서 뷰가 오고 갈 때 "zIndex"가 그대로 유지되지 않는다는 것입니다.이 경우 "showMessage"가 true에서 false로 변경되면 "Hello World" 텍스트가 포함된 VStack이 스택의 맨 아래에 배치되고 그 위에 노란색이 즉시 그려집니다.실제로 색이 바래고 있는데 노란색 뒤에서 색이 바래서 보이지 않습니다.

이 문제를 해결하려면 스택의 각 보기에 대해 "zIndex"를 명시적으로 지정하여 항상 동일하게 유지해야 합니다.

struct ContentView: View {
    @State private var showMessage = false
    
    var body: some View {
        ZStack {
            Color.yellow.zIndex(0)
            
            VStack {
                Spacer()
                Button(action: {
                    withAnimation(.easeOut(duration: 3)) {
                        self.showMessage.toggle()
                    }
                }) {
                    Text("SHOW MESSAGE")
                }
            }.zIndex(1)
            
            if showMessage {
                Text("HELLO WORLD!")
                    .transition(.opacity)
                    .zIndex(2)
            }
        }
    }
}

제 연구 결과는 불투명도 전환이 항상 효과적인 것은 아니라는 것입니다.(슬라이드와 .slide를 함께 사용하면 작동합니다.)

.transition(.opacity) //does not always work

사용자 지정 애니메이션으로 작성하면 작동합니다.

.transition(AnyTransition.opacity.animation(.easeInOut(duration: 0.2))) 
.zIndex(1)

나는 swift에서 벌레를 발견했습니다.애니메이션을 위한 UI_미리보기.코드에서 전환 애니메이션을 사용하고 스위프트에서 해당 애니메이션을 보고 싶을 때UI_preview는 애니메이션을 표시하지 않거나 애니메이션과 함께 일부 보기가 사라질 때만 표시됩니다.이 문제를 해결하려면 VStack에서 미리 보기를 추가하기만 하면 됩니다.이런 식으로:

struct test_UI: View {
    @State var isShowSideBar = false
    var body: some View {
        ZStack {
            Button("ShowMenu") {
                withAnimation {
                    isShowSideBar.toggle()
                }
                
            }
            if isShowSideBar {
                SideBarView()
                    .transition(.slide)
            }
        }
    }
}
struct SomeView_Previews: PreviewProvider {
    static var previews: some View {
        VStack {
           SomeView()
        }
    }
}

이것 이후에, 모든 애니메이션이 일어날 것입니다.

저는 이것이 캔버스의 문제라고 생각합니다.오늘 아침에 전환 작업을 하고 있었는데 캔버스에서 작동하지 않는 동안 시뮬레이터에서 작동하는 것 같습니다.한번 시도해 보세요.저는 애플에 버그를 보고했습니다.

Scott Gribben의 답변(아래 참조)이 더 마음에 들지만, (녹색 체크로 인해) 이 답변을 삭제할 수 없기 때문에 원래 답변은 그대로 두겠습니다.하지만 저는 그것을 벌레라고 생각한다고 주장할 것입니다.코드에 나타나는 순서 보기에 의해 zIndex가 암시적으로 할당될 것으로 예상할 수 있습니다.


이 문제를 해결하기 위해 VStack 내부에 if 문을 포함시킬 수 있습니다.

struct ContentView: View {
    @State private var showMessage = false

    var body: some View {
        ZStack {
            Color.yellow

            VStack {
                Spacer()
                Button(action: {
                    withAnimation(.easeOut(duration: 3)) {
                        self.showMessage.toggle()
                    }
                }) {
                    Text("SHOW MESSAGE")
                }
            }

            VStack {
                if showMessage {
                    Text("HELLO WORLD!")
                        .transition(.opacity)
                }
            }
        }
    }
}

zIndex중단 시 애니메이션이 중단될 수 있습니다.▁a▁you▁view로 감습니다.VStack,HStack아니면 다른 용기가 말이 될 것입니다.

저는 그냥 .transition을 포기했습니다.작동이 안 돼요.대신 보기의 오프셋을 애니메이션화하여 훨씬 더 신뢰할 수 있도록 했습니다.

먼저 오프셋에 대한 상태 변수를 만듭니다.

@State private var offset: CGFloat = 200

두 번째로 VStack의 오프셋을 설정했습니다.그런 다음 .onApear()의 .onApear()에서 애니메이션을 사용하여 오프셋을 0으로 다시 변경합니다.

        VStack{
            Spacer()
            HStack{
                Spacer()
                Image("MyImage")
            }
        }
        .offset(x: offset)
        .onAppear {
            withAnimation(.easeOut(duration: 2.5)) {
                offset = 0
            }
        }

아래 코드가 작동해야 합니다.

import SwiftUI

struct SwiftUITest: View {
    
    @State private var isAnimated:Bool = false
  
    var body: some View {
        ZStack(alignment:.bottom) {
            VStack{
                Spacer()
                Button("Slide View"){
                    withAnimation(.easeInOut) {
                        isAnimated.toggle()
                    }
                    
                }
                Spacer()
                Spacer()
           
            }
            if isAnimated {
                RoundedRectangle(cornerRadius: 16).frame(height: UIScreen.main.bounds.height/2)
                    .transition(.slide)

            }
            
            
        }.ignoresSafeArea()
    }
}

struct SwiftUITest_Previews: PreviewProvider {
    static var previews: some View {
        VStack {
            SwiftUITest()
        }
    }
}

당신은 그것을.

 .id(showMessage) 

V 스택의 본체 이후에, 그것은 당신을 도울 것입니다.

SwiftUI 사용자 지정 불투명도 전환

다음을 위해 연장할 수 있습니다.in그리고.out불투명 전환.

import SwiftUI

extension AnyTransition {
    static var inOpacity: AnyTransition {
        AnyTransition.modifier(
                        active: OpacityModifier(opacity: 0),
                      identity: OpacityModifier(opacity: 1)
        )
    }
    static var outOpacity: AnyTransition {
        AnyTransition.modifier(
                        active: OpacityModifier(opacity: 1),
                      identity: OpacityModifier(opacity: 0)
        )
    }
}
struct OpacityModifier : ViewModifier {
    let opacity: Double
    
    func body(content: Content) -> some View {
        content.opacity(opacity)
    }
}

enter image description here

struct ContentView : View {
    
    @State var isMessageVisible: Bool = false
    @State var text = Text("SwiftUI Transition Animation")
                          .font(.largeTitle)
                          .foregroundColor(.yellow)
    
    var body: some View {
        ZStack {
            Color.indigo.ignoresSafeArea()
            
            VStack {
                Spacer()
                Button("SHOW MY MESSAGE") {
                    withAnimation(.linear(duration: 2)) {
                        isMessageVisible.toggle()
                    }
                }
            }
            if isMessageVisible {
                text.transition(.inOpacity)       // in
            } else {
                text.transition(.outOpacity)      // out
            }
        }
    }
}

언급URL : https://stackoverflow.com/questions/57730074/transition-animation-not-working-properly-in-swiftui

반응형