我在使用自动布局时,使用了UIButton
。当图片尺寸较小时,点击区域也很小。我可以想象出几种修复方法:
- 增加图像大小,即在图像周围放置透明区域。这不好,因为当您定位图像时,必须记住额外的透明边框。
- 使用CGRectInset并增加大小。这与自动布局不兼容,因为使用自动布局将返回原始图像大小。
除了上述两种方法,是否有更好的解决方案来增加UIButton
的点击区域?
我在使用自动布局时,使用了UIButton
。当图片尺寸较小时,点击区域也很小。我可以想象出几种修复方法:
除了上述两种方法,是否有更好的解决方案来增加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
在界面构建器中,它会看起来像这样:
非常简单。创建一个自定义的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个触摸区域。
而且Swift 5版本:
class CustomButton: UIButton {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return bounds.insetBy(dx: -10, dy: -10).contains(point)
}
}
pointInside
和hitTest
。当您意识到这对于某些情况来说并不是一种优雅的解决方案时,我认为。 - anders我确认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")
}
}
button.imageView?.isUserInteractionEnabled = false
@mrwheet button.imageView?.isUserInteractionEnabled = false
- Davidheight
应该是 +10.0
或者 y
应该是 -10.0
,不是吗? - clearlight这应该可以正常工作
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)
}
}
基于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)
}
关于边缘插图答案的一些背景信息。
当使用自动布局与内容边缘插图相结合时,您可能需要更改约束条件。
假设您有一个10x10的图像,并希望将其放大为30x30以获得更大的点击区域:
将自动布局约束设置为所需的更大区域。如果您立即构建,则会拉伸图像。
使用内容边缘插图来缩小可用于图像的空间,使其匹配正确的大小。在此示例中,它将是10 10 10 10。这样,图像就有了一个10x10的空间来绘制自己。
成功。
contentEdgeInsets
(它们像按钮内容外的边距),同时还要使用相同的插入重写 alignmentRect
属性,将自动布局使用的矩形带回到图像中。这确保了自动布局使用更小的图像计算其约束,而不是按钮的完整可点击范围。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
),以及较小的图像 - 其前沿根据图标而不是整个按钮与绿色视图的前沿对齐。
这里介绍的两种解决方案确实可以在适当的情况下解决问题。但是,您可能会遇到一些问题。
以下内容特定于上述解决方案:
使用contentEdgeInsets来增加按钮的大小而不增加图标/文本的大小,类似于添加填充。
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
---------
继承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)
}