Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/108.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何增加UIButton的点击区域?_Ios_Objective C_Swift_Uibutton - Fatal编程技术网

Ios 如何增加UIButton的点击区域?

Ios 如何增加UIButton的点击区域?,ios,objective-c,swift,uibutton,Ios,Objective C,Swift,Uibutton,我使用带有自动布局的ui按钮。当图像很小时,抽头区域也很小。我可以想象几种方法来解决这个问题: 增加图像大小,即在图像周围放置一个透明区域。这是不好的,因为在定位图像时,必须记住超透明的边框 使用CGRectInset并增加大小。这不适用于自动布局,因为使用自动布局时,它将回落到原始图像大小 除了上述两种方法之外,还有更好的方法来增加UIButton的点击区域吗?您可以简单地调整按钮的内容插入以获得所需的大小。在代码中,它将如下所示: button.contentEdgeInsets = UIE

我使用带有自动布局的
ui按钮
。当图像很小时,抽头区域也很小。我可以想象几种方法来解决这个问题:

  • 增加图像大小,即在图像周围放置一个透明区域。这是不好的,因为在定位图像时,必须记住超透明的边框
  • 使用CGRectInset并增加大小。这不适用于自动布局,因为使用自动布局时,它将回落到原始图像大小

  • 除了上述两种方法之外,还有更好的方法来增加UIButton的点击区域吗?

    您可以简单地调整按钮的内容插入以获得所需的大小。在代码中,它将如下所示:

    button.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16)
    //Or if you specifically want to adjust around the image, instead use button.imageEdgeInsets
    
    在interface builder中,它将如下所示:

    button.contentEdgeInsets = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16)
    //Or if you specifically want to adjust around the image, instead use button.imageEdgeInsets
    

    您可以在情节提要中或通过代码设置按钮边缘设置。按钮的大小在高度和宽度上应大于设置为按钮的图像

    注意:在Xcode8之后,设置内容插入在size Inspector中可用

    或者,您也可以在“图像视图”上使用“图像视图”,并在“图像视图”上单击鼠标,以执行操作。确保勾选脚本上为imageview启用的用户交互,以使手势正常工作。 使图像视图大于要在其上设置的图像,并在其上设置图像。 现在,将图像视图图像的模式设置为以情节提要/界面生成器为中心

    您可以点击图像进行操作


    希望对您有所帮助。

    非常简单。创建自定义UIButton类。然后覆盖内部的点。。。方法,并根据需要更改值

    #import "CustomButton.h"
    
    @implementation CustomButton
    
    -(BOOL) pointInside:(CGPoint)point withEvent:(UIEvent *)event
    {
        CGRect newArea = CGRectMake(self.bounds.origin.x - 10, self.bounds.origin.y - 10, self.bounds.size.width + 20, self.bounds.size.height + 20);
        
        return CGRectContainsPoint(newArea, point);
    }
    @end
    
    这将需要更多的10点接触面积为每一方

    和Swift 5版本:

    class CustomButton: UIButton {
        override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
            return bounds.insetBy(dx: -10, dy: -10).contains(point)
        }
    }
    

    Swift 4•Xcode 9

    您可以通过编程方式选择-

    用于图像-

    button.imageEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
    
    button.titleEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
    
    标题-

    button.imageEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
    
    button.titleEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
    

    我确认Syed的解决方案即使使用autolayout也能很好地工作。以下是Swift 4.x版本:

    import UIKit
    
    class BeepSmallButton: UIButton {
    
        // MARK: - Functions
    
        override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
            let newArea = CGRect(
                x: self.bounds.origin.x - 5.0,
                y: self.bounds.origin.y - 5.0,
                width: self.bounds.size.width + 10.0,
                height: self.bounds.size.height + 20.0
            )
            return newArea.contains(point)
        }
    
        override init(frame: CGRect) {
            super.init(frame: frame)
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }
    

    子类
    ui按钮
    并添加此函数

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        let verticalInset = CGFloat(10)
        let horizontalInset = CGFloat(10)
    
        let largerArea = CGRect(
            x: self.bounds.origin.x - horizontalInset,
            y: self.bounds.origin.y - verticalInset,
            width: self.bounds.size.width + horizontalInset*2,
            height: self.bounds.size.height + verticalInset*2
        )
    
        return largerArea.contains(point)
    }
    
    这应该行得通

    import UIKit
    
    @IBDesignable
    class GRCustomButton: UIButton {
    
        @IBInspectable var margin:CGFloat = 20.0
        override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
            //increase touch area for control in all directions by 20
    
            let area = self.bounds.insetBy(dx: -margin, dy: -margin)
            return area.contains(point)
        }
    
    }
    

    关于边插入的一些上下文回答

    将自动布局与内容边缘插入结合使用时,可能需要更改约束

    假设您有一个10x10的图像,并且希望将其设置为30x30,以获得更大的点击区域:

  • 将自动布局约束设置为所需的较大区域。如果你 立即构建这将扩展图像

  • 使用“内容边缘”插入来缩小可供用户使用的空间 图像,使其匹配正确的大小。在本例中,这将是10 10 10 10. 给图像留一个10x10的空间来绘制自己


  • Swift 5版本基于Syed的回答(较大区域为负值):

    或者:

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        return bounds.inset(by: UIEdgeInsets(top: -5, left: -5, bottom: -5, right: -5)).contains(point)
    }
    

    我的方法是使用
    contentEdgeInsets
    (其作用类似于按钮内容之外的边距)在小图像周围为按钮提供一些额外的空间,但也使用相同的插入覆盖
    alignmentRect
    属性,从而将autolayout使用的rect带回图像中。这样可以确保autolayout使用较小的图像而不是按钮的完全可点击范围来计算其约束

    class HIGTargetButton:UIButton{
    重写初始化(帧:CGRect){
    super.init(frame:frame)
    }
    必需初始化?(编码器:NSCoder){
    fatalError(“初始化(编码者:)尚未实现”)
    }
    覆盖func setImage(image:UIImage?,用于状态:UIControl.state){
    super.setImage(图像,用于:状态)
    guard let image=image else{return}
    设verticalMarginToAdd=max(0,(targetSize.height-image.size.height)/2)
    让horizontalMarginToAdd=max(0,(targetSize.width-image.size.width)/2)
    让插图=UIEdgeInsets(顶部:垂直添加,
    左:水平边缘添加,
    底部:垂直添加,
    右:水平边缘(添加)
    contentEdgeInsets=插图
    }
    覆盖变量对齐矩形插入:UIEdgeInsets{
    内容集
    }
    私人租赁targetSize=CGSize(宽度:44.0,高度:44.0)
    }
    
    粉红色按钮具有更大的可点击目标(此处显示为粉红色,但可以是
    .clear
    )和更小的图像-其前缘与绿色视图的前缘对齐,基于图标,而不是整个按钮


    子类化的替代方法是扩展
    UIControl
    ,通过利用objC运行时向其添加
    touchAreaInsets
    属性,并滑动
    pointInside:withEvent

    #import <objc/runtime.h>
    #import <UIKit/UIKit.h>
    
    #import "NSObject+Swizzling.h" // This is where the magic happens :)
    
    
    @implementation UIControl (Extensions)
    
    @dynamic touchAreaInsets;
    static void * CHFLExtendedTouchAreaControlKey;
    
    + (void)load
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            [self swizzleSelector:@selector(pointInside:withEvent:) withSelector:@selector(chfl_pointInside:event:) classMethod:NO];
        });
    }
    
    - (BOOL)chfl_pointInside:(CGPoint)point event:(UIEvent *)event
    {
        if(UIEdgeInsetsEqualToEdgeInsets(self.touchAreaInsets, UIEdgeInsetsZero)) {
            return [self chfl_pointInside:point event:event];
        }
        
        CGRect relativeFrame = self.bounds;
        CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, self.touchAreaInsets);
        
        return CGRectContainsPoint(hitFrame, point);
    }
    
    - (UIEdgeInsets)touchAreaInsets
    {
        NSValue *value = objc_getAssociatedObject(self, &CHFLExtendedTouchAreaControlKey);
        if (value) {
            UIEdgeInsets touchAreaInsets; [value getValue:&touchAreaInsets]; return touchAreaInsets;
        }
        else {
            return UIEdgeInsetsZero;
        }
    }
    
    - (void)setTouchAreaInsets:(UIEdgeInsets)touchAreaInsets
    {
        NSValue *value = [NSValue value:&touchAreaInsets withObjCType:@encode(UIEdgeInsets)];
        objc_setAssociatedObject(self, &CHFLExtendedTouchAreaControlKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    @end
    

    应该给它负值还是请解释正值——这几乎就像CSS中的“边距”。这不起作用。AutoLayout将尊重插图,改变按钮的位置,这不是我们想要的。相反,我们只希望命中检测受到影响,而不是布局。我很惊讶这是公认的答案。它不起作用,在扭曲图像的同时框架保持不变。我昨天创建了一个示例项目,看看它是否仍然有效,它确实有效。如果它扭曲了图像,那是因为图像视图的contentMode设置不正确。这应该是可以接受的答案。非常棒,只需处理按钮周围更大的区域,并允许它接收事件。我发现这对我的情况没有任何影响,我认为这是因为按钮的UIImageView抓住了触摸。我怎样才能防止呢?这让我完全疯了……@mrwheet
    button.imageView?.isUserInteractionEnabled=false
    这会放大按钮上的任何图像,这不是我们想要的。@Whomble。如果你不想要更大的背景区域。只需在UIImage上添加一个Ui按钮就可以了,谢谢。这似乎是正确的答案,没有副作用。非常有用。感谢您“修复”上述解决方案。这对我来说是一个非常好的解决方案,因为它不涉及自定义类