#2 MagnificationGesture

7 阅读1分钟

功能

为任意 View 添加“双指捏合”缩放手势,实时返回缩放比例(relative to 1.0),可跟踪变化或结束时持久化。

参数

  1. onChanged:实时更新 UI,可配合 withAnimation(.linear) 实现平滑。
  2. onEnded:持久化缩放值、重置反弹(示例用 withAnimation(.spring()) 回弹到原尺寸)。
  3. 若仅需临时缩放,可在 onEnded 内将累加值清零即可。

示例

struct MagnificationGestureBootcamp: View {
    
    @State var currentAmount: CGFloat = 0 // 当前增量
    // 保留上一次的放大(缩小的)的比例
    @State var lastAmount: CGFloat = 0 // 上次遗留
    
    var body: some View {
//        Text("Hello, World!")
//            .font(.title)
//            .padding(40)
//            .background(Color.red.cornerRadius(8))
//            .scaleEffect(1.0 + currentAmount + lastAmount) // 总比例
//            .gesture(
//                // 两个手指同时拖拽屏幕,类似放大图片的动作
//                MagnificationGesture()
//                    .onChanged({ value in
//                        currentAmount = value - 1 // 仅本次增量
//                    })
//                    .onEnded({ value in
//                        lastAmount = lastAmount + currentAmount // 固化结果
//                        currentAmount = 0 // 复位增量
//                    })
//            )
        
        VStack {
            HStack {
                Circle()
                    .frame(width: 32, height: 32)
                Text("Swiftful Thinking")
                Spacer()
                Image(systemName: "ellipsis")
            }
            .padding(.horizontal)
            Rectangle()
                .frame(height: 300)
                .scaleEffect(1 + currentAmount)
                .gesture(
                    MagnificationGesture()
                        .onChanged({ value in
                            currentAmount = value - 1
                        })
                        .onEnded({ value in
                            withAnimation(.spring) {
                                currentAmount = 0
                            }
                        })
                )
            
            HStack {
                Image(systemName: "heart.fill")
                Image(systemName: "text.bubble.fill")
                Spacer()
            }
            .padding(.horizontal)
            .font(.headline)
            Text("This is the caption for my photo!")
                .frame(maxWidth: .infinity, alignment: .leading)
                .padding(.horizontal)
            
        }
    }
}

注意事项

  • 缩放中心为视图几何中心;如需指定锚点,请使用 .scaleEffect(_, anchor:)
  • 同时存在 DragGestureRotationGesture 时,可用 .simultaneousGestureGestureMask 组合。
  • 数值增量为相对 1.0 的偏移,记得计算总比例时加 1。