如何延迟滚动时更改 UIView 大小
How can I change UIView size on scroll w/ a delay
我有一个 UIView
锚定到 top
、leading
和 trailing
锚点。它的初始高度为 138
并且应该收缩到不小于 88
.
我有一个 UITableView
锚定到这个视图的底部,它也锚定到超级视图的 leading
、trailing
和底部。
它不是 header 视图的 table 视图,而是一个单独的视图。
滚动 table 视图时,我希望我的 UIView
缩小并重置回初始大小,具体取决于滚动方向。
- 向上滚动=缩小到不少于
88
- 向下滚动 = 增加到不超过
138
我目前可以通过使用
来实现这一点
func scrollViewDidScroll(_ scrollView: UIScrollView) {
onUserScroll?(scrollView)
}
通过绑定触发下面的代码
class FeedView: UIView {
private(set) var brandedHeader: UIView!
private(set) var brandedHeaderHeight: NSLayoutConstraint!
private(set) var tableView: UITableView!
private lazy var maxHeaderHeight: CGFloat = 138
private lazy var minHeaderHeight: CGFloat = 88
private var previousScrollOffset: CGFloat = 0
...............
}
extension FeedView {
func setTableViewDelegate(_ delegate: TableViewDelegate) {
tableView.delegate = delegate
tableView.dataSource = delegate
}
func onUserScroll(_ scrollView: UIScrollView) {
let scrollDiff = scrollView.contentOffset.y - self.previousScrollOffset
let absoluteTop: CGFloat = 0
let absoluteBottom: CGFloat = scrollView.contentSize.height - scrollView.frame.size.height
let isScrollingDown = scrollDiff > 0 && scrollView.contentOffset.y > absoluteTop
let isScrollingUp = scrollDiff < 0 && scrollView.contentOffset.y < absoluteBottom
guard canAnimateHeader(scrollView) else { return }
// Calculate new header height
var newHeight = self.brandedHeaderHeight.constant
if isScrollingDown {
newHeight = max(self.minHeaderHeight, self.brandedHeaderHeight.constant - abs(scrollDiff))
} else if isScrollingUp {
newHeight = min(self.maxHeaderHeight, self.brandedHeaderHeight.constant + abs(scrollDiff))
}
// Header needs to animate
if newHeight != self.brandedHeaderHeight.constant {
self.brandedHeaderHeight.constant = newHeight
self.setScrollPosition(self.previousScrollOffset)
}
self.previousScrollOffset = scrollView.contentOffset.y
}
private func canAnimateHeader(_ scrollView: UIScrollView) -> Bool {
// Calculate the size of the scrollView when header is collapsed
let scrollViewMaxHeight = scrollView.frame.height + self.brandedHeaderHeight.constant - minHeaderHeight
// Make sure that when header is collapsed, there is still room to scroll
return scrollView.contentSize.height > scrollViewMaxHeight
}
private func setScrollPosition(_ position: CGFloat) {
self.tableView.contentOffset = CGPoint(x: self.tableView.contentOffset.x, y: position)
}
}
但是我想做的是延迟调整大小事件。
目前,它会在向上或向下滚动时立即开始,事实上,我想让它在用户向上滚动 X 量后开始调整大小,然后仅在他们再次通过该点时向下滚动时才调整大小。
我更新了我的代码如下
private var previousScrollOffset: CGFloat = 100 // offset the initial scroll so the header does not shrink immediately on scroll
然后还有
func onUserScroll(_ scrollView: UIScrollView) {
guard scrollView.contentOffset.y < 200 else { return }
..........
}
但这并没有像预期的那样工作。
希望能实现和大标题导航栏滚动效果一样的效果
使用多个 y-constants 开始 shrinking/revealing 顶栏。
例如
如果向下滚动并显示栏并且 contentOffset.y
大于 500 - 缩小它。
如果向上滚动条缩小并且 contentOffset.y
小于 300 - 显示它。
用
更新您的onUserScroll
函数
let isScrollingDown = scrollDiff > 0 && scrollView.contentOffset.y > absoluteTop && scrollView.contentOffset.y > 300
let isScrollingUp = scrollDiff < 0 && scrollView.contentOffset.y < absoluteBottom && scrollView.contentOffset.y < 300
我相信你应该会得到想要的效果。
我有一个 UIView
锚定到 top
、leading
和 trailing
锚点。它的初始高度为 138
并且应该收缩到不小于 88
.
我有一个 UITableView
锚定到这个视图的底部,它也锚定到超级视图的 leading
、trailing
和底部。
它不是 header 视图的 table 视图,而是一个单独的视图。
滚动 table 视图时,我希望我的 UIView
缩小并重置回初始大小,具体取决于滚动方向。
- 向上滚动=缩小到不少于
88
- 向下滚动 = 增加到不超过
138
我目前可以通过使用
来实现这一点func scrollViewDidScroll(_ scrollView: UIScrollView) {
onUserScroll?(scrollView)
}
通过绑定触发下面的代码
class FeedView: UIView {
private(set) var brandedHeader: UIView!
private(set) var brandedHeaderHeight: NSLayoutConstraint!
private(set) var tableView: UITableView!
private lazy var maxHeaderHeight: CGFloat = 138
private lazy var minHeaderHeight: CGFloat = 88
private var previousScrollOffset: CGFloat = 0
...............
}
extension FeedView {
func setTableViewDelegate(_ delegate: TableViewDelegate) {
tableView.delegate = delegate
tableView.dataSource = delegate
}
func onUserScroll(_ scrollView: UIScrollView) {
let scrollDiff = scrollView.contentOffset.y - self.previousScrollOffset
let absoluteTop: CGFloat = 0
let absoluteBottom: CGFloat = scrollView.contentSize.height - scrollView.frame.size.height
let isScrollingDown = scrollDiff > 0 && scrollView.contentOffset.y > absoluteTop
let isScrollingUp = scrollDiff < 0 && scrollView.contentOffset.y < absoluteBottom
guard canAnimateHeader(scrollView) else { return }
// Calculate new header height
var newHeight = self.brandedHeaderHeight.constant
if isScrollingDown {
newHeight = max(self.minHeaderHeight, self.brandedHeaderHeight.constant - abs(scrollDiff))
} else if isScrollingUp {
newHeight = min(self.maxHeaderHeight, self.brandedHeaderHeight.constant + abs(scrollDiff))
}
// Header needs to animate
if newHeight != self.brandedHeaderHeight.constant {
self.brandedHeaderHeight.constant = newHeight
self.setScrollPosition(self.previousScrollOffset)
}
self.previousScrollOffset = scrollView.contentOffset.y
}
private func canAnimateHeader(_ scrollView: UIScrollView) -> Bool {
// Calculate the size of the scrollView when header is collapsed
let scrollViewMaxHeight = scrollView.frame.height + self.brandedHeaderHeight.constant - minHeaderHeight
// Make sure that when header is collapsed, there is still room to scroll
return scrollView.contentSize.height > scrollViewMaxHeight
}
private func setScrollPosition(_ position: CGFloat) {
self.tableView.contentOffset = CGPoint(x: self.tableView.contentOffset.x, y: position)
}
}
但是我想做的是延迟调整大小事件。
目前,它会在向上或向下滚动时立即开始,事实上,我想让它在用户向上滚动 X 量后开始调整大小,然后仅在他们再次通过该点时向下滚动时才调整大小。
我更新了我的代码如下
private var previousScrollOffset: CGFloat = 100 // offset the initial scroll so the header does not shrink immediately on scroll
然后还有
func onUserScroll(_ scrollView: UIScrollView) {
guard scrollView.contentOffset.y < 200 else { return }
..........
}
但这并没有像预期的那样工作。
希望能实现和大标题导航栏滚动效果一样的效果
使用多个 y-constants 开始 shrinking/revealing 顶栏。
例如
如果向下滚动并显示栏并且 contentOffset.y
大于 500 - 缩小它。
如果向上滚动条缩小并且 contentOffset.y
小于 300 - 显示它。
用
更新您的onUserScroll
函数
let isScrollingDown = scrollDiff > 0 && scrollView.contentOffset.y > absoluteTop && scrollView.contentOffset.y > 300
let isScrollingUp = scrollDiff < 0 && scrollView.contentOffset.y < absoluteBottom && scrollView.contentOffset.y < 300
我相信你应该会得到想要的效果。