【问题标题】:How to expand the hitTest area of a UIButton without extruding it's background image?如何在不挤压背景图像的情况下扩展 UIButton 的 hitTest 区域?
【发布时间】:2012-09-06 09:56:28
【问题描述】:

我已经设置了UIButton 的背景图片并在上面加上了一个标题(我使用了setBackgroundImage 方法而不是setImage)。现在我想扩大UIButton 的hitTest 区域而不挤压它的背景图像。

我该怎么做?

【问题讨论】:

    标签: iphone objective-c ios uibutton


    【解决方案1】:

    更简洁的方法是覆盖 pointInside。

    这是一个 Swift 版本:

    override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
        let expandedBounds = CGRectInset(self.bounds, -15, -15)
        return CGRectContainsPoint(expandedBounds, point)
    }
    

    【讨论】:

    • 不要忘记检查您的视图是否可见并且有窗口,否则您可能会得到有趣的结果...
    • @steipete 希望你的评论早点发布......结果不是那么有趣!
    【解决方案2】:

    这是已接受答案的更正版本。我们使用bounds 代替frameCGRectInset 代替CGRectMake。更清洁、更可靠。

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
        return CGRectContainsPoint([self expandedBounds], point) ? self : nil;
    }
    
    - (CGRect)expandedBounds {
        return CGRectInset(self.bounds, -20, -20);
    }
    

    【讨论】:

      【解决方案3】:

      此版本允许您定义所有 UIButton 的最小点击大小。至关重要的是,它还可以处理 UIButtons 被隐藏的情况,许多答案都忽略了这一点。

      extension UIButton {
          public override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
              // Ignore if button hidden
              if self.hidden {
                  return nil
              }
      
              // If here, button visible so expand hit area
              let hitSize = CGFloat(56.0)
              let buttonSize = self.frame.size
              let widthToAdd = (hitSize - buttonSize.width > 0) ? hitSize - buttonSize.width : 0
              let heightToAdd = (hitSize - buttonSize.height > 0) ? hitSize - buttonSize.height : 0
              let largerFrame = CGRect(x: 0-(widthToAdd/2), y: 0-(heightToAdd/2), width: buttonSize.width+widthToAdd, height: buttonSize.height+heightToAdd)
              return (CGRectContainsPoint(largerFrame, point)) ? self : nil
          }
      }
      

      【讨论】:

        【解决方案4】:

        好吧,你可以扩展 UIButton 并覆盖 UIView 的 hitTest 方法:

        - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
            int expandMargin = 20;
            CGRect extendedFrame = CGRectMake(0 - expandMargin , 0 - expandMargin , self.bounds.size.width + (expandMargin * 2) , self.bounds.size.height + (expandMargin * 2));
            return (CGRectContainsPoint(extendedFrame , point) == 1) ? self : nil;
        }
        

        【讨论】:

        • 这是不正确的。 point 在本地坐标系中,如果 vieworigin 不等于 CGPointZero,则使用 frame 代替 bounds 会导致问题。
        • CGRectInset 会比疯狂的 CGRectMake 更好
        【解决方案5】:

        我为此创建了library

        您可以选择使用一个类别,不需要子类化

        @interface UIView (KGHitTesting)
        - (void)setMinimumHitTestWidth:(CGFloat)width height:(CGFloat)height;
        @end
        

        或者您可以将您的 UIView 或 UIButton 子类化并设置 minimumHitTestWidth 和/或 minimumHitTestHeight。然后,您的按钮命中测试区域将由这 2 个值表示。

        就像其他解决方案一样,它使用- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 方法。该方法在 iOS 执行命中测试时被调用。 This 博客文章很好地描述了 iOS 命中测试的工作原理。

        https://github.com/kgaidis/KGHitTestingViews

        @interface KGHitTestingButton : UIButton <KGHitTesting>
        
        @property (nonatomic) CGFloat minimumHitTestHeight; 
        @property (nonatomic) CGFloat minimumHitTestWidth;
        
        @end
        

        您也可以直接继承并使用 Interface Builder 而无需编写任何代码:

        【讨论】:

          猜你喜欢
          • 2019-03-02
          • 1970-01-01
          • 2012-10-26
          • 2022-10-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多