当UIButton的框架位于其父框架的外部时,UIButton(或与此相关的任何其他控件)是否有可能接收触摸事件?原因是当我尝试此操作时,我的UIButton似乎无法接收任何事件。我该如何解决?
当UIButton的框架位于其父框架的外部时,UIButton(或与此相关的任何其他控件)是否有可能接收触摸事件?原因是当我尝试此操作时,我的UIButton似乎无法接收任何事件。我该如何解决?
Answers:
是。您可以重写此hitTest:withEvent:
方法以返回一个视图,该视图具有比该视图包含的更大的点集。请参阅《UIView类参考》。
编辑:示例:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
CGFloat radius = 100.0;
CGRect frame = CGRectMake(-radius, -radius,
self.frame.size.width + radius,
self.frame.size.height + radius);
if (CGRectContainsPoint(frame, point)) {
return self;
}
return nil;
}
编辑2 :(在澄清之后:)为了确保将按钮视为在父级边界之内,您需要pointInside:withEvent:
在父级中覆盖以包括按钮的框架。
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
if (CGRectContainsPoint(self.view.bounds, point) ||
CGRectContainsPoint(button.view.frame, point))
{
return YES;
}
return NO;
}
请注意,此处仅提供用于覆盖pointInside的代码不是很正确。正如Summon在下面说明的那样,请执行以下操作:
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
if ( CGRectContainsPoint(self.oversizeButton.frame, point) )
return YES;
return [super pointInside:point withEvent:event];
}
请注意,您很可能self.oversizeButton
在此UIView子类中将它作为IBOutlet来使用;那么您只需将相关的“特大按钮”拖到相关的特殊视图即可。(或者,由于某种原因,如果您在项目中经常执行此操作,则将有一个特殊的UIButton子类,并且可以在子视图列表中查看这些类。)希望对您有所帮助。
pointInside:withEvent:
以包括按钮的框架。我将在上面的答案中添加一些示例代码。
hitTest:withEvent:
pointInside:withEvent:
当我按下位于父母范围之外的按钮时,并没有呼叫我的区域。有什么事吗
在父视图中,您可以覆盖点击测试方法:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
CGPoint translatedPoint = [_myButton convertPoint:point fromView:self];
if (CGRectContainsPoint(_myButton.bounds, translatedPoint)) {
return [_myButton hitTest:translatedPoint withEvent:event];
}
return [super hitTest:point withEvent:event];
}
在这种情况下,如果该点落在按钮的范围内,则将呼叫转接到该按钮;如果不是,请还原为原始实现。
就我而言,我有一个UICollectionViewCell
包含的子类UIButton
。我禁用clipsToBounds
了该单元格,并且该按钮在单元格边界之外可见。但是,该按钮未收到触摸事件。通过使用杰克的答案,我能够检测到按钮上的触摸事件:https : //stackoverflow.com/a/30431157/3344977
这是Swift版本:
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
let translatedPoint = button.convertPoint(point, fromView: self)
if (CGRectContainsPoint(button.bounds, translatedPoint)) {
print("Your button was pressed")
return button.hitTest(translatedPoint, withEvent: event)
}
return super.hitTest(point, withEvent: event)
}
斯威夫特4:
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let translatedPoint = button.convert(point, from: self)
if (button.bounds.contains(translatedPoint)) {
print("Your button was pressed")
return button.hitTest(translatedPoint, with: event)
}
return super.hitTest(point, with: event)
}
为什么会这样呢?
这是因为,当您的子视图超出超级视图的范围时,该子视图上实际发生的触摸事件将不会传递到该子视图。然而,WILL交付给它的父。
无论子视图是否在视觉上被剪切,触摸事件始终会遵循目标视图的父视图的边界矩形。换句话说,在其超级视图的边界矩形之外的视图的一部分中发生的触摸事件不会传递到该视图。链接
你需要做什么?
当您的超级视图接收到上述触摸事件时,您需要明确告知UIKit我的子视图应该是接收此触摸事件的子视图。
那代码呢?
在您的监督下,实施 func hitTest(_ point: CGPoint, with event: UIEvent?)
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if isHidden || alpha == 0 || clipsToBounds { return super.hitTest(point, with: event) }
// convert the point into subview's coordinate system
let subviewPoint = self.convert(point, to: subview)
// if the converted point lies in subview's bound, tell UIKit that subview should be the one that receives this event
if !subview.isHidden && subview.bounds.contains(subviewPoint) { return subview }
return super.hitTest(point, with: event)
}
令人着迷的哥特奇:您必须去“最高的太小的超级观看”
您必须“向上”进入问题视图位于外部的“最高”视图。
典型示例:
假设您有一个带有容器视图C的屏幕S。容器视图控制器的视图为V。实际在V之外的视图
但请注意,B也在C之外。
在这个例子中,你必须应用的解决方案override hitTest
其实到C,而不是到V。如果将其应用于V,则不会执行任何操作。
迅速:
targetView是您希望接收事件的视图(该视图可能全部或部分位于其父视图的框架之外)。
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
let pointForTargetView: CGPoint = targetView.convertPoint(point, fromView: self)
if CGRectContainsPoint(targetView.bounds, pointForTargetView) {
return closeButton
}
return super.hitTest(point, withEvent: event)
}
对于我(对于其他人),答案不是覆盖hitTest
方法,而是覆盖pointInside
方法。我只能在两个地方这样做。
Superview
这是一种观点,即如果将其clipsToBounds
设置为true,它将使整个问题消失。这是我UIView
在Swift 3中的简单操作:
class PromiscuousView : UIView {
override func point(inside point: CGPoint,
with event: UIEvent?) -> Bool {
return true
}
}
子视图
您的行驶里程可能会有所不同,但就我而言,我还必须覆盖pointInside
已确定接触超出范围的子视图方法。我的在Objective-C中,所以:
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
WEPopoverController *controller = (id) self.delegate;
if (self.takeHitsOutside) {
return YES;
} else {
return [super pointInside:point withEvent:event];
}
}
迅捷4.1更新
为了在同一个UIView中获取触摸事件,您只需要添加以下重写方法,它将标识UIView中所点击的特定视图,该视图已超出范围
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let pointforTargetview:CGPoint = self.convert(point, to: btnAngle)
if btnAngle.bounds.contains(pointforTargetview) {
return self
}
return super.hitTest(point, with: event)
}