[英]scrolling/resizing UITableView
I'll get right to the point. 我会讲到重点。
I have a UIViewController that has two subviews in it. 我有一个UIViewController,其中有两个子视图。 The top one (let's call it HeaderView from now one) is a custom UIView and the bottom one is a UITableView. 顶部的是一个自定义的UIView(下面将其称为HeaderView),而底部的是一个UITableView。
I have set them up in InterfaceBuilder so that the HeaderView has 0 margin from the left, top and right, plus it has a fixed height. 我已经在InterfaceBuilder中对其进行了设置,以便HeaderView的左侧,顶部和右侧的边距为0,并且其高度固定。 The UITableView is directly underneath with 0 margin from all sides. UITableView在所有面的正下方,且页边距为0。
My goal is to achieve a behaviour such that when I start scrolling the UITableView's content the HeaderView will start shrinking and the UITableView becomes higher without scrolling. 我的目标是实现一种行为,当我开始滚动UITableView的内容时,HeaderView将开始缩小,并且UITableView会变得更高而无需滚动。 This should go on until the HeaderView has reached a minimum height. 这应该一直进行到HeaderView达到最小高度为止。 After that the UITableView should start scrolling as normal. 之后,UITableView应该开始正常滚动。 When scrolling down the effect should be reversed. 向下滚动时,效果应相反。
I have initially started this out using a UIScrollView instead of the UITableView and I have achieved the desired result. 我最初是使用UIScrollView而不是UITableView来开始的,并且已经达到了预期的结果。 Here is how: 方法如下:
connect the UIScrollView to the outlet 将UIScrollView连接到插座
@IBOutlet weak var scrollView: UIScrollView!
set the UIScrollViewDelegate in the controller's viewDidLoad()
method self.scrollView.delegate = self
and declared the UIViewController to conform to the protocol 在控制器的viewDidLoad()
方法中设置UIScrollViewDelegate self.scrollView.delegate = self
并声明UIViewController符合协议
intercept when the UIScrollView scrolls: 在UIScrollView滚动时进行拦截:
func scrollViewDidScroll(_ scrollView: UIScrollView) { self.adjustScrolling(offset: scrollView.contentOffset.y, scrollView: scrollView) }
in my adjustScrolling(offset:scrollView:)
method the "magic" happens 在我的adjustScrolling(offset:scrollView:)
方法中,“魔术”发生了
Now let's look at what happens in this method. 现在让我们看看这种方法会发生什么。
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
}
If I haven't forgotten anything this should be enough to achieve the desired effect. 如果我没有忘记任何内容,这应该足以实现所需的效果。 Let me break it down: 让我分解一下:
actualOffset
binding it between 0 and self.MaxHeaderScroll
which is just 67 (I think, it's calculated dynamically but this doesn't really matter) 我计算actualOffset
0之间结合它self.MaxHeaderScroll
这仅仅是67(我认为,它是动态计算的,但这并不重要) actualOffset
hasn't changed since the last time this function was called I don't bother to aplly any changes. 如果我发现自从上次调用此函数以来, actualOffset
并没有发生变化,那么我就不会麻烦地进行任何更改。 This avoids some useless calculations. 这避免了一些无用的计算。 CATransform3DTranslate
on just the y axis by negative actualOffset
. 我将滚动应用于标题,方法是将CATransform3DTranslate
沿y轴actualOffset
,而负的actualOffset
。 self.header.didScrollBy(actualOffset)
so that the HeaderView can apply some visual changes internally. 我调用self.header.didScrollBy(actualOffset)
以便HeaderView可以在内部应用一些可视更改。 This doesn't concearn the question though. 但这并没有掩盖问题。 actualOffset
amount to contrast the scrolling. 我向下滚动scrollView的内容时,实际的actualOffset
量相同,以对比滚动。 This piece is essential to the correct visual effect that I want to achieve. 对于我想要实现的正确视觉效果而言,这是必不可少的。 If I didn't do this, the scrollView would still resize correctly but the content would start scrolling right away, which I don't want. 如果我不这样做,scrollView仍会正确调整大小,但是内容将立即开始滚动,这是我不希望的。 It should only start scrolling once the HeaderView reaches it's minimum height. 仅应在HeaderView达到最小高度后才开始滚动。 actualOffset
for later comparison 最后,我存储了actualOffset
供以后比较 As I said, this works fine. 正如我所说,这很好。 The problem arises when I switch from a UIScrollView to a UITableView. 当我从UIScrollView切换到UITableView时出现问题。 I assumed it would work since UITableView inherits from UIScrollView. 由于UITableView继承自UIScrollView,因此我认为它会起作用。
The only piece of code that doesn't work is the number 6. I don't really know what is going wrong so I will just list everything I have found out and/or noticed. 唯一不起作用的代码是数字6。我真的不知道出了什么问题,所以我只列出我发现和/或注意到的所有内容。 Hopefully someone will be able to help me out. 希望有人能够帮助我。
scrollView.subviews[0]
refers to a view that holds all the content inside it. 对于UIScrollView,在点6中, scrollView.subviews[0]
引用一个视图,其中包含所有内容。 When I change to UITableView this subview seems to be of the type UITableViewWrapperView
which I could not find any documentation about, nor does XCode recognize it as a valid class. 当我更改为UITableView时,此子视图似乎是UITableViewWrapperView
类型,找不到任何文档,XCode也不将其识别为有效类。 This is already frustrating. 这已经令人沮丧。 dequeueReusableCell(withIdentifier:for:)
to instatiate the cells and the UITableView thinks that the top cells aren't visible when they actually are. 我之所以稀疏是因为我正在使用dequeueReusableCell(withIdentifier:for:)
实例化单元格,并且UITableView认为顶部的单元格实际上并不可见。 I wasn't able to work around this problem. 我无法解决此问题。 self.tableView.tableHeaderView
to a UIView of the actualOffset
height to contrast scrolling but this gave a weird effect where the cells would not scroll correctly and when the UITableView was brought back to the initial position, there would be a gap on top. 我尝试将self.tableView.tableHeaderView
设置为actualOffset
高度的UIView进行对比度滚动,但这产生了怪异的效果,即单元格无法正确滚动,并且当UITableView返回初始位置时,会出现间隙在上面。 No clue about this either. 也没有任何线索。 I know there's a lot here so please don't hesitate asking for more details. 我知道这里有很多东西,所以请随时询问更多详细信息。 Thank you in advance. 先感谢您。
I made something like this recently, so heres how I achieved it: 我最近做了这样的事情,所以这是我如何实现的:
Make a UIView with a height constraint constant and link this to your view/VC, have you UITableview constrained to the VC's view full screen behind the UIView. 使一个具有高度约束常量的UIView并将其链接到您的视图/ VC,将UITableview约束到UIView后面的VC全屏视图。
Now set your UITableViews contentInset top to the starting height of your 'headerView' now, in the scrollViewDidScroll you adjust the constant until the height of the header is at its minimum. 现在,将UITableViews contentInset顶部设置为“ headerView”的起始高度,在scrollViewDidScroll中,调整常量,直到标题的高度最小为止。
If you just run it, the blue area is your 'header' and the colored rows are just any cell. 如果只运行它,则蓝色区域是您的“标题”,而彩色行则是任何单元格。 You can autolayout whatever you want in the blue area and it should auto size and everything 您可以在蓝色区域中自动布局任何内容,它应该会自动调整大小和所有内容
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.