What might be causing this animation bug with SwiftUI and NavigationView?

南楼画角 提交于 2020-12-03 11:48:18

问题


I've been experimenting with some SwiftUI layouts and one of the things that I wanted to try out was creating a simple circular progress ring. After playing around with the code for a while I managed to get everything working the way I was hoping for it to, at least for a prototype. The issue arrises when I embed this view inside a SwiftUI NavigationView. Now, every time I run the app in the canvas, simulator, or on a device, the initial loading of the progress ring has the entire view slowly sliding up into position.

This is a simple prototype, just messing around with the new SwiftUI tools. After some experimentation, I've found that if I remove the NavigationView the ring acts like it's meant to from the beginning. I'm not seeing an obvious reason for why this issue is occurring though.

import SwiftUI

struct ProgressRing_ContentView: View {

@State var progressToggle = false
@State var progressRingEndingValue: CGFloat = 0.75

var ringColor: Color = Color.green
var ringWidth: CGFloat = 20
var ringSize: CGFloat = 200

var body: some View {
    TabView{
        NavigationView{
            VStack{

                Spacer()

                ZStack{
                    Circle()
                        .trim(from: 0, to: progressToggle ? progressRingEndingValue : 0)
                        .stroke(ringColor, style: StrokeStyle(lineWidth: ringWidth, lineCap: .round, lineJoin: .round))
                        .background(Circle().stroke(ringColor, lineWidth: ringWidth).opacity(0.2))
                        .frame(width: ringSize, height: ringSize)
                        .rotationEffect(.degrees(-90.0))
                        .animation(.easeInOut(duration: 1))
                        .onAppear() {
                            self.progressToggle.toggle()
                        }

                    Text("\(Int(progressRingEndingValue * 100)) %")
                        .font(.largeTitle)
                        .fontWeight(.bold)
                }

                Spacer()

                Button(action: {
                    self.progressRingEndingValue = CGFloat.random(in: 0...1)
                }) { Text("Randomize")
                        .font(.largeTitle)
                        .foregroundColor(ringColor)
                }

                Spacer()

            }
            .navigationBarTitle("ProgressRing", displayMode: .inline)
            .navigationBarItems(leading:
                Button(action: {
                    print("Refresh Button Tapped")
                    }) {
                    Image(systemName: "arrow.clockwise")
                        .foregroundColor(Color.green)
                    }, trailing:
                Button(action: {
                    print("Share Button Tapped")
                    }) {
                    Image(systemName: "square.and.arrow.up")
                        .foregroundColor(Color.green)
                }
            )
        }
    }
}
}

#if DEBUG
struct ProgressRing_ContentView_Previews: PreviewProvider {
static var previews: some View {
    Group {

        ProgressRing_ContentView()
            .environment(\.colorScheme, .light)
            .previewDisplayName("Light Mode")

}
}
#endif

Above is the exact code that I'm currently working with. The actual animation of the ring sliding seems to be working how I expected it to, I'm just not sure why the entire ring itself is moving when embedded in a NavigationView.


回答1:


You need to use explicit animations, instead of implicit. With implicit animations, any animatable parameter that changes, the framework will animate. Whenever possible, you should use explicit animations. Below is the updated code. Notice I remove the .animation() call and added two withAnimation() closures.

If you would like to expand your knowledge on implicit vs. explicit animations, check this link: https://swiftui-lab.com/swiftui-animations-part1/

struct ContentView: View {

    @State var progressToggle = false
    @State var progressRingEndingValue: CGFloat = 0.75

    var ringColor: Color = Color.green
    var ringWidth: CGFloat = 20
    var ringSize: CGFloat = 200

    var body: some View {
        TabView{
            NavigationView{
                VStack{

                    Spacer()

                    ZStack{
                        Circle()
                            .trim(from: 0, to: progressToggle ? progressRingEndingValue : 0)
                            .stroke(ringColor, style: StrokeStyle(lineWidth: ringWidth, lineCap: .round, lineJoin: .round))
                            .background(Circle().stroke(ringColor, lineWidth: ringWidth).opacity(0.2))
                            .frame(width: ringSize, height: ringSize)
                            .rotationEffect(.degrees(-90.0))
                            .onAppear() {
                                withAnimation(.easeInOut(duration: 1)) {
                                    self.progressToggle.toggle()
                                }
                        }

                        Text("\(Int(progressRingEndingValue * 100)) %")
                            .font(.largeTitle)
                            .fontWeight(.bold)
                    }

                    Spacer()

                    Button(action: {
                        withAnimation(.easeInOut(duration: 1)) {
                            self.progressRingEndingValue = CGFloat.random(in: 0...1)
                        }
                    }) { Text("Randomize")
                        .font(.largeTitle)
                        .foregroundColor(ringColor)
                    }

                    Spacer()

                }
                .navigationBarTitle("ProgressRing", displayMode: .inline)
                .navigationBarItems(leading:
                    Button(action: {
                        print("Refresh Button Tapped")
                    }) {
                        Image(systemName: "arrow.clockwise")
                            .foregroundColor(Color.green)
                    }, trailing:
                    Button(action: {
                        print("Share Button Tapped")
                    }) {
                        Image(systemName: "square.and.arrow.up")
                            .foregroundColor(Color.green)
                    }
                )
            }
        }
    }
}


来源:https://stackoverflow.com/questions/57737144/what-might-be-causing-this-animation-bug-with-swiftui-and-navigationview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!