UIButtonに3D Touchをつける

peek,popで使われる3DtouchをUIButtonで使えたらいいなと思いカスタムボタンを作成してみました。

趣味で作っているBLEアプリで、デバイスのリモコンを作る際にボタンを押す力でスピードを変えるのに使いました。ゲームなどで使っても面白いかなと思います。

カスタムボタン

指圧が変化した際にtouchesMovedが呼ばれる為touchesMovedでも処理を読んでいます。

また、touchesEndedで0を指定しない場合最後の値が0でない数値が入ってしまう場合があるので0を指定しています

import UIKit

class ForceButton: UIButton {

   var force: Float = 0.0
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        pressStrength(touches: touches)
        super.touchesBegan(touches, with: event)
    }
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        pressStrength(touches: touches)
        super.touchesMoved(touches, with: event)
    }
    
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        force = 0.0
        super.touchesBegan(touches, with: event)
    }

    
    func pressStrength(touches: Set<UITouch>) {
        if traitCollection.forceTouchCapability == .available {
            for touch:UITouch in touches {
                let strength = Float(touch.force / touch.maximumPossibleForce)
                force = strength
            }
        }
    }
}

ViewControllerで呼び出し

変化した際値が欲しかったので.allTouchEventsをトリガにしてメソッドを呼び出すようにしています。

class ViewController: UIViewController {

    @IBOutlet weak var button: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        button.addTarget(self, action: #selector(tapped(_:)), for: .allTouchEvents)
    }
    @objc func tapped(_ sender: ForceButton) {
        print(sender.force)
    }
}

出力ログはこんな感じです。