You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI缺失UITouch属性:如何在纯SwiftUI中获取force与majorRadius?

在纯SwiftUI中获取触摸的force与majorRadius属性

SwiftUI原生手势(如DragGesture)仅提供触摸坐标、位移等基础信息,并未直接暴露UITouch的force(按压力度)和majorRadius(触摸触点半径)属性。目前纯SwiftUI环境下没有原生API能直接获取这两个值,必须通过与UIKit桥接的方式实现,以下是具体方案:

1. 封装UIKit触摸处理组件

通过UIViewRepresentable创建一个能捕获触摸事件的UIView包装器,在其中监听UITouch的属性变化,并将数据传递给SwiftUI:

import SwiftUI

struct TouchCaptureView: UIViewRepresentable {
    // 回调函数,传递触摸数据
    var onTouchUpdate: (CGFloat, CGFloat) -> Void
    
    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        view.isUserInteractionEnabled = true
        // 添加点击手势识别器
        view.addGestureRecognizer(UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleTap(_:))))
        // 添加长按手势识别器,支持持续获取数据
        view.addGestureRecognizer(UILongPressGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleLongPress(_:))))
        return view
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator(onTouchUpdate: onTouchUpdate)
    }
    
    class Coordinator: NSObject {
        var onTouchUpdate: (CGFloat, CGFloat) -> Void
        
        init(onTouchUpdate: @escaping (CGFloat, CGFloat)) {
            self.onTouchUpdate = onTouchUpdate
        }
        
        @objc func handleTap(_ gesture: UITapGestureRecognizer) {
            guard let touch = gesture.touches.first else { return }
            onTouchUpdate(touch.force, touch.majorRadius)
        }
        
        @objc func handleLongPress(_ gesture: UILongPressGestureRecognizer) {
            guard let touch = gesture.touches.first else { return }
            // 长按过程中持续更新数据
            if gesture.state == .began || gesture.state == .changed {
                onTouchUpdate(touch.force, touch.majorRadius)
            }
        }
    }
}

2. 在SwiftUI视图中使用该组件

将封装好的TouchCaptureView嵌入SwiftUI视图,接收并展示触摸数据:

struct ContentView: View {
    @State private var touchForce: CGFloat = 0
    @State private var touchRadius: CGFloat = 0
    
    var body: some View {
        VStack(spacing: 20) {
            Text("按压力度: \(touchForce, specifier: "%.2f")")
            Text("触点半径: \(touchRadius, specifier: "%.2f")")
            
            // 占据大部分区域的触摸捕获视图
            TouchCaptureView { force, radius in
                touchForce = force
                touchRadius = radius
            }
            .background(Color.blue.opacity(0.2))
            .cornerRadius(10)
        }
        .padding()
    }
}

补充说明

  • 上述方案虽依赖UIKit的UITouch API,但属于SwiftUI与UIKit的标准桥接方式,是目前实现该需求的唯一可行路径。
  • 若需要支持拖拽过程中的持续数据更新,可替换为UIPanGestureRecognizer,在其changed状态下获取触摸数据。
  • force属性取值范围为0到设备支持的最大压力(可通过UITouch.maximumPossibleForce获取),majorRadius代表触摸触点的近似半径。

内容的提问来源于stack exchange,提问作者Ziv Adler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 10:24:44