接收界外的触摸事件

Raj*_*esh 14 uikit ios swift

之前有类似的问题,我已经提到使用hitTest:withEvent:在其超视图框架之外的子视图上捕获触摸,并将触摸事件传递到其父视图边界之外的视图.但他们似乎没有回答我的特殊问题.

我有一个具有以下结构的自定义控件:

+-------------------------------+
|           UIButton            |
+-------------------------------+
|                          |
|                          |
|        UITableView       |
|                          |
|                          |
+------------------------- +
Run Code Online (Sandbox Code Playgroud)

自定义控件会覆盖UIButton子类并将UITableView其添加为其子视图.这个想法是让整个控件像下拉列表一样.当UIButton按下时,UITableView将下拉列表和使选择的选择.

如果控件是最顶层的直接子项,这一切都适用hitTestUIButton上面Apple的Q&A链接中所描述的被覆盖的内容UIView.但是,如果控件位于另一个视图层次结构中,UITableView则不会接收触摸事件.

以下是使用的hitTest代码:

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
    // Convert the point to the target view's coordinate system.
    // The target view isn't necessarily the immediate subview
    let pointForTargetView = self.spinnerTableView.convertPoint(point, fromView:self) 

    if (CGRectContainsPoint(self.spinnerTableView.bounds, pointForTargetView)) {
        // The target view may have its view hierarchy,
        // so call its hitTest method to return the right hit-test view
        return self.spinnerTableView.hitTest(pointForTargetView, withEvent:event);
    }
    return super.hitTest(point, withEvent: event)
}
Run Code Online (Sandbox Code Playgroud)

编辑:

我很抱歉没有能够查看答案并检查他们是否解决了问题,因为其他一些任务需要立即引起注意.我会检查它们并接受一个有帮助的.谢谢你的耐心.

Nev*_*ess 5

如你所说:

但是,如果控件位于另一个视图层次结构中,则UITableView不会接收触摸事件.

即使你让它工作了,如果你已经在另一个UIView下查看了这个控件?

这样我们就有了为视图层次结构转换点的负担,我的建议是,正如您在此控件中看到的那样,它将tableview添加到控件本身所在的同一层次结构中.(例如,它在添加了此控件的控制器上添加了表视图)

链接的一部分:

-(void)textFieldDidBeginEditing:(UITextField *)textField
{
    [self setupSuggestionList];
    [suggestionListView setHidden:NO];

    // Add list to the super view.
    if(self.dataSourceDelegate && [self.dataSourceDelegate isKindOfClass:UIViewController.class])
    {
        [((UIViewController *)self.dataSourceDelegate).view addSubview:suggestionListView];
    }

    // Setup list as per the given direction
    [self adjustListFrameForDirection:dropDownDirection];
}
Run Code Online (Sandbox Code Playgroud)

希望有所帮助!


maq*_*ene 5

我认为你应该重写pointInside实现:

\n\n
class Control: UIButton {\n\n    var dropdown: Bool = false\n\n    override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {\n        if dropdown {\n            return CGRectContainsPoint(CGRect(x: 0, y:0, width: self.bounds.width, self.bounds.height + spinnerTableView.frame.height), point)\n        }\n        return super.pointInside(point, withEvent: event)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

像这样,当超级视图调用控件hittest超出控件边界时,它不会返回 nil。

\n\n

但仍然存在一个问题\xef\xbc\x8c 如果控件位于另一个视图层次结构中,UITableView 可能无法接收触摸事件。

\n\n

我认为这个问题很正常\xef\xbc\x8c你无法决定其他视图的点在哪个控制之下,如果控制超级视图hitTest返回nil,控制hitTest方法将不会被调用。\n除非你覆盖了pointInside该控制下的所有视图方法控制,但不现实。

\n


Ale*_*ano 3

我在想UIResponder,类似的事情:

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
        // Convert the point to the target view's coordinate system.
        // The target view isn't necessarily the immediate subview

        var responder: UIResponder = self
        while responder.nextResponder() != nil {
            responder = responder.nextResponder()!
            if responder is UITableView {
                // Got UITableView
                break;
            }
        }
        let pointForTargetView = responder.convertPoint(point, fromView:self)
        if (CGRectContainsPoint(responder.bounds, pointForTargetView)) {
            // The target view may have its view hierarchy,
            // so call its hitTest method to return the right hit-test view
            return self.responder.hitTest(pointForTargetView, withEvent:event);
        }
        return super.hitTest(point, withEvent: event)
}
Run Code Online (Sandbox Code Playgroud)

如果此方法不起作用,请尝试convertPoint使用 superview:

当您确定它self.spinnerTableView不为零并且它是您的表时,请执行以下操作:

let pointForTargetView = self.spinnerTableView.superView.convertPoint(point, fromView:self) 
Run Code Online (Sandbox Code Playgroud)