SwiftUI带缩放效果的拖拽关闭视图时跳变问题求助
解决SwiftUI拖拽关闭大视图时的缩放跳变问题
问题描述
为大视图添加DragGesture实现拖拽关闭功能时,视图会随手势幅度缩放,但触发关闭后,视图会先跳回原始缩放比例,再通过matchedGeometryEffect动画过渡到小视图,出现明显的跳变卡顿。
问题根源
- 原代码在
DragGesture的onChanged回调中直接触发关闭逻辑,此时手势仍在进行中,立刻重置gestureOffset = .zero会让scaleEffect瞬间恢复到1,导致跳变。 matchedGeometryEffect的过渡动画没有衔接拖拽时的缩放状态,关闭时大视图直接回到初始尺寸再开始过渡。
修复代码
struct TestView: View { @State var showBigView = false @Namespace private var animationNameSpace @State var gestureOffset: CGSize = .zero @State var finalScale: CGFloat = 1.0 var body: some View { ZStack { if !showBigView { Image(systemName: "tshirt") .resizable() .scaledToFit() .foregroundColor(.red) .matchedGeometryEffect(id: "circle", in: animationNameSpace) .frame(width: 100, height: 100) .onTapGesture { withAnimation(.easeInOut) { showBigView = true finalScale = 1.0 gestureOffset = .zero } } } else { let currentScale = max(1 - (gestureOffset.height / 600), 0.6) Image(systemName: "tshirt") .resizable() .scaledToFit() .foregroundColor(.red) .matchedGeometryEffect(id: "circle", in: animationNameSpace) .frame(width: 300, height: 300) .scaleEffect(currentScale) .offset(y: gestureOffset.height) .gesture( DragGesture() .onChanged { value in guard value.translation.height > 0 else { return } gestureOffset = value.translation } .onEnded { value in if value.translation.height > 150 { finalScale = currentScale withAnimation(.easeInOut(duration: 0.3)) { showBigView = false gestureOffset = .zero } } else { withAnimation(.easeInOut) { gestureOffset = .zero } } } ) .transition(.scale(scale: finalScale)) } } } }
关键修改说明
- 新增
finalScale变量:记录关闭瞬间的缩放比例,让过渡动画从当前缩放状态启动,避免跳变。 - 关闭逻辑移至
onEnded:确保手势完全结束后再判断是否关闭,避免中途状态突变。 - 添加垂直偏移:让视图随拖拽手势下移,操作更符合直觉。
- 限制最小缩放:设置
currentScale最小值为0.6,防止视图过度缩小影响体验。 - 自定义过渡动画:用
finalScale作为过渡的初始缩放值,让matchedGeometryEffect的动画和拖拽缩放无缝衔接。
内容的提问来源于stack exchange,提问作者Noah
相关产品推荐
相关产品推荐

