我使用UIButton
进行自动布局。当图像很小时,点击区域也很小。我可以想象几种方法来解决这个问题:
除了上述两种方法之外,是否有更好的解决方案来增加UIButton的分接区域?
答案 0 :(得分:49)
您只需调整按钮的内容插入即可获得所需的尺寸。在代码中,它看起来像这样:
button.contentEdgeInsets = UIEdgeInsets(上:12,左:16,下:12,右:16)
//或者如果您特别想调整图像,请使用button.imageEdgeInsets
在界面构建器中,它将如下所示:
答案 1 :(得分:12)
很简单。创建自定义UIButton类。然后覆盖pointInside ...方法并根据需要更改值。
#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点以上的触摸区域。
答案 2 :(得分:8)
您可以在故事板中或通过代码设置按钮EdgeInsets。按钮的大小和高度应该比设置为按钮的图像大。
注意:在Xcode8之后,设置内容inset在尺寸检查中可用
或者,您也可以在拍摄图像视图时使用带有敲击手势的图像视图进行操作。确保在故事板上勾选用户图像视图的用户交互,以便手势正常工作。 使图像视图大于要在其上设置的图像并在其上设置图像。 现在将图像视图图像的模式设置为故事板/界面构建器的中心。
希望它会有所帮助。
答案 3 :(得分:6)
我确认Syed的解决方案即使使用自动版式也能正常工作。这是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")
}
}
答案 4 :(得分:4)
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)
答案 5 :(得分:3)
基于Syed答案的Swift 5版本(较大区域的负值):
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return bounds.insetBy(dx: -10, dy: -10).contains(point)
}
或者:
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)
}
答案 6 :(得分:1)
子类UIButton
并添加此功能
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)
}
答案 7 :(得分:1)
我要解决的方法是使用contentEdgeInsets
(在按钮内容外的边距)为按钮在小图像周围留出一些额外的空间,同时覆盖alignmentRect
属性具有相同的插图,将自动布局使用的矩形返回 in 到图像。这样可以确保自动布局使用较小的图像而不是按钮的完整可点击范围来计算其约束。
class HIGTargetButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setImage(_ image: UIImage?, for state: UIControl.State) {
super.setImage(image, for: state)
guard let image = image else { return }
let verticalMarginToAdd = max(0, (targetSize.height - image.size.height) / 2)
let horizontalMarginToAdd = max(0, (targetSize.width - image.size.width) / 2)
let insets = UIEdgeInsets(top: verticalMarginToAdd,
left: horizontalMarginToAdd,
bottom: verticalMarginToAdd,
right: horizontalMarginToAdd)
contentEdgeInsets = insets
}
override var alignmentRectInsets: UIEdgeInsets {
contentEdgeInsets
}
private let targetSize = CGSize(width: 44.0, height: 44.0)
}
粉红色按钮的可点击目标较大(此处显示为粉红色,但可能为.clear
),图像更小-其前边缘与基于图标的绿色视图的前边缘对齐,而不是整个按钮
答案 8 :(得分:0)
这应该有效
RouterModule.forRoot([], {useHash:true})
答案 9 :(得分:0)
关于边缘插图答案的一些上下文。
结合使用自动布局和内容边缘插图时,您可能需要更改约束。
假设您有一个10x10的图片,并且希望将其设为30x30,以实现更大的点击范围:
将自动布局约束设置为所需的较大区域。如果你 立即构建,这将拉伸图像。
使用内容边缘插图来缩小可用于 图片,使其与正确的尺寸匹配。在此示例中,该值为10 10 10 10.将图像留有10x10的空间以吸引自己。
胜利。
答案 10 :(得分:0)
子类的一种替代方法是扩展UIControl
,为其添加一个touchAreaInsets
属性-通过利用objC运行时-并扩展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
这里是NSObject+Swizzling.h
https://gist.github.com/epacces/fb9b8e996115b3bfa735707810f41ec8
这是一个非常通用的界面,可让您减少/增加UIControl
s的触摸区域。
#import <UIKit/UIKit.h>
/**
* Extends or reduce the touch area of any UIControls
*
* Example (extends the button's touch area by 20 pt):
*
* UIButton *button = [[UIButton alloc] initWithFrame:CGRectFrame(0, 0, 20, 20)]
* button.touchAreaInsets = UIEdgeInsetsMake(-10.0f, -10.0f, -10.0f, -10.0f);
*/
@interface UIControl (Extensions)
@property (nonatomic, assign) UIEdgeInsets touchAreaInsets;
@end
答案 11 :(得分:0)
此处介绍的两种解决方案都有效……在正确的情况下。但这里有一些你可能会遇到的问题。 首先是不完全明显的:
特定于上述解决方案:
使用 contentEdgeInsets 增加按钮大小而不增加图标/文本大小,类似于添加 padding
button.contentEdgeInsets = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
这个很简单,增加按钮大小会增加点击区域。
子类化 UIButton 并覆盖 point(inside point: CGPoint, with event: UIEvent?) -> Bool
class BigAreaButton: UIButton {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return bounds.insetBy(dx: -20, dy: -20).contains(point)
}
}
这个解决方案很棒,因为它可以让你在不改变布局的情况下将点击区域扩展到视图边界之外,但这里有一些问题:
---------
| |
|oooo |
|oXXo |
|oXXo |
|oooo | Button-X nested in View-o will NOT extend beyond View-o
---------
答案 12 :(得分:-3)
我不确定,但应该有一种方法可以为任何UIView指定最小尺寸,这可能会解决您的额外工作问题。但老实说,在图像周围添加额外的透明背景是最佳解决方案。