UIScrollView 不会将点击手势传播给其子项

Posted

技术标签:

【中文标题】UIScrollView 不会将点击手势传播给其子项【英文标题】:UIScrollView does not propagate tap gesture to its children 【发布时间】:2015-09-10 08:07:54 【问题描述】:

我被困在这个问题上,没有其他关于 SO 的问题对我有帮助...

我有实现 UIGestureRecognizerDelegate 的视图控制器。有几个视图,其中一个是 contentView,在 contentView 内部,有一个 UIScrollView。同样在该滚动视图内部,还有一个 scrollContentView,它是简单的 UIView,但它包含更多子视图,由于空间原因,我没有在代码示例中包含这些子视图。一切正常(经过很长时间),但看起来没有传播点击手势,将 UIScrollView 扔到子视图..

我没有使用故事板。

我尝试了一切,任何帮助将不胜感激。

class MyController: PopoverController, UITableViewDelegate, UIGestureRecognizerDelegate

    var scrollPane: UIScrollView!

    var myContentView: UIView!

    var bottomPane: EditOrderItemBottomPaneView!


    var quantityPaneView: QuantityPaneView!

    var optionsTable: OptionsTableView!

    var modificationsTable: ModificationsTableView!

    var specialPricingsTable: SpecialPricingsTableView!


    override func viewDidLoad()
    
        super.viewDidLoad()

        categoriesModel = DIContainer.get().getCategoriesModel()
        activeOrderModel = DIContainer.get().getActiveOrderModel()
        modificationModel = DIContainer.get().getProductModificationsModel()

        orderItem = popoverModel.get("orderItem") as! OrderItem!
        let category: ProductCategory = categoriesModel.getCategoryById(orderItem.categoryId)!

        titleLabel.text = category.name

        // scroll view
        scrollPane = UIScrollView()
        scrollPane.translatesAutoresizingMaskIntoConstraints = false
        scrollPane.delegate = self
        contentView.addSubview(scrollPane)

        // bottom pane
        bottomPane = EditOrderItemBottomPaneView()
        contentView.addSubview(bottomPane)

        contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[scrollView][bottomView]|", options: [], metrics: nil, views: ["scrollView": scrollPane, "bottomView": bottomPane]))
        contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[scrollView]|", options: [], metrics: nil, views: ["scrollView": scrollPane]))
        contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[bottomView]|", options: [], metrics: nil, views: ["bottomView": bottomPane]))

        // scroll content view
        myContentView = UIView()
        myContentView.translatesAutoresizingMaskIntoConstraints = false
        scrollPane.addSubview(myContentView)
        scrollPane.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[content]|", options: [], metrics: nil, views: ["content": myContentView]))
        scrollPane.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[content]|", options: [], metrics: nil, views: ["content": myContentView]))

        contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[content]|", options: [], metrics: nil, views: ["content": myContentView]))
        contentView.addConstraint(NSLayoutConstraint(item: myContentView, attribute: NSLayoutAttribute.Trailing,
                relatedBy: NSLayoutRelation.Equal, toItem: contentView, attribute: NSLayoutAttribute.Trailing,
                multiplier: 1, constant: 0))
        contentView.addConstraint(NSLayoutConstraint(item: myContentView, attribute: NSLayoutAttribute.Leading,
                relatedBy: NSLayoutRelation.Equal, toItem: contentView, attribute: NSLayoutAttribute.Leading,
                multiplier: 1, constant: 0))

        // quantity pane
        quantityPaneView = QuantityPaneView()
        myContentView.addSubview(quantityPaneView)

        // options table
        let optionsDataSource: OrderItemOptionsTableViewDataSource = DIContainer.get().getOrderItemOptionsTableViewDataSource()
        optionsDataSource.orderItem = orderItem
        if optionsDataSource.getNumberOfOptions() > 0 
            optionsTable = OptionsTableView(delegate: DIContainer.get().getOrderItemOptionsTableViewDelegate(),
                    dataSource: optionsDataSource, orderItem: orderItem)
            myContentView.addSubview(optionsTable)
        

        // modifications table
        modificationsTable = ModificationsTableView(
        delegate: DIContainer.get().getOrderItemModificationsTableViewDelegate(),
                dataSource: DIContainer.get().getOrderItemModificationsTableViewDataSource(),
                orderItem: orderItem)
        myContentView.addSubview(modificationsTable)

        // special pricing table
        specialPricingsTable = SpecialPricingsTableView(
        delegate: DIContainer.get().getOrderItemSpecialPricingsTableViewDelegate(),
                dataSource: DIContainer.get().getOrderItemSpecialPricingsTableViewDataSource(),
                orderItem: orderItem)
        myContentView.addSubview(specialPricingsTable)

        var views = [
                "quantityPane": quantityPaneView,
                "modifications": modificationsTable,
                "specialPricings": specialPricingsTable
        ]

        myContentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-25-[quantityPane]-25-|", options: [], metrics: nil, views: views))
        myContentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-25-[modifications]-25-|", options: [], metrics: nil, views: views))
        myContentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-25-[specialPricings]-25-|", options: [], metrics: nil, views: views))

        if optionsDataSource.getNumberOfOptions() > 0 
            views["options"] = optionsTable
            myContentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-25-[options]-25-|", options: [], metrics: nil, views: views))
            myContentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[quantityPane]-25-[options]-25-[modifications]-25-[specialPricings]", options: [], metrics: nil, views: views))
        
        else 
            myContentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[quantityPane]-25-[modifications]-25-[specialPricings]", options: [], metrics: nil, views: views))
        
    

    override func viewDidLayoutSubviews()
    
        super.viewDidLayoutSubviews()

        var h: CGFloat = 0.0
        for view: UIView in myContentView.subviews 
            h += view.frame.size.height;
        

        scrollPane.contentSize = CGSizeMake(myContentView.frame.size.width, h)
    

    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool
    
        return true
    

    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool
    
        if touch.view != scrollPane 
            return false
        

        return true
    

【问题讨论】:

我想你忘了添加 uigesturerecognizerdelegate 添加并在代表是否调用时尝试 我已经实现了那个委托协议,但是没有调用方法 你能显示你更新的代码吗 我编辑了我的问题,所以现在有该控制器的完整代码 看到这个链接可能对你有用***.com/questions/2627934/… 【参考方案1】:

实现 UIGestureRecognizer 委托方法。

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch

    if (touch.view != yourScrollView)  
        return NO;
    
    return YES;

【讨论】:

好吧,还是不行……我在这个方法中有断点,它没有被调用。有什么建议吗?你想让我提供一些更详细的信息吗?顺便说一句,你从哪里得到这些信息的?你能指点我一些资源吗?非常感谢【参考方案2】:

我意识到整个屏幕设计得非常糟糕。我没有解决问题,但我重新实现了整个控制器。我仍然认为有可能解决这个问题,但有更简单的方法。

关键是,我在滚动内容视图中有更多的表格视图。当然,也可以只创建一个包含更多部分的表。这样做的副作用是一个表格视图本身是可滚动的,因此不需要使用自定义 UIScrollView。

因此,对于开始进行 ios 开发的每个人,请尽可能使用带有更多部分的 UITableView。

【讨论】:

以上是关于UIScrollView 不会将点击手势传播给其子项的主要内容,如果未能解决你的问题,请参考以下文章

从另一个视图将滚动手势传递给 UIScrollView

如何使用点击事件使其不会传播到视图

将捏合手势从自定义 UIView 传递到父 UIScrollView

UIScrollView及其子类的嵌套联动

Xamarin IOS UILabel在UIScrollView中点击手势不起作用

禁用 UIScrollView 手势