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

Ios 如何在Swift中扩展特定UIButton的命中区域?,ios,swift,uibutton,swift3,extension-methods,Ios,Swift,Uibutton,Swift3,Extension Methods,在我的应用程序中,我有一个非常小的ui按钮,因此我考虑增加它的点击区域 我找到了一个扩展: fileprivate let minimumHitArea = CGSize(width: 100, height: 100) extension UIButton { open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { // if the button is hi

在我的应用程序中,我有一个非常小的
ui按钮,因此我考虑增加它的点击区域

我找到了一个扩展:

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
    }
}
fileprivate let minimumHitArea=CGSize(宽:100,高:100)
扩展按钮{
打开覆盖函数hitTest(uPoint:CGPoint,带有事件:UIEvent?->UIView{
//如果按钮是隐藏/禁用/透明的,则无法点击
如果self.ishiden | | | |!self.isUserInteractionEnabled | | self.alpha<0.01{返回nil}
//增加命中帧,使其至少与“minimumHitArea”一样大`
让buttonSize=self.bounds.size
让widthToAdd=最大值(minimumHitArea.width-buttonSize.width,0)
let heightToAdd=最大值(最小HitArea.height-按钮大小.height,0)
设largerFrame=self.bounds.insertby(dx:-宽度到添加/2,dy:-高度到添加/2)
//在较大的帧上执行命中测试
返回(大帧包含(点))?自身:无
}
}

但当我使用它时,我应用程序中的每个按钮都有一个更大的点击区域。我只想将它增加到一个
特殊按钮
-我怎么做?

如果您想启用这样的命中区域,您可以向扩展添加一个
计算属性
,您可以在控制器中设置该属性:

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
  }
}
更新:

首先,您使用的方法并不像预期的那样工作。而且我的
计算属性的方法也不像我想的那样有效。因此,即使该方法不能像预期的那样工作,我也只想用
computed属性
更新我的方法。 因此,要从外部设置属性,可以使用。也有看。使用此解决方案,现在可以从控制器处理
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
  }
}
fileprivate let minimumHitArea=CGSize(宽:100,高:100)
私有变量xoAssociationKey:UInt8=0
扩展按钮{
var isIncreasedHitAreaEnabled:Bool{
得到{
返回(objc_getAssociatedObject(self,&xAssociationKey)!=nil)
}
设置(新值){
objc_setAssociatedObject(self,&xoAssociationKey,newValue,objc_AssociationPolicy.objc_ASSOCIATION_RETAIN)
}
}
打开覆盖函数hitTest(uPoint:CGPoint,带有事件:UIEvent?->UIView{
//如果按钮是隐藏/禁用/透明的,则无法点击
如果self.ishiden | | | |!self.isUserInteractionEnabled | | self.alpha<0.01{返回nil}
如果ISIncreasedHitareabled{
//增加命中帧,使其至少与“minimumHitArea”一样大`
让buttonSize=self.bounds.size
让widthToAdd=最大值(minimumHitArea.width-buttonSize.width,0)
let heightToAdd=最大值(最小HitArea.height-按钮大小.height,0)
设largerFrame=self.bounds.insertby(dx:-宽度到添加/2,dy:-高度到添加/2)
//在较大的帧上执行命中测试
返回(大帧包含(点))?自身:无
}
回归自我
}
}

不要扩大命中区域;缩小绘图区域。使按钮成为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点


创建一个自定义UIButton类,并重写pointInside:(CGPoint)point方法,如下所示。然后从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
#导入
@界面自定义按钮:UIButton
@属性(非原子)区域;
@不动产(非原子)面积;
@不动产(非原子)面积;
@不动产(非原子)面积;
@结束
#导入“CustomButton.h”
@实现自定义按钮
-(BOOL)pointInside:(CGPoint)pointwithevent:(UIEvent*)event
{
CGRect NEWARE=CGRectMake(self.bounds.origin.x-_leftArea,self.bounds.origin.y-_topArea,self.bounds.size.width+_leftArea+_rightArea,self.bounds.size.height+_bottomArea+_topArea);
返回CGRectContainsPoint(新区域,点);
}
@结束

所以让我把这一点弄清楚-如果我不设置标志
isincreasedHitAreaEnabled
,那么默认情况下它将为false?我的意思是-我不需要在我的应用程序中的每一个按钮上都将其设置为false,对吗?嗯,@Ronatary,我认为这一代码影响了我应用程序中的所有按钮,即使我只在其中一个按钮上设置了
isIncreased…
更重要的是,即使我将
minimumHitArea
更改为
width:10,height:10
,似乎命中区域覆盖了整个视图-你知道这里可能有什么问题吗?我会检查它,而@ronatory的答案是(1)将UIButton子类化为,比如说,
SpecialButton
,然后扩展它而不是UIButton。请注意,从扩展重写函数是一个坏主意,在“纯”swift中是不允许的,只有在Objective-C NSObject类中才允许。引用Apple swift iBook:“扩展可以向类型添加新功能,但不能覆盖现有功能”,摘自:Apple Inc.“Swift编程语言(Swift 3.0.1)”iBooks.更新了我的答案。但不幸的是,这个方法没有达到预期效果。我想你应该试试matt的答案@ronatory谢谢你的回答,我真的很感谢你的努力:)问题是我试了matt的答案,但效果似乎不太好,我不确定那里可能有什么问题,尽管目前我的按钮已关闭设置如下:如果我想从每侧扩展触摸区域,例如5,我应该如何做?我是否必须更改约束中的
宽度
高度
然后我怎么才能更改
contentEdgeInsets
?对不起,我的第一个答案不起作用,但我的第二个答案起作用了。嗯@matt,我尝试了你的方法,把这个类作为一个插座连接,并在故事板中为我的按钮设置它,但它不起作用-目前我按钮的图像不见了…按钮本身是c
#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