繁体   English   中英

捕获超视图框架外的子视图(多层)

[英]Capturing touches on a subview outside the frame of its superview (over multiple layers)

我在这个帖子中描述了一个类似的问题: 使用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。

默认情况下,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];
}

来自Apple的文档

位于接收者界限之外的点永远不会被报告为命中,即使它们实际上位于接收者的子视图中。 如果当前视图的剪辑To Bounds属性设置为NO并且受影响的子视图超出视图的边界,则会发生这种情况。

巴图,非常感谢你的帮助。 我现在在你的建议的帮助下找到了类似的解决方案。

我没有直接在下拉列表边界中测试命中,而是将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来处理输入字段单击。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM