滚动/调整大小 UITableView



我会直奔主题。

我有一个UIView控制器,里面有两个子视图。顶部的(让我们从现在开始称之为HeaderView)是一个自定义UIView,底部是一个UITableView。
我已经在界面构建器中设置了它们,以便 HeaderView 从左、上和右边有 0 边距,而且它有一个固定的高度。 UITableView 位于正下方,所有边距为 0。

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

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

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

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

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

  4. 在我的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
}

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

  1. 我计算在 0 和self.MaxHeaderScroll之间绑定它的actualOffset,只有 67(我认为,它是动态计算的,但这并不重要)
  2. 如果我看到自上次调用此函数以来actualOffset没有更改,我懒得进行任何更改。这避免了一些无用的计算。
  3. 我通过将滚动应用于标题,只需在 y 轴上用CATransform3DTranslate将其平移为负actualOffset
  4. 我调用self.header.didScrollBy(actualOffset),以便 HeaderView 可以在内部应用一些视觉更改。不过,这并不能回答这个问题。
  5. 我调整了滚动视图的大小,以便它从顶部和底部保持 0 边距,因为 HeaderView 更高。
  6. 我将滚动视图的内容向下翻译相同的actualOffset量以对比滚动。这件作品对于我想要实现的正确视觉效果至关重要。如果我不这样做,scrollView 仍然会正确调整大小,但内容会立即开始滚动,这是我不想要的。只有在 HeaderView 达到其最小高度后,它才应开始滚动。
  7. 我现在在 scrollView 中设置了一个底部内嵌,以便能够一直滚动到最后。如果没有这个,scrollView的最后一部分将被切断,因为scrollView本身会认为它到达了其内容的末尾。
  8. 最后,我存储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 恢复到初始位置时,顶部会有一个间隙。对此也毫无头绪。

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

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

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

现在将UITableViews内容Inset顶部设置为"headerView"的起始高度,在scrollViewDidScroll中,您可以调整常量,直到标题的高度达到最小值。

这是一个演示

如果您只是运行它,蓝色区域是您的"标题",彩色行只是任何单元格。您可以在蓝色区域中自动布局任何您想要的内容,它应该自动调整大小和所有内容

最新更新