如何追踪SwiftUI按钮的动画状态并阻止其在动画中触发?
一、获取动画数据
系统默认Button的动画状态并未对外暴露,要获取动画数据(包括进度、状态),需要手动通过状态变量结合Animatable协议实现:
- 自定义可追踪动画进度的容器视图
通过遵循Animatable协议,可实时获取动画的进度值:
struct AnimatingContainer<Content: View>: View, Animatable { var content: () -> Content var animationProgress: CGFloat // 绑定动画数据,系统会自动更新该值 var animatableData: CGFloat { get { animationProgress } set { animationProgress = newValue } } init(animationProgress: CGFloat, @ViewBuilder content: @escaping () -> Content) { self.animationProgress = animationProgress self.content = content } var body: some View { content() .onChange(of: animationProgress) { newProgress in // 实时获取动画进度,按需处理(如存储、打印) print("当前动画进度:\(newProgress)") } } }
- 在Button中集成并控制动画
用状态变量管理动画的启动/结束状态,结合withAnimation触发动画并监听完成事件:
struct ContentView: View { @State private var isAnimating = false @State private var animationProgress: CGFloat = 0.0 var body: some View { AnimatingContainer(animationProgress: animationProgress) { Button("触发动画") { guard !isAnimating else { return } isAnimating = true // 启动示例缩放动画,时长1秒 withAnimation(.easeInOut(duration: 1.0).onCompletion { isAnimating = false animationProgress = 0.0 }) { animationProgress = 1.0 } } .scaleEffect(animationProgress == 1.0 ? 0.8 : 1.0) // 绑定动画效果 } } }
二、阻止动画中触发点击操作
有两种实用实现方式:
- 直接在Button的action中判断状态
在点击回调里先检查isAnimating,动画进行中则直接返回:
Button("触发动画") { guard !isAnimating else { return } // 后续动画逻辑 }
- 使用
.disabled修饰符(推荐)
给Button添加.disabled(isAnimating)修饰,既阻止点击,还会自动改变按钮视觉状态(如变灰),给用户明确反馈:
Button("触发动画") { // 动画逻辑 } .scaleEffect(animationProgress == 1.0 ? 0.8 : 1.0) .disabled(isAnimating)
内容的提问来源于stack exchange,提问作者Steven-Carrot
相关产品推荐
相关产品推荐

