滚动/调整 UITableView

Posted

技术标签:

【中文标题】滚动/调整 UITableView【英文标题】:scrolling/resizing UITableView 【发布时间】:2017-05-09 08:15:01 【问题描述】:

我会直入主题。

我有一个 UIViewController,里面有两个子视图。最上面的(我们从现在开始称它为 HeaderView)是自定义 UIView,而底部是 UITableView。 我已经在 InterfaceBuilder 中设置了它们,这样 HeaderView 的左边、顶部和右边的边距为 0,而且它有一个固定的高度。 UITableView 就在正下方,四周的边距为 0。

我的目标是实现这样一种行为,即当我开始滚动 UITableView 的内容时,HeaderView 将开始缩小并且 UITableView 变得更高而不滚动。这应该一直持续到 HeaderView 达到最小高度。之后 UITableView 应该开始正常滚动。向下滚动时,效果应该反转。

我最初是使用 UIScrollView 而不是 UITableView 开始的,我已经达到了预期的结果。方法如下:

    将 UIScrollView 连接到插座@IBOutlet weak var scrollView: UIScrollView!

    在控制器的viewDidLoad()方法中设置UIScrollViewDelegate self.scrollView.delegate = self 并声明 UIViewController 符合协议

    在 UIScrollView 滚动时拦截:func scrollViewDidScroll(_ scrollView: UIScrollView) self.adjustScrolling(offset: scrollView.contentOffset.y, scrollView: scrollView)

    在我的 adjustScrolling(offset:scrollView:) 方法中,“魔法”发生了

现在让我们看看这个方法会发生什么。

    private func adjustScrolling(offset: CGFloat, scrollView: UIScrollView) 

        // bind value between 0 and max header scroll
        let actualOffset: CGFloat = offset < 0 ? 0 : (offset >= self.maxHeaderScroll ? self.maxHeaderScroll : offset)

        // avoid useless calculations
        if (actualOffset == self.currentOffset) 
            return
        

        /**
         * Apply the vertical scrolling to the header
         */
        // Translate the header up to give more space to the scrollView
        let headerTransform = CATransform3DTranslate(CATransform3DIdentity, 0, -(actualOffset), 0)
        self.header.layer.transform = headerTransform
        // Adjust header's subviews to new size
        self.header.didScrollBy(actualOffset)

        /**
         * Apply the corrected vertical scrolling to the scrollView
         */
        // Resize the scrollView to fill all empty space
        let newScrollViewY = self.header.frame.origin.y + self.header.frame.height
        scrollView.frame = CGRect(
            x: 0,
            y: newScrollViewY,
            width: scrollView.frame.width,
            height: scrollView.frame.height + (scrollView.frame.origin.y - newScrollViewY)
        )
        // Translate the scrollView's content view down to contrast scrolling
        let scrollTransform = CATransform3DTranslate(CATransform3DIdentity, 0, (actualOffset), 0)
        scrollView.subviews[0].layer.transform = scrollTransform
        // Set bottom inset to show content hidden by translation
        scrollView.contentInset = UIEdgeInsets(
            top: 0,
            left: 0,
            bottom: actualOffset,
            right: 0
        )

        self.currentOffset = actualOffset
    

如果我没有忘记任何东西,这应该足以达到预期的效果。让我分解一下:

    我计算了将actualOffset 绑定在 0 和 self.MaxHeaderScroll 之间的值,即 67(我认为它是动态计算的,但这并不重要) 如果我看到actualOffset 自上次调用此函数以来没有更改,我不会费心去应用任何更改。这样可以避免一些无用的计算。 我通过在 y 轴上将 CATransform3DTranslate 向上平移到负 actualOffset 来将滚动应用于标题。 我调用self.header.didScrollBy(actualOffset) 以便HeaderView 可以在内部应用一些视觉更改。不过,这与问题无关。 我调整了 scrollView 的大小,现在 HeaderView 更高了,因此它从顶部和底部保持 0 边距。 我将滚动视图的内容向下平移相同的actualOffset 量以对比滚动。这件作品对于我想要实现的正确视觉效果至关重要。如果我不这样做,scrollView 仍会正确调整大小,但内容会立即开始滚动,这是我不想要的。只有在 HeaderView 达到其最小高度时,它才应该开始滚动。 我现在在 scrollView 中设置了一个底部插图,这样我就可以一直滚动到最后。如果没有这个,scrollView 的最后一部分将被切断,因为scrollView 本身会认为它到达了其内容的末尾。 最后我存储了actualOffset 供以后比较

