SwiftUI 视图在意想不到的路径上动画
SwiftUI view animates at unexpected path
我做了以下 PulsatingView
:
struct PulsatingView: View {
@State private var opacity = 0.7
@State private var scale: CGFloat = 0.5
var body: some View {
VStack {
ZStack {
Circle()
.fill(Color.black.opacity(opacity))
.animation(.easeInOut(duration: 2).delay(1.5).repeatForever(autoreverses: false))
.frame(width: 7, height: 7)
.scaleEffect(scale)
.animation(.easeIn(duration: 2.5).delay(1).repeatForever(autoreverses: false))
Circle()
.fill(Color.black)
.frame(width: 7, height: 7)
}
}
.onAppear {
opacity = 0
scale = 5
}
}
}
它产生以下结果:(点击查看动画;它是一个 .gif)
但是,当我将它添加到视图中时,例如在 VStack
中,会发生这种情况:(点击查看动画;它是一个 .gif)
我不知道为什么会这样,也不知道该如何解决。我已经尝试过添加 .fixedSize(horizontal: true, vertical: true)
或 .frame(width: 50, height: 50)
等修饰符,但这没有帮助。
有人知道这是怎么回事吗?
尝试使用具有连接值的动画,例如
Circle()
.fill(Color.black.opacity(opacity))
.animation(.easeInOut(duration: 2).delay(1.5).repeatForever(autoreverses: false), value: opacity) // << here !!
.frame(width: 7, height: 7)
.scaleEffect(scale)
.animation(.easeIn(duration: 2.5).delay(1).repeatForever(autoreverses: false), value: scale) // << here !!
重要提示: 如果它在 NavigationView
中启动,则动画状态应被推迟激活。 .
中提供了原因和调查详情
这个问题与您的代码无关,因为我们应该使用 NavigationView 来修复它 DispatchQueue.main.async
我也想重构您的代码,希望对您有所帮助,您也可以尽可能避免硬编码值,例如,您可以在视图外应用框架:
struct ContentView: View {
var body: some View {
CircleView(lineWidth: 0.5, color: .red, scale: 5.0)
.frame(width: 7, height: 7)
}
}
struct CircleView: View {
let lineWidth: CGFloat
let color: Color
let scale: CGFloat
@State private var startAnimation: Bool = Bool()
var body: some View {
Circle()
.strokeBorder(style: .init(lineWidth: startAnimation ? .zero : lineWidth)).opacity(startAnimation ? .zero : 1.0)
.scaleEffect(startAnimation ? scale : 1.0)
.overlay( Circle() )
.foregroundColor(color)
.onAppear() { DispatchQueue.main.async { startAnimation.toggle() } }
.animation(.easeIn(duration: 2.5).delay(1).repeatForever(autoreverses: false), value: startAnimation)
}
}
我终于设法在我自己的项目中找到解决这个问题的方法 - 我发现让动画视图在 NavigationView
中工作的唯一解决方案是在 onAppear
调用中移动动画,像这样:
Circle()
.fill(Color.black.opacity(opacity))
.onAppear {
withAnimation(.easeInOut(duration: 2).repeatForever(autoreverses: false)) {
opacity = 0
}
}
希望这可以帮助其他人,如果他们遇到了我最终遇到的同样问题!
我做了以下 PulsatingView
:
struct PulsatingView: View {
@State private var opacity = 0.7
@State private var scale: CGFloat = 0.5
var body: some View {
VStack {
ZStack {
Circle()
.fill(Color.black.opacity(opacity))
.animation(.easeInOut(duration: 2).delay(1.5).repeatForever(autoreverses: false))
.frame(width: 7, height: 7)
.scaleEffect(scale)
.animation(.easeIn(duration: 2.5).delay(1).repeatForever(autoreverses: false))
Circle()
.fill(Color.black)
.frame(width: 7, height: 7)
}
}
.onAppear {
opacity = 0
scale = 5
}
}
}
它产生以下结果:(点击查看动画;它是一个 .gif)
但是,当我将它添加到视图中时,例如在 VStack
中,会发生这种情况:(点击查看动画;它是一个 .gif)
我不知道为什么会这样,也不知道该如何解决。我已经尝试过添加 .fixedSize(horizontal: true, vertical: true)
或 .frame(width: 50, height: 50)
等修饰符,但这没有帮助。
有人知道这是怎么回事吗?
尝试使用具有连接值的动画,例如
Circle()
.fill(Color.black.opacity(opacity))
.animation(.easeInOut(duration: 2).delay(1.5).repeatForever(autoreverses: false), value: opacity) // << here !!
.frame(width: 7, height: 7)
.scaleEffect(scale)
.animation(.easeIn(duration: 2.5).delay(1).repeatForever(autoreverses: false), value: scale) // << here !!
重要提示: 如果它在 NavigationView
中启动,则动画状态应被推迟激活。
这个问题与您的代码无关,因为我们应该使用 NavigationView 来修复它 DispatchQueue.main.async
我也想重构您的代码,希望对您有所帮助,您也可以尽可能避免硬编码值,例如,您可以在视图外应用框架:
struct ContentView: View {
var body: some View {
CircleView(lineWidth: 0.5, color: .red, scale: 5.0)
.frame(width: 7, height: 7)
}
}
struct CircleView: View {
let lineWidth: CGFloat
let color: Color
let scale: CGFloat
@State private var startAnimation: Bool = Bool()
var body: some View {
Circle()
.strokeBorder(style: .init(lineWidth: startAnimation ? .zero : lineWidth)).opacity(startAnimation ? .zero : 1.0)
.scaleEffect(startAnimation ? scale : 1.0)
.overlay( Circle() )
.foregroundColor(color)
.onAppear() { DispatchQueue.main.async { startAnimation.toggle() } }
.animation(.easeIn(duration: 2.5).delay(1).repeatForever(autoreverses: false), value: startAnimation)
}
}
我终于设法在我自己的项目中找到解决这个问题的方法 - 我发现让动画视图在 NavigationView
中工作的唯一解决方案是在 onAppear
调用中移动动画,像这样:
Circle()
.fill(Color.black.opacity(opacity))
.onAppear {
withAnimation(.easeInOut(duration: 2).repeatForever(autoreverses: false)) {
opacity = 0
}
}
希望这可以帮助其他人,如果他们遇到了我最终遇到的同样问题!