|
class Button: UIButton, ExtendedTouchable { |
|
var touchableSurface: UIView? |
|
|
|
override func layoutSubviews() { |
|
super.layoutSubviews() |
|
setupTouchableArea() |
|
} |
|
|
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { |
|
guard isEnabled, !isHidden, alpha != 0.0 else { |
|
return nil |
|
} |
|
|
|
guard let touchableSurface = touchableSurface, touchableSurface.frame.contains(point) else { |
|
return super.hitTest(point, with: event) |
|
} |
|
|
|
return self |
|
} |
|
} |
|
|
|
/// Touchable functionality, extended to cover a potentially larger surface area on screen |
|
protocol ExtendedTouchable: class { |
|
/// Subview that is the outline for the extended touchable area |
|
var touchableSurface: UIView? { get set } |
|
|
|
/// Create the extended touchable area |
|
func setupTouchableArea() |
|
} |
|
|
|
// MARK: - UIControl |
|
extension ExtendedTouchable where Self: UIControl { |
|
func setupTouchableArea() { |
|
if bounds.size.width > .minimumButtonDimension, bounds.size.height > .minimumButtonDimension { |
|
touchableSurface?.removeFromSuperview() |
|
touchableSurface = nil |
|
return |
|
} |
|
|
|
if touchableSurface == nil { |
|
touchableSurface = { |
|
let view = UIView() |
|
view.backgroundColor = .clear |
|
|
|
// For debug |
|
// backgroundColor = #colorLiteral(red: 0.06274509804, green: 0.1254901961, blue: 0.4117647059, alpha: 0.2008240582) |
|
// view.backgroundColor = #colorLiteral(red: 0.06274509804, green: 0.1254901961, blue: 0.4117647059, alpha: 0.2008240582) |
|
|
|
addSubview(view) |
|
sendSubview(toBack: view) |
|
|
|
view.translatesAutoresizingMaskIntoConstraints = false |
|
view.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true |
|
view.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true |
|
view.widthAnchor.constraint (equalToConstant: max(bounds.size.width, .minimumButtonDimension)).isActive = true |
|
view.heightAnchor.constraint (equalToConstant: max(bounds.size.height, .minimumButtonDimension)).isActive = true |
|
|
|
return view |
|
}() |
|
} |
|
} |
|
} |
|
|
|
// MARK: - CGFloat constants |
|
private extension CGFloat { |
|
static let minimumButtonDimension: CGFloat = 44.0 |
|
} |