正如我所说,这很好用。当我从 UIScrollView 切换到 UITableView 时出现问题。我认为它会起作用,因为 UITableView 继承自 UIScrollView。 唯一不起作用的代码是数字 6。我真的不知道出了什么问题,所以我只列出我发现和/或注意到的所有内容。希望有人能够帮助我。

对于 UIScrollView,在第 6 点中,scrollView.subviews[0] 指的是一个包含所有内容的视图。当我更改为 UITableView 时,此子视图似乎属于 UITableViewWrapperView 类型,我找不到任何有关它的文档,XCode 也没有将其识别为有效类。这已经令人沮丧了。 如果在第 6 点我还在 x 轴上进行了一些平移(假设是 50),我可以看到一个初始的非常快速的平移,该平移立即恢复为 0。这只发生在 UITableView 开始滚动时,它不会滚动时不要继续。 我已尝试在第 6 点更改子视图的框架以达到预期的效果。虽然滚动是正确的,但当我滚动 UITableView 时,顶部单元格开始消失。我认为这是因为我使用dequeueReusableCell(withIdentifier:for:) 来设置单元格,而 UITableView 认为顶部的单元格实际上是不可见的。我无法解决这个问题。 我尝试将self.tableView.tableHeaderView 设置为actualOffset 高度的UIView 以对比滚动,但这会产生奇怪的效果,即单元格无法正确滚动并且当UITableView 被带回初始位置时,会有成为顶部的差距。对此也没有任何线索。

我知道这里有很多,所以请不要犹豫,询问更多详细信息。提前谢谢你。

【问题讨论】:

只是做一个演示 @SeanLintern88 运气好吗? 嘿,我做了一个演示,但后来重新阅读了你的问题,不确定我是否涵盖了所有内容,请看演示 运气好吗?如果您有任何问题,我会在接下来的一个小时内:D 【参考方案1】:

我最近做了这样的事情,所以这是我实现它的方法:

制作一个具有高度约束常量的 UIView 并将其链接到您的视图/VC,您是否将 UITableview 约束到 UIView 后面的 VC 视图全屏。

现在将 UITableViews contentInset top 设置为“headerView”的起始高度,在 scrollViewDidScroll 中调整常量,直到标题的高度达到最小值。

Here is a demo

如果您只是运行它,蓝色区域是您的“标题”,而彩色行是任何单元格。你可以在蓝色区域自动布局任何你想要的东西,它应该自动调整大小和一切

【讨论】:

嘿伙计,多亏了你的例子,我设法让它工作了。太棒了,我欠你一个! 只要 *** 允许我,我也会奖励你赏金 :) 当你实现 targetContentOffset 时,它也会变得易货,这是另一个 scrollViewDelegate 方法,这意味着如果你需要的话,你可以停止在最小/最大高度之间结束的滚动动画 当我禁用弹跳属性并从默认状态向下滚动(在视觉上什么都不做)时,我遇到了一个问题,向上滚动而不抬起手指什么都不会发生,直到我到达y 点 i开始往下拖。为什么会这样?我们如何才能克服它以允许更快速的砍伐。找不到解决方案@SeanLintern

以上是关于滚动/调整 UITableView的主要内容,如果未能解决你的问题,请参考以下文章

在调整滚动视图大小时滚动到滚动视图页面

调整滚动视图框架的大小时,UIScrollView 子视图的大小调整不正确

csp怎么调滚动条大小

调整tree-select组件高度及横向滚动条

调整 UICollectionView 滚动速度/灵敏度

不要滚动元素调整大小