macOS下SwiftUI:ProgressView无法实现居中平滑缩放动画
SwiftUI ProgressView 动画异常问题解决
问题根源
- 独立分支导致布局错位:你用了两个独立的
if语句分别控制Circle和ProgressView的显示,SwiftUI会将它们视为两个无关的视图,而非同一位置的替换元素。这使得ProgressView初始化时没有继承Circle的中心布局,动画起点偏移到右下角。 - 无明确尺寸引发延迟:ProgressView默认没有固定尺寸,布局系统需要先计算其大小再执行动画,导致点击后出现延迟,同时进一步加剧位置偏移。
修正方案
将两个视图放在同一个if-else分支中,让SwiftUI识别为视图替换操作;同时给ProgressView添加明确尺寸约束,确保布局中心对齐。
修正后的代码
struct ProgressViewAnimationFix: View { @State private var isShowingProgressView: Bool = false var body: some View { ZStack(alignment: .center) { if !isShowingProgressView { Circle() .fill(Color.red) .onTapGesture { withAnimation { isShowingProgressView = true } } .transition(.scale) } else { ProgressView() .frame(width: 40, height: 40) // 固定尺寸,确保居中布局 .transition(.scale) } } .frame(width: 100, height: 100, alignment: .center) } }
另一种简洁写法(统一过渡)
struct ProgressViewAnimationFix: View { @State private var isShowingProgressView: Bool = false var body: some View { ZStack(alignment: .center) { Group { if isShowingProgressView { ProgressView() .frame(width: 40, height: 40) } else { Circle() .fill(Color.red) .onTapGesture { withAnimation { isShowingProgressView = true } } } } .transition(.scale) // 统一应用过渡动画 } .frame(width: 100, height: 100, alignment: .center) } }
效果说明
if-else结构让SwiftUI将两个视图视为同一位置的切换元素,自动对齐中心,动画从中心平滑缩放。- 固定ProgressView的尺寸后,布局系统无需额外计算大小,消除了动画延迟,同时保证位置稳定。
内容的提问来源于stack exchange,提问作者jeremyabannister
相关产品推荐
相关产品推荐

