如何在Swift中扩展特定UIButton的命中区域?

时间:2017-02-11 21:39:58

标签: ios swift uibutton swift3 extension-methods

在我的应用程序中,我有一个非常小的UIButton,所以我考虑增加它的命中区域。

我找到了一个扩展名:

fileprivate let minimumHitArea = CGSize(width: 100, height: 100)

extension UIButton {
    open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        // if the button is hidden/disabled/transparent it can't be hit
        if self.isHidden || !self.isUserInteractionEnabled || self.alpha < 0.01 { return nil }

        // increase the hit frame to be at least as big as `minimumHitArea`
        let buttonSize = self.bounds.size
        let widthToAdd = max(minimumHitArea.width - buttonSize.width, 0)
        let heightToAdd = max(minimumHitArea.height - buttonSize.height, 0)
        let largerFrame = self.bounds.insetBy(dx: -widthToAdd / 2, dy: -heightToAdd / 2)

        // perform hit test on larger frame
        return (largerFrame.contains(point)) ? self : nil
    }
}

但是当我使用它时,我的应用中的每个按钮都有一个更大的命中区域。我想将其增加到只有一个specialButton - 我该怎么做?

3 个答案:

答案 0 :(得分:0)

如果要启用这样的匹配区域,您可以在扩展程序中添加computed property,您可以在控制器中设置该扩展程序:

fileprivate let minimumHitArea = CGSize(width: 100, height: 100)

extension UIButton {

  var isIncreasedHitAreaEnabled: Bool {
    get {
      // default value is false, so you can easily handle from outside when to enable the increased hit area of your specific button
      return false
    }
    set {

    }
  }

  open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    // if the button is hidden/disabled/transparent it can't be hit
    if self.isHidden || !self.isUserInteractionEnabled || self.alpha < 0.01 { return nil }

    // only if it's true the hit area can be increased
    if isIncreasedHitAreaEnabled {
      // increase the hit frame to be at least as big as `minimumHitArea`
      let buttonSize = self.bounds.size
      let widthToAdd = max(minimumHitArea.width - buttonSize.width, 0)
      let heightToAdd = max(minimumHitArea.height - buttonSize.height, 0)
      let largerFrame = self.bounds.insetBy(dx: -widthToAdd / 2, dy: -heightToAdd / 2)

      // perform hit test on larger frame
      return (largerFrame.contains(point)) ? self : nil
    }
    return self
  }
}

然后在您的视图控制器中将isIncreasedHitAreaEnabled设置为true,如果您想为特定按钮(例如在viewDidLoad中)增加它,那么:

override func viewDidLoad() {
  super.viewDidLoad()
  specialButton.isIncreasedHitAreaEnabled = true
}

更新:

首先,您使用的方法不能像预期的那样工作。我对computed property的态度也不像我想象的那样有效。因此,即使该方法不能按预期工作,我只想用computed property更新我的方法。 因此,要从外部设置属性,您可以使用Associated Objects。还要看here。现在使用此解决方案,您可以从控制器处理Bool属性isIncreasedHitAreaEnabled

fileprivate let minimumHitArea = CGSize(width: 100, height: 100)
private var xoAssociationKey: UInt8 = 0

extension UIButton {

  var isIncreasedHitAreaEnabled: Bool {
    get {
      return (objc_getAssociatedObject(self, &xoAssociationKey) != nil)
    }
    set(newValue) {
      objc_setAssociatedObject(self, &xoAssociationKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
    }
  }

  open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    // if the button is hidden/disabled/transparent it can't be hit
    if self.isHidden || !self.isUserInteractionEnabled || self.alpha < 0.01 { return nil }

    if isIncreasedHitAreaEnabled {
      // increase the hit frame to be at least as big as `minimumHitArea`
      let buttonSize = self.bounds.size
      let widthToAdd = max(minimumHitArea.width - buttonSize.width, 0)
      let heightToAdd = max(minimumHitArea.height - buttonSize.height, 0)
      let largerFrame = self.bounds.insetBy(dx: -widthToAdd / 2, dy: -heightToAdd / 2)

      // perform hit test on larger frame
      return (largerFrame.contains(point)) ? self : nil
    }
    return self
  }
}

答案 1 :(得分:0)

不要扩大命中区域;缩小绘图区域。使按钮成为UIButton的子类,并在该子类中,按照以下方式实现rect方法:

class MyButton : UIButton {
    override func contentRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.insetBy(dx: 30, dy: 30)
    }
    override func backgroundRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.insetBy(dx: 30, dy: 30)
    }
}

现在按钮可以在可见背景外点30点。

enter image description here

答案 2 :(得分:0)

创建一个自定义UIButton类并覆盖pointInside:(CGPoint)点方法,如下所示。然后从viewController设置这些属性值。

#import <UIKit/UIKit.h>
@interface CustomButton : UIButton
    @property (nonatomic) CGFloat leftArea;
    @property (nonatomic) CGFloat rightArea;
@property (nonatomic) CGFloat topArea;
@property (nonatomic) CGFloat bottomArea;
@end




#import "CustomButton.h
@implementation CustomButton

-(BOOL) pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    CGRect newArea = CGRectMake(self.bounds.origin.x - _leftArea, self.bounds.origin.y - _topArea, self.bounds.size.width + _leftArea + _rightArea, self.bounds.size.height + _bottomArea + _topArea);

    return CGRectContainsPoint(newArea, point);
}
@end