如何在 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个,我该怎么做?我是否必须更改约束中的width
和height
(通过向每个约束中添加5),然后如何更改contentEdgeInsets
?
对不起,我的第一个答案不起作用,但我的第二个答案起作用。
hmm @matt,我尝试了您的方法,将此类作为插座连接,并在情节提要中为我的按钮设置了它,但效果不佳 - 目前我按钮的图像是消失了......按钮本身是可点击的,但该区域并没有确定每边多30px :(
可点击区域是按钮的大小。你说你有限制,所以你需要调整这些,很明显。
hm,所以我现在将按钮的约束更改为width: 45
和height: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