1

I'm trying to increase the hit area of a UITapGestureRecognizer on a UILabel object. This answer suggests overriding hitTest on the UILabel:

class PaddedLabel: UILabel {
    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        print("hitTest called")
        let padding: CGFloat = 20.0
        let extendedBounds = bounds.insetBy(dx: -padding, dy: -padding)
        return extendedBounds.contains(point) ? self : nil
    }
}

However, the problem is that hitTest is not even called unless I'm actually tapping on the object, and not somewhere close to it. Therefore, extending the bounds seems to be useless.

The label is one of a few inside a UIStackView:

let label = PaddedLabel()
let gs = UITapGestureRecognizer(target: self, action: #selector(ThisViewController.handleTap(_:)))
label.addGestureRecognizer(gs)
label.isUserInteractionEnabled = true
stackView.addArrangedSubview(label)

How do I make this work?

Mark
  • 1,306
  • 13
  • 19
  • 1
    The work around might be adding a transparent uiview on top of it and add the tap gesture to it. – luckystars Jul 03 '20 at 10:02
  • That's a good idea. How is a "click event" on the screen propagated anyway? What code decides the objects to check for a UITapGestureRecognizer? – Mark Jul 03 '20 at 10:41

1 Answers1

2

You can edit PaddedLabel like below to set insets:

class PaddedLabel: UILabel {
    
    var textInsets = UIEdgeInsets.zero {
        didSet { invalidateIntrinsicContentSize() }
    }

    override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
        let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
        let invertedInsets = UIEdgeInsets(top: -textInsets.top,
                                          left: -textInsets.left,
                                          bottom: -textInsets.bottom,
                                          right: -textInsets.right)
        return textRect.inset(by: invertedInsets)
    }

    override func drawText(in rect: CGRect) {
        super.drawText(in: rect.inset(by: textInsets))
    }
}

and set textInsets to enlarge its tappable area.

label.textInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)

enter image description here

enter image description here

Omer Faruk Ozturk
  • 1,722
  • 13
  • 25