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