2017-02-11 38 views
0

在我的应用程序中,我有一个很小的UIButton,所以我想增加它的命中面积。如何在Swift中扩展特定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 - 我该怎么做?

+0

的替代方法@ ronatory的答案是:(1)亚类的UIButton为,比如说,'SpecialButton',然后延伸,代替的UIButton。 – dfd

+0

请注意,从扩展中重写函数是一个坏主意,并且不允许在纯“swift”中,只能在Objective-C NSObject类中使用。引用Apple Swift iBook:“扩展可以向某种类型添加新功能,但它们无法覆盖现有功能”。摘自:Apple Inc.“Swift Programming Language(Swift 3.0.1)。”iBooks。 https://itun.es/us/jEUH0.l –

+0

更新了我的答案。但不幸的是,该方法不能像预期的那样工作。我认为你应该尝试马特的答案http://stackoverflow.com/a/42182054/5327882 – ronatory

回答

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

然后在您的视图控制器只需设置isIncreasedHitAreaEnabledtrue如果你要增加它的特定按钮(例如,在您的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 
    } 
} 
+0

所以让我这样做 - 如果我没有设置标志'isincreasedHitAreaEnabled',那么默认情况下它会是false?我的意思是 - 我不需要在我的应用程序中的每个其他按钮上将其设置为false,对吧? – user3766930

+0

确切地说,添加代码注释,使其更清晰 – ronatory

+0

hmm,@ron,我认为这段代码影响了我的应用程序中的所有按钮,即使我只在其中的一个上设置了'isIncreased ...'......更重要的是,即使我将'minimumHitArea'更改为'width:10,height:10',看起来好像命中区域覆盖了整个视图 - 你知道这里可能有什么问题吗? – user3766930

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

+0

目前,我的按钮的约束设置如下:http://imgur.com/a/T3p8x如果我想扩大触摸区域,例如, 5从每边来看,我应该怎么做?我是否必须在约束条件中更改'width'和'height'(每个都加上5),然后如何更改'contentEdgeInsets'? – user3766930

+0

对不起,我的第一个答案没有用,但我的第二个答案是。 – matt

+0

嗯@matt,我尝试了你的方法,把这个类作为插座连接,并在故事板中为我的按钮设置它,但它不能正常工作 - 目前从我的按钮中的图像不见了...按钮本身是可点击的,但是该区域并不是可扩展的,对于每边30px更多:( – user3766930

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