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

Posted

技术标签:

【中文标题】如何在 Swift 中扩展特定 UIButton 的点击区域?【英文标题】:how can I expand the hit area of a specific UIButton in Swift? 【发布时间】:2017-02-11 21:39:57 【问题描述】:

在我的应用程序中,我有一个很小的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 - 我该怎么做?

【问题讨论】:

@ronatory 的答案的替代方法是 (1) 将 UIButton 子类化为 SpecialButton,然后扩展它而不是 UIButton。 请注意,从扩展中覆盖函数是一个坏主意,并且不允许在“纯”swift中,仅在Objective-C NSObject类中。引用 Apple Swift iBook 的话:“扩展可以为类型添加新功能,但不能覆盖现有功能”摘自:Apple Inc. “Swift 编程语言 (Swift 3.0.1)。”电子书。 itun.es/us/jEUH0.l 更新了我的答案。但不幸的是,该方法并没有像预期的那样工作。我认为您应该尝试马特的回答***.com/a/42182054/5327882 @ronatory 感谢您的回答,我非常感谢您的努力:) 问题是我尝试了 matt 的回答,但似乎效果不佳,我不确定可能是什么问题虽然有 【参考方案1】:

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

【讨论】:

目前我的按钮有这样的约束设置:imgur.com/a/T3p8x 如果我想扩展触摸区域,例如两边各5个,我该怎么做?我是否必须更改约束中的widthheight(通过向每个约束中添加5),然后如何更改contentEdgeInsets 对不起,我的第一个答案不起作用,但我的第二个答案起作用。 hmm @matt,我尝试了您的方法,将此类作为插座连接,并在情节提要中为我的按钮设置了它,但效果不佳 - 目前我按钮的图像是消失了......按钮本身是可点击的,但该区域并没有确定每边多30px :( 可点击区域是按钮的大小。你说你有限制,所以你需要调整这些,很明显。 hm,所以我现在将按钮的约束更改为width: 45height:45,然后运行应用程序并且按钮更改了大小......我做错了什么?我希望按钮大小相同,但可点击区域会在其周围增长...我的按钮设置了圆角半径并且它是圆形的 - 这可能会导致一些问题?【参考方案2】:

如果你想像这样启用点击区域,你可以在你的扩展中添加一个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
  

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

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
  

【讨论】:

所以让我做对了——如果我不设置标志isincreasedHitAreaEnabled,那么默认情况下它会是假的吗?我的意思是 - 我不需要在我的应用程序中的每个其他按钮上将其设置为 false,对吧? hmm,@ronatory,我认为这段代码影响了我应用程序中的所有按钮,即使我只在其中一个按钮上设置了isIncreased......更重要的是,即使我更改了@987654336 @到width:10, height:10,似乎命中区域覆盖了整个视图-您知道这里可能出了什么问题吗? 我会检查的【参考方案3】:

创建一个自定义 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

【讨论】:

以上是关于如何在 Swift 中扩展特定 UIButton 的点击区域?的主要内容,如果未能解决你的问题,请参考以下文章

如何从HTTP请求将图像加载到UIButton Swift中

如何从 HTTP 请求将图像加载到 UIButton Swift

Swift 3:将UIButton扩展添加到ViewController

通过扩展 UIButton 类使用 Swift 创建自定义按钮

swift 扩展名称UIButton的颜色

swift 扩展用于更改UIImage。这对于UIButton的设置突出显示图像很有用。