SwiftUI动画过程中获取当前值 实现环形进度条百分比文本同步动画
问题原因
SwiftUI 默认不对文本内容的变化做逐帧插值更新,直接绑定manager.progress的文本只会在属性值变更完成后刷新,无法跟随环形进度的动画过程同步更新。
解决方案
方案1:iOS 15+ 极简实现
直接给文本添加数字内容过渡动画即可,同时将动画和manager.progress绑定保证同步,修改后完整代码如下:
struct LoadingScreen: View { @ObservedObject var manager : OnboardingManager var body: some View { ZStack { Circle() .stroke(lineWidth: 20.0) .opacity(0.3) .foregroundColor(Color.red) Circle() .trim(from: 0.0, to: CGFloat(min(self.manager.progress, 1.0))) .stroke(style: StrokeStyle(lineWidth: 20.0, lineCap: .round, lineJoin: .round)) .foregroundColor(Color.red) .rotationEffect(Angle(degrees: 270.0)) // 动画绑定progress,避免多余隐式动画 .animation(.linear(duration: manager.progressDuration), value: manager.progress) Text(String(format: "%.0f %%", min(self.manager.progress, 1.0)*100.0)) .font(.largeTitle) .bold() // 数字内容过渡 .contentTransition(.numericText()) // 和圆环同步动画参数 .animation(.linear(duration: manager.progressDuration), value: manager.progress) .onTapGesture(perform: { // 用withAnimation包裹触发更新,保证全局动画同步 withAnimation(.linear(duration: manager.progressDuration)) { manager.executeLoad() } }) } } }
方案2:兼容iOS 15以下版本
通过自定义遵守AnimatableModifier协议的修饰器,实现逐帧插值渲染文本:
- 先定义可动画的百分比文本修饰器
struct AnimatablePercentText: AnimatableModifier { var progress: Double let decimalPlaces: Int = 0 var animatableData: Double { get { progress } set { progress = newValue } } func body(content: Content) -> some View { Text(String(format: "%.\(decimalPlaces)f %%", min(progress, 1.0)*100)) .font(.largeTitle) .bold() } } extension View { func animatablePercent(progress: Double) -> some View { self.modifier(AnimatablePercentText(progress: progress)) } }
- 替换原文本部分的代码即可
EmptyView() .animatablePercent(progress: manager.progress) .animation(.linear(duration: manager.progressDuration), value: manager.progress) .onTapGesture(perform: { withAnimation(.linear(duration: manager.progressDuration)) { manager.executeLoad() } })
内容的提问来源于stack exchange,提问作者dante
相关产品推荐
相关产品推荐

