SwiftUI实现Material Design风格波纹动画技术求助
SwiftUI Material Design 波纹效果完整实现
以下是修复并完善后的波纹效果实现,已经包含了从触摸点扩散至整个视图的缩放动画,完全贴合Material Design的交互规范:
import SwiftUI struct Ripple: ViewModifier { let rippleColor: Color func body(content: Content) -> some View { GeometryReader { geo in ZStack { content if let touchPoint = touchPoint { Circle() .fill(rippleColor) .position(touchPoint) .scaleEffect(scale) .opacity(opacity) .animation(.easeOut(duration: 0.6), value: scale) } } .gesture( DragGesture(minimumDistance: 0) .onChanged { gesture in guard touchPoint != gesture.startLocation else { return } // 重置动画状态 scale = 0.01 opacity = 1.0 touchPoint = gesture.startLocation // 启动扩散动画 withAnimation(.easeOut(duration: 0.6)) { // 计算覆盖整个视图所需的最小缩放比例 let maxDistance = max( distance(from: touchPoint!, to: geo.frame(in: .local).topLeading), distance(from: touchPoint!, to: geo.frame(in: .local).topTrailing), distance(from: touchPoint!, to: geo.frame(in: .local).bottomLeading), distance(from: touchPoint!, to: geo.frame(in: .local).bottomTrailing) ) scale = maxDistance * 2 / 16 // 16是初始圆直径 opacity = 0.0 } } ) } } // MARK: 私有状态与方法 @State private var scale: CGFloat = 0.01 @State private var opacity: CGFloat = 0.0 @State private var touchPoint: CGPoint? private func distance(from point1: CGPoint, to point2: CGPoint) -> CGFloat { sqrt(pow(point2.x - point1.x, 2) + pow(point2.y - point1.y, 2)) } } extension View { func rippleEffect(rippleColor: Color = .accentColor.opacity(0.5)) -> some View { modifier(Ripple(rippleColor: rippleColor)) } } // 使用示例 struct RippleDemo: View { var body: some View { Button("点击测试波纹") { } .padding() .background(.blue) .foregroundColor(.white) .cornerRadius(8) .rippleEffect() } }
关键修改说明
- 几何尺寸计算:通过
GeometryReader获取视图边界,计算触摸点到视图四个角落的最大距离,确保波纹能完全覆盖整个视图。 - 同步动画:将缩放(
scaleEffect)和透明度(opacity)的动画绑定,用withAnimation触发连贯的扩散消失效果,替代原代码中的Timer,更符合SwiftUI原生动画逻辑。 - 手势优化:每次触摸时重置动画状态,确保重复点击能正确触发新波纹。
- 初始状态调整:将波纹初始缩放设为极小值,避免初始显示的突兀感。
内容的提问来源于stack exchange,提问作者RPK
相关产品推荐
相关产品推荐

