如何通过不在全屏 UITableView 的 UIEdgeInsets 中的屏幕上的点传递点击手势:

Posted

技术标签:

【中文标题】如何通过不在全屏 UITableView 的 UIEdgeInsets 中的屏幕上的点传递点击手势:【英文标题】:How to pass tap gesture through point on screen that is not in full-screen UITableView's UIEdgeInsets: 【发布时间】:2018-10-03 08:43:02 【问题描述】:

我创建了一个屏幕,其中我有一个全屏UITableView,我为其设置了UIEdgeInsets,我的配置如下:

categoriesTableView.contentInset = UIEdgeInsets.init(top: HEADER_VIEW_HEIGHT, left: 0, bottom: 0, right: 0)

其中HEADER_VIEW_HEIGHTCGFloat = 160

这允许我向UITableView 添加一个“标题视图”,当我开始滚动UITableView 时,它会被覆盖(......并且不会像真正的标题视图那样卡在 UITableView 上方)。

问题:问题是我需要在标题视图中有3个可点击的视图,所以我在故事板中设计了3个视图并在它们上配置了Tap Gesture Recognizers。但是当我尝试使用它们时,即使我在屏幕上看到这些视图(由于 contentInset 配置),点击手势也不会传递UITableView。我可以让它们可点击/可点击的唯一方法是,如果我在 UITableView 上将 User Interaction Enabled 设置为 false(我不能这样做,因为我需要 UITableView 也可以拖动和点击)。

问题:如果由于 contentInset 设置而未被UITableView 覆盖,我如何将点击事件传递给较低的“标题视图”可点击部分?

这是 UI 图像,在其中您可以看到有一个全屏 UITableView,在它后面有一个包含 3 个子视图的视图,其中包含 3 个最喜欢的项目,我可以将它们呈现给用户以便更轻松地访问。当屏幕启动时,UITableView 有一个 contentInset,因此用户可以看到这些简单的访问选项并按下它们(他现在不能这样做)。当用户开始滚动时,UITableView 会出现在具有 3 个视图的布局顶部,并且用户可以全屏滚动列表。有点像视差效果。

【问题讨论】:

【参考方案1】:

我对此有一个非常丑陋的解决方案..

现在你有一个表格视图,下面有一个标题视图,对吧?在 table view 的顶部再添加一个 view,其中包含 3 个 subviews,并且颜色都是透明的。

将这个新添加的子视图定位为与标题视图相同的位置(通过以编程方式提供与标题视图相同的框架或将其顶部、左侧、底部和右侧约束连接到标题视图)。同样,将这个新视图的 3 个子视图定位为与标题视图内的子视图相同。并对这个新视图的子视图进行轻击手势。所以我们的用户会认为他在点击标题视图,而他实际上是在这个不可见的视图中点击。

如果你想在表格视图向上滚动并覆盖标题视图时触摸它,那么你可以使用这两者之一..

    调用 UIScrollViewDelegate 委托方法 scrollViewDidScroll() 并在里面如果 scrollView.contentOffset.y >= 160,为这个新添加的视图将 User Interaction Enabled 设置为 false,如果 scrollView.contentOffset.y 则将其恢复为 true

    或者从scrollViewDidScroll()内部,赋值outletOfTopConstraintOfYourNewView.constant = -(scrollView.contentOffset.y),这样新视图也会随着滚动向上移动,从而改变其可见的可点击区域。

另一个不太优雅的想法是..

不提供 contentInset,而是在此表视图中的第 0 个索引处再添加一个部分,其中只有一个高度为 160 的单元格,用户交互启用为 false,颜色为透明。那么你就不用担心scrollViewDidScroll()中的逻辑了。

【讨论】:

是的,我正在考虑类似的事情,但就像你说的那样,这确实是一个丑陋的解决方案,我希望可以在系统中使用更优雅的东西来将水龙头传递给现有视图而不是创建一个新的透明的。如果我没有其他建议,我可能会这样做,没有其他选择,但我希望情况并非如此。暂时给你 +1,希望能提供帮助 我已对答案进行了编辑。也请检查一下。 我不能真正使用你的第二个建议,因为我在设计上对 UITableView 有阴影。所以如果我添加第一个透明视图,阴影会落在它后面,这会导致外观不好。在任何其他情况下,我认为这将是更好的解决方案,也许除了您需要通过 +1 班次处理数据这一事实。【参考方案2】:

更新:

以下解决方案并不完美,但它可能会给你一个开始的方向。

A) 将tableView 的top 约束放在headerview 的top 约束。

B) 在 ViewController 中创建 headerview 高度约束的 IBOutlet

C) 监听tableview的ScrollViewDidScroll,放这样的代码

func scrollViewDidScroll(_ scrollView: UIScrollView) 
            let y = scrollView.contentOffset.y
            if y > 50
                if heightConstant.constant != 0
                    view.layoutIfNeeded()
                    heightConstant.constant = 0
                    UIView.animate(withDuration: 0.5, delay: 0, options: .allowUserInteraction, animations: 
                        self.view.layoutIfNeeded()
                    , completion: nil)

                
            else
                view.layoutIfNeeded()
                heightConstant.constant = 160
                UIView.animate(withDuration: 0.5, delay: 0, options: .allowUserInteraction, animations: 
                    self.view.layoutIfNeeded()
                , completion: nil)
            
        

这里的 50 是它应该开始动画的点形式。它有点类似于 android 中的 Collapsable Toolbar。只需确保 headerView.isClipsToBounds = true。


将您的 headerview 转换为 UITableViewCell 并将您的 UITableViewDataSource 更改为

extension ViewController: UITableViewDataSource
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return section == 0 ? 1 : yourList.count
    

    func numberOfSections(in tableView: UITableView) -> Int 
        return 2
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        if indexPath.section == 0
            // set your header view here
        else
            // Your normal cell configuration
        
    

有了这个,你的 headerview 将成为 table view 的一部分,但作为 UITableViewCell 因此它不会像普通的那样像粘性 header 那样表现。

【讨论】:

感谢您的回答,但我不能真正使用您的建议,因为我在设计上对 UITableView 有阴影。因此,如果我添加一个视图作为第一部分,那么阴影会落在它后面,这将导致外观不好。 @EmilAdz 你能发一张 UI 的图片吗? 他想要的效果与@SahilManchanda不同。他实际上想要粘性行为。但是,与其在滚动时表格视图在标题视图后面,他希望表格视图滑过标题视图的顶部,从而隐藏它(有点像whatsapp的联系信息页面中的滚动)。 @SahilManchanda,已在问题中发布,感谢您的帮助。 @SahilManchanda,我现在尝试了您的第二个建议,抱歉花了我一些时间,还有其他任务。问题是,由于动画对 tableview 滚动做出反应,这感觉很迟钝,当我真正在 tableview 滚动以更改边界和约束而不是触发另一个时,我设法通过以前的实现获得了更好的点响应动画。

以上是关于如何通过不在全屏 UITableView 的 UIEdgeInsets 中的屏幕上的点传递点击手势:的主要内容,如果未能解决你的问题,请参考以下文章

如何不在我的 UITableView 上显示“...”?

UITableview:部分标题不会自动调整全屏点击的位置

拖动滚动 UITableView 本身而不是其内容

不全屏时如何获取全屏(最小ui)视图的窗口大小?

React-Native-Video 如何在视频未全屏或不在屏幕时暂停视频

不在 UITableView 中时如何设置 UITableViewCell 的选定背景颜色