我遇到了类似问题:Capturing touches on a subview outside the frame of its superview using hitTest:withEvent:
场合
我们正在开发Xamarin iOS中的应用程序。我们有一个自定义视图来创建一个自己的autoComplete输入字段,其中包含一个UiTextField和一个UiTableView,用于显示结果。
为了实现更好的模块化,我们有另一个名为LabeledContainer的自定义视图。在其中,我可以设置标签并向底部视图添加内容,在这种情况下是autoComplete。
AutoComplete LabeledContainer
+---------------+ +---------------+
| UiView | | UiView |
|+-------------+| |+-------------+|
|| UiTextField || || UiLabel ||
|+-------------+| |+-------------+|
|+-------------+| |+-------------+|
|| UiTableView || || UiView ||
|+-------------+| |+-------------+|
+---------------+ +---------------+
The following gets rendered:
MAINVIEW
+------------------------------+
| |
| |
| |
| |
|+----------------------------+|
|| LabeledContainer ||
||+--------------------------+||
||| Label |||
||+--------------------------+||
||+--------------------------+||
||| Content |||
|||+------------------------+|||
|||| AutoComplete ||||
|||+------------------------+|||
||+--------------------------+||
|+----------------------------+|
| |
| |
| |
| |
+------------------------------+
问题
我遇到“hitarea”问题,因为autoComplete下拉列表(tableView)位于自定义视图框架之外。框架只占用输入字段的高度,下拉框架在底部重叠。所以我添加了以下方法来将下拉列表添加到hitArea。
public override bool PointInside(CGPoint point, UIEvent uievent)
{
var bounds = Bounds;
bounds.Height += DROPDOWN.Bounds.Height;
return bounds.Contains(point);
}
但是这只有在我将autoComplete添加为mainView的subChild时才有效,因为PointInside会在那里被触发。如果我将autoComplete添加到labeledContainer,后者的标签高度为自动完成的input + inputfield,则PointsInnside方法永远不会被触发。情况就是这样,因为带标签的容器不够高,对吧?那么当superView被触摸时,一个视图的PointsInside会被触发?但我不能使得labeledContainer或autoComplete更高,以防止推送其他视图。
我尝试将PointsInside方法也添加到labeledContainer,但它没有解决我的问题,因为它没有触及labeledContainer帧,并且从不调用autoComplete PointsInside。
答案 0 :(得分:4)
默认情况下,UIViews不会在其超级视图之外接收触摸事件。但是,您可以将容器视图子类化以检测其框架外的触摸。容器视图应将未处理的触摸事件转发到其子视图。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
CGPoint pointForTargetView = [self.autoCompleteView convertPoint:point fromView:self];
if (CGRectContainsPoint(self.autoCompleteView.bounds, pointForTargetView)) {
return [self.autoCompleteView hitTest:pointForTargetView withEvent:event];
}
return [super hitTest:point withEvent:event];
}
接收器范围之外的点永远不会被报告为 点击,即使他们实际上位于接收者的子视图之一。 如果设置了当前视图的剪辑To Bounds属性,则会发生这种情况 为NO,受影响的子视图超出了视图范围。
答案 1 :(得分:0)
我没有直接在下拉范围内测试命中,而是将hitTest委托给自定义自动完成视图。所以我没有公开dropdown属性,可以在我的自定义自动完成视图中测试它。
// Xamarin version - labeledContainer
public override UIView HitTest(CGPoint p, UIEvent e)
{
var translatedP = AutoComplete.ConvertPointFromView(p, this);
return AutoComplete.HitTest(translatedP, e) ?? base.HitTest(p, uievent);
}
此外,我必须像这样实现autoComplete的HitTest:
// Xamarin version - autoComplete
public override UIView HitTest(CGPoint p, UIEvent e)
{
var translatedP = DropDown.ConvertPointFromView(p, this);
return DropDown.HitTest(translatedP, e) ?? base.HitTest(p, uievent);
}
在这里,我翻译结果下拉列表的点,并检查它是否在里面。如果没有,则调用默认的HitTest来处理输入字段点击。