Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
298 views
in Technique[技术] by (71.8m points)

swift - How to combine rotation and fade-out animation in SwiftUI

My screen is showing a rotating indicator until the data to be displayed finishes downloading.

I was able to implement the indicator rotation animation correctly.

struct MainView: View {

    @ObservedObject var viewModel = MainViewModel()

    var body: some View {
        VStack(spacing: 0) {
            if let data = viewModel.fetchedData {
                Text(data.description)
            } else {
                Spacer()
            }
            AdBanner()
        }
        .overlay(Indicator(shown: $viewModel.isLoading))
    }
}

struct Indicator: View {

    @Binding var shown: Bool
    @State private var rotating = false

    @ViewBuilder
    var body: some View {
        if shown {
            Image("Ring")
                .rotationEffect(.degrees(rotating ? 360 : 0))
                .onAppear {
                    withAnimation(.linear(duration: 1).repeatForever(autoreverses: false) {
                        self.rotating = true
                    }
                }
        }
    }
}

When the data download is finished, I want this indicator to fade out with its rotation continuing. I have tried many things, but I cannot implement this correctly. For example, it may not animate, or it may fade out but the rotation may be broken.

  • Not animate:

before:

        .overlay(Indicator(shown: $viewModel.isLoading))

after:

        .overlay(Indicator(shown: $viewModel.isLoading.animation(.easeOut(duration: 1))))
  • Rotation broken (The angle is reset to 0 when the fade starts.):

before:

        if shown {
            Image("Ring")
                .rotationEffect(.degrees(rotating ? 360 : 0))
                .onAppear {
                    withAnimation {
                        self.rotating = true
                    }
                }
        }

after:

    ZStack {
        if shown {
            Image("Ring")
                .rotationEffect(rotating ? 360 : 0)
                .onAppear {
                    withAnimation {
                        self.rotating = true
                    }
                }
        }
    }
    .transition(.opacity)
    .animation(.easeOut(duration: 1))

Is it possible to fade out the rotation animation without interrupting it?

question from:https://stackoverflow.com/questions/65878817/how-to-combine-rotation-and-fade-out-animation-in-swiftui

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You need transition, because view (image in this case) is removed from view hierarchy. And transition is animated by container of removing view.

Note: it is better to link every animation to own switching state to avoid affect on other animations

Here is solution. Tested with Xcode 12.1 / iOS 14.1

struct Indicator: View {
    
    @Binding var shown: Bool
    @State private var rotating = false
    
    @ViewBuilder
    var body: some View {
        VStack {
            if shown {
                Image("Ring")
                    .rotationEffect(Angle(degrees: rotating ? 360 : 0))
                    .animation(Animation.linear(duration: 1).repeatForever(autoreverses: false), value: rotating)
                    .transition(.opacity)
                    .onAppear {
                        self.rotating = true
                    }
            }
        }.animation(.default, value: shown)
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...