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

如何在无3D Touch的iPhone(如iPhone11)实现屏幕称重功能?

解决无3D Touch机型的屏幕称重问题

嘿,我来帮你搞定这个问题!你的原有代码依赖3D Touch专属的UIForceTouchCapability和UITouch.force API,但iPhone 11及之后的机型已经取消了3D Touch(改用Haptic Touch,而Haptic Touch不支持压力感知),这就导致原来的逻辑在这些机型上完全跑不通。不过别担心,我们可以换个思路——利用触摸接触面积来模拟压力检测,进而实现类似的称重功能。

原代码的核心问题

你的代码里有个关键判断:self.traitCollection.forceTouchCapability == .available,在无3D Touch的机型上这个判断永远不成立,而且touch.force和touch.maximumPossibleForce会返回固定的无效值,所以整个称重逻辑根本不会执行。

替代方案:基于触摸接触面积的实现

我们可以利用UITouch的majorRadius属性——这个值代表触摸区域的近似半径,按压越用力,手指接触屏幕的面积越大,majorRadius就会越大。通过校准这个值的变化,我们就能把它映射成重量。以下是修改后的完整实现:

第一步:添加校准相关的变量

先在你的ViewController里定义几个变量,用来存储校准基准和配置参数:

// 轻按屏幕时的基准触摸半径(校准用)
private var calibrationRadius: CGFloat = 0.0
// 你要对应最大压力的重量(比如原来的385克)
private let maxTargetWeight: CGFloat = 385.0
// 是否完成初始校准
private var isCalibrated = false
// 测试得到的最大半径差值(需要你实际测试调整)
private let maxRadiusDelta: CGFloat = 10.0

第二步:重写触摸事件方法

替换你原来的touchesMoved和touchesEnded,加上校准逻辑:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesBegan(touches, with: event)
    guard let touch = touches.first else { return }
    
    // 首次触摸时完成校准,记录轻按的基准半径
    if !isCalibrated {
        calibrationRadius = touch.majorRadius
        isCalibrated = true
        forceLabel.text = "校准完成,请按压"
        grammLabel.text = "0 grams"
    }
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesMoved(touches, with: event)
    guard let touch = touches.first, isCalibrated else { return }
    
    // 计算当前触摸半径与基准半径的差值
    let radiusDelta = touch.majorRadius - calibrationRadius
    // 防止差值为负(比如手指抬起时的波动)
    guard radiusDelta >= 0 else {
        forceLabel.text = "0% force"
        grammLabel.text = "0 grams"
        return
    }
    
    // 计算压力比例(最大不超过100%)
    let forceRatio = min(radiusDelta / maxRadiusDelta, 1.0)
    let forcePercent = Int(forceRatio * 100)
    // 映射成对应的重量
    let currentWeight = forceRatio * maxTargetWeight
    
    forceLabel.text = "\(forcePercent)% force"
    grammLabel.text = "\(Int(currentWeight)) grams"
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesEnded(touches, with: event)
    forceLabel.text = "0% force"
    grammLabel.text = "0 grams"
    // 可选:如果需要每次使用前都校准,可以在这里重置
    // isCalibrated = false
}

关键细节说明

  • 校准的重要性:必须让用户先轻按屏幕获取基准半径,因为不同手指的初始接触面积不一样,校准后才能准确计算按压的变化量。
  • maxRadiusDelta的调整:这个值需要你实际测试——比如用385克的物体按压屏幕,记录此时的touch.majorRadius减去校准半径的差值,把这个值设为maxRadiusDelta,这样重量映射才会准确。
  • 精度问题:这种方法的精度肯定不如原来的3D Touch,因为接触面积会受手指大小、按压角度、屏幕清洁度影响,所以可以考虑添加多次采样平滑处理,减少数值波动。

额外提示

如果想要更好的体验,可以在界面上添加一个"重新校准"按钮,让用户随时重置基准值,避免因为手指位置变化导致的误差。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 18:37:40