SwiftUI:如何让MagnificationGesture以两指中间的CGPoint为中心进行缩放
解决以两指中点为中心缩放的问题
你现在的代码只处理了缩放比例,但没有跟踪手势的中心位置,所以缩放始终以视图的默认中心(屏幕中心)为基准。要实现以两指放置的中点为中心缩放,我们需要同时管理缩放比例和视图偏移量,在手势更新时动态计算这两个值,补偿缩放带来的位置变化。
以下是修改后的完整代码:
struct ContentView: View { // 跟踪手势的临时数据:缩放比例和两指中点 @GestureState private var gestureData = (scale: CGFloat(1), center: CGPoint.zero) // 持久化的缩放和偏移状态 @State private var currentScale = CGFloat(1) @State private var currentOffset = CGPoint.zero // 手势开始时的初始状态,用于计算偏移量 @State private var initialScale: CGFloat = 1 @State private var initialOffset: CGPoint = .zero var body: some View { let gradient = Gradient(colors: [.red, .yellow, .green, .blue, .purple, .red, .yellow, .green, .blue, .purple, .red, .yellow, .green, .blue, .purple]) let magnificationGesture = MagnificationGesture() // 更新手势状态,获取当前缩放比例和两指中点 .updating($gestureData) { value, state, _ in state.scale = value state.center = value.location } .onChanged { value in // 计算当前的缩放比例(初始缩放 * 手势实时缩放) let newScale = initialScale * value // 计算缩放带来的偏移量变化:中点到视图中心的距离 * 缩放比例的变化率 let deltaScale = newScale - initialScale let offsetDelta = CGPoint( x: (gestureData.center.x - 1000) * deltaScale / initialScale, y: (gestureData.center.y - 1000) * deltaScale / initialScale ) // 更新当前偏移和缩放 currentOffset = initialOffset + offsetDelta currentScale = newScale } .onEnded { value in // 手势结束后,保存当前状态作为下一次手势的初始值 currentScale *= value initialScale = currentScale initialOffset = currentOffset } Circle() .fill( RadialGradient(gradient: gradient, center: .center, startRadius: 50, endRadius: 2000) ) .frame(width: 2000, height: 2000) .offset(currentOffset) .scaleEffect(currentScale) .gesture(magnificationGesture.coordinateSpace(.named("CircleCoordinate"))) .coordinateSpace(name: "CircleCoordinate") .onAppear { // 初始化初始状态 initialScale = currentScale initialOffset = currentOffset } } }
关键修改点说明:
新增状态变量:
gestureData:用@GestureState跟踪手势的临时缩放比例和两指中点位置,手势结束后会自动重置。currentScale/currentOffset:持久化存储当前的缩放比例和视图偏移量。initialScale/initialOffset:记录手势开始时的状态,用于计算缩放过程中的偏移变化。
手势逻辑调整:
- 在
updating闭包里获取手势的实时缩放比例和两指中点位置。 - 在
onChanged里计算新的缩放比例,并根据中点到视图中心的距离,计算需要补偿的偏移量——这样能保证缩放时中点位置保持不变。 onEnded里更新持久化的初始状态,确保下一次手势能基于当前状态继续操作。
- 在
坐标系设置:
- 给Circle视图添加自定义
coordinateSpace,让手势的位置计算相对于Circle本身,而不是屏幕,这样中点坐标的计算更准确。
- 给Circle视图添加自定义
这样修改后,无论你在屏幕哪个位置用两指缩放,都会以两指的中点为中心进行缩放,完美解决你的问题!
内容的提问来源于stack exchange,提问作者niklassaers
相关产品推荐
相关产品推荐

