简体   繁体   English

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

[英]how can I expand the hit area of a specific UIButton in Swift?

In my application I have a UIButton that is quite small, so I thought about increasing the hit area of it. 在我的应用程序中,我有一个很小的UIButton ,所以我考虑增加它的点击区域。

I found an extension for that: 我找到了一个扩展名:

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
    }
}

but when I use it, every button in my app has a bigger hit area. 但是当我使用它时,我应用程序中的每个按钮都有较大的点击区域。 I want to increase it to only one specialButton - how can I do it? 我想将其增加到仅一个specialButton我该怎么做?

You can add a computed property to your extension which you can set in your controller if you want to enable the hit area like this: 您可以在扩展程序中添加一个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
  }
}

And then in your view controller just set isIncreasedHitAreaEnabled to true if you want to increase it for a specific button (eg in your viewDidLoad ): 然后,如果要为特定按钮(例如,在viewDidLoad )增加它,则在视图控制器中只需将isIncreasedHitAreaEnabled设置为true即可:

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

Update: 更新:

First of all the method which you use doesn't work like expected. 首先,您使用的方法无法正常工作。 And also my approach with the computed property did not work like I thought. 而且,我对computed property也不像我想的那样有效。 So even if the method does not work like expected, I just want to update my approach with the computed property . 因此,即使该方法无法按预期工作,我也只想使用computed property来更新我的方法。 So to set the property from outside, you can use Associated Objects . 因此,要从外部设置属性,可以使用关联对象 Also have look here . 也可以看看这里 With this solution now it would be possible to handle the Bool property isIncreasedHitAreaEnabled from your controller: 现在,通过此解决方案,可以从您的控制器处理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
  }
}

Don't expand the hit area; 不要扩大打击范围; shrink the drawing area. 缩小绘图区域。 Make the button a subclass of UIButton, and in that subclass, implement rect methods, along these lines: 使按钮成为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)
    }
}

Now the button is tappable 30 points outside its visible background. 现在,该按钮在其可见背景之外可以点击30点。

在此处输入图片说明

Create a Custom UIButton Class and override pointInside:(CGPoint)point method like below. 创建一个自定义UIButton类,并覆盖pointInside:(CGPoint)point方法,如下所示。 Then set these properties value from viewController. 然后从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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM