我正在尝试实现一个自定义顶部栏,其行为类似于iOS 11+大标题导航栏,该栏的大标题部分在向下滚动内容时会折叠:
区别在于,我的栏需要自定义高度,并且底部需要滚动时不会塌陷。我设法使该部分正常工作:
该栏是使用UIStackView&实施的,并具有一些非必需的布局约束,但我相信其内部实现是不相关的。最重要的是,栏的高度与滚动视图的顶部contentInset
相关联。这些是由contentOffset
方法中的scrollview的UIScrollViewDelegate.scrollViewDidScroll
驱动的:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let topInset = (-scrollView.contentOffset.y).limitedBy(topBarHeightRange)
// changes both contentInset and scrollIndicatorInsets
adjustTopContentInset(topInset)
// changes top bar height
heightConstraint?.constant = topInset
adjustSmallTitleAlpha()
}
topBarHeightRange
存储最小和最大钢筋高度
我遇到的一个问题是,当用户停止滚动滚动视图时,该条可能会以半折叠状态结束。再次,让我们看一下所需的行为:
内容偏移量被捕捉到紧凑高度或扩展高度,以“更近”为准。我正在尝试在UIScrollViewDelegate.scrollViewWillEndDragging
方法中实现相同的目标:
func scrollViewWillEndDragging(_ scrollView: UIScrollView,
withVelocity velocity: CGPoint,
targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let targetY = targetContentOffset.pointee.y
// snaps to a "closer" value
let snappedTargetY = targetY.snappedTo([topBarHeightRange.lowerBound, topBarHeightRange.upperBound].map(-))
targetContentOffset.pointee.y = snappedTargetY
print("Snapped: \(targetY) -> \(snappedTargetY)")
}
当我查看打印输出时,它表明targetContentOffset
已正确修改。但是,在应用程序中,在视觉上,内容偏移仅捕捉到紧凑的高度,而不捕捉到扩展的高度(您可以观察到,较大的“标题”标签最终被切成两半,而不是切回到“扩展”位置。 / p>
我怀疑此问题与在用户滚动时更改contentInset.top
有关,但是我不知道如何解决此问题。
很难解释这个问题,所以我希望GIF有所帮助。这是仓库:https://github.com/AleksanderMaj/ScrollView
有什么主意如何使scrollview / bar组合正确对齐到紧凑/扩展高度?
答案 0 :(得分:1)
我看了看你的项目并喜欢你的实现。
我在您的scrollViewWillEndDragging
方法中提出了一个解决方案,方法是在方法末尾添加以下代码:
if abs(targetY) < abs(snappedTargetY) {
scrollView.setContentOffset(CGPoint(x: 0, y: snappedTargetY), animated: true)
}
基本上,如果向下滚动量不值得隐藏大标题(如果targetY小于snappedTargetY,则会发生这种情况),只需滚动到snappedTargetY的值即可显示大标题。
似乎暂时可以使用,但是如果您遇到任何错误或找到改进方法,请告诉我。
整个scrollViewWillEndDragging方法:
func scrollViewWillEndDragging(_ scrollView: UIScrollView,
withVelocity velocity: CGPoint,
targetContentOffset: UnsafeMutablePointer<CGPoint>) {
let targetY = targetContentOffset.pointee.y
// snaps to a "closer" value
let snappedTargetY = targetY.snappedTo([topBarHeightRange.lowerBound, topBarHeightRange.upperBound].map(-))
targetContentOffset.pointee.y = snappedTargetY
if abs(targetY) < abs(snappedTargetY) {
scrollView.setContentOffset(CGPoint(x: 0, y: snappedTargetY), animated: true)
}
print("Snapped: \(targetY) -> \(snappedTargetY)")
}