我一直在尝试一些SwiftUI布局,而我想尝试的事情之一就是创建一个简单的圆形进度环。在玩了一段时间的代码后,我设法使所有工作都按我希望的方式进行,至少是对于原型而言。当我将此视图嵌入SwiftUI NavigationView中时,问题浮出水面。现在,每次我在画布,模拟器或设备上运行该应用程序时,进度环的初始加载都会使整个视图缓慢向上滑动到适当位置。
这是一个简单的原型,只是与新的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中时整个环本身都会移动。
答案 0 :(得分:5)
您需要使用显式动画,而不是隐式动画。对于隐式动画,任何可更改的动画参数,框架都将进行动画处理。只要有可能,就应该使用显式动画。下面是更新的代码。注意,我删除了.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)
}
)
}
}
}
}