6

Is it possible to customize the area from the button at which it is considered .touchDragExit (or .touchDragEnter) (out of its selectable area?)?

To be more specific, I am speaking about this situation: I tap the UIButton, the .touchDown gets called, then I start dragging my finger away from the button and at some point (some distance away) it will not select anymore (and of course I can drag back in to select...). I would like the modify that distance...

Is this even possible?

  • I think the following may help: https://stackoverflow.com/a/38335868/35499 – Dean Jul 22 '19 at 21:34
  • @Dean how exactly would I implement the above Swift answer (which is an old version of Swift) –  Jul 22 '19 at 22:18

2 Answers2

5

You need to overwrite the UIButton continueTracking and touchesEnded functions.

Adapting @Dean's link, the implementation would be as following (swift 4.2):

class ViewController: UIViewController {

    @IBOutlet weak var button: DragButton!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

}

class DragButton: UIButton {

    private let _boundsExtension: CGFloat = 0 // Adjust this as needed

    override open func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {

        let outerBounds: CGRect = bounds.insetBy(dx: CGFloat(-1 * _boundsExtension), dy: CGFloat(-1 * _boundsExtension))

        let currentLocation: CGPoint = touch.location(in: self)
        let previousLocation: CGPoint = touch.previousLocation(in: self)

        let touchOutside: Bool = !outerBounds.contains(currentLocation)
        if touchOutside {
            let previousTouchInside: Bool = outerBounds.contains(previousLocation)
            if previousTouchInside {
                print("touchDragExit")
                sendActions(for: .touchDragExit)
            } else {
                print("touchDragOutside")
                sendActions(for: .touchDragOutside)
            }
        } else {
            let previousTouchOutside: Bool = !outerBounds.contains(previousLocation)
            if previousTouchOutside {
                print("touchDragEnter")
                sendActions(for: .touchDragEnter)
            } else {
                print("touchDragInside")
                sendActions(for: .touchDragInside)
            }
        }

        return true
    }

    override open func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {

        let touch: UITouch = touches.first!
        let outerBounds: CGRect = bounds.insetBy(dx: CGFloat(-1 * _boundsExtension), dy: CGFloat(-1 * _boundsExtension))

        let currentLocation: CGPoint = touch.location(in: self)

        let touchInside: Bool = outerBounds.contains(currentLocation)
        if touchInside {
            print("touchUpInside action")
            return sendActions(for: .touchUpInside)
        } else {
            print("touchUpOutside action")
            return sendActions(for: .touchUpOutside)
        }
    }
}

Try changing the _boundsExtension value

alxlives
  • 5,084
  • 4
  • 28
  • 50
1

The drag area is exaclty equal to the area define by bounds. So if you want to customize the drag are simple customise the bounds of your button.

Abhishek Maurya
  • 697
  • 7
  • 19