swift - 是什么导致了 SwiftUI 和 NavigationView 的这个动画错误?

标签 swift animation swiftui navigationview

我一直在试验一些 SwiftUI 布局,我想尝试的其中一件事是创建一个简单的圆形进度环。玩了一会儿代码后,我设法让一切都按照我希望的方式工作,至少对于原型(prototype)来说是这样。当我将此 View 嵌入到 SwiftUI NavigationView 中时,问题就出现了。现在,每次我在 Canvas 、模拟器或设备上运行该应用程序时,进度环的初始加载都会使整个 View 缓慢向上滑动到位。

这是一个简单的原型(prototype),只是在摆弄新的 SwiftUI 工具。经过一些实验,我发现如果我删除 NavigationView,环的行为就像它从一开始就意味着的那样。不过,我没有看到出现此问题的明显原因。

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

以上是我目前正在使用的确切代码。环滑动的实际动画似乎按照我的预期工作,我只是不确定为什么当嵌入 NavigationView 时整个环本身都在移动。

最佳答案

您需要使用显式动画,而不是隐式动画。使用隐式动画,任何更改的动画参数,框架都会动画。只要有可能,您应该使用明确的动画。下面是更新后的代码。请注意,我删除了 .animation() 调用并添加了两个 withAnimation() 闭包。

如果您想扩展关于隐式动画与显式动画的知识,请查看此链接: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)
                    }
                )
            }
        }
    }
}

关于swift - 是什么导致了 SwiftUI 和 NavigationView 的这个动画错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57737144/

相关文章:

ios - SwiftUI,iOS : How to access public function inside @main struct from custom internal View?

swift - 如何在 SwiftUI 中的堆栈上设置背景颜色

ios - TabView (SwiftUI) : Respond onTab on an already active tabItem

xcode - 标签消失后将其移除

iphone - 在 Objective C 中模拟蜡烛火焰

swift - AppDelegate 中的当前 viewController 崩溃/空白屏幕

javascript - 在不同的 ScrollMagic 场景中重复使用补间

animation - Material-UI JSS 中的闪烁动画

ios - Xcode 9 - 修复范围内的所有内容变灰

ios - 如何禁用除所选单元格之外的所有单元格