单击内部选项卡时保持 ScrollView 位置(其中刷新内部数据)
Keep ScrollView position when clicking a tab inside (which refresh data inside)
滚动视图 - 内容视图 - 1) 图像,2) 选项卡,3) 堆栈视图
以上是我的分镜安排。 选项卡实际上是集合视图。选项卡下方,有堆栈视图 (也在内容视图中)。当我单击每个选项卡时,我 将所选选项卡的索引 发送到 didSelect。它将调用具有以下流程的 refreshData 函数:堆栈视图 中的 当前子视图 将被删除 (使用 vc.mainStack.subviews.forEach({ $0.removeFromSuperview() })) 并将 根据索引 重新加载另一个子视图所选选项卡的。图片的位置将保持不变,即页面顶部。但是,每次我单击该选项卡时,屏幕总是会滚动到顶部。如何保持滚动位置(在我点击另一个标签之前),以便当我点击新标签时,它会保持在相同的滚动位置?
self.yContentOffset = scrollView.contentOffset.y
已经在 scrollViewDidScroll 中添加了上面的代码并且
vc.scrollView.contentOffset.y = self.yContentOffset
删除堆栈中的所有子视图后添加上面的代码,然后我调用新数据(用于子视图)。还尝试在调用新子视图后添加代码,但两者都不起作用。有谁知道如何做到这一点的逻辑?
听起来问题是 UI 在您删除当前子视图和添加新子视图之间 "refreshed"。因此,您的 mainStack
变得非常短,导致内容视图不够高,无法滚动,您的滚动视图会相应地自行调整。
您的选择是等待删除子视图,直到您有新的子视图,然后删除/添加相同的功能,或者用清晰的 "placeholder" 视图替换子视图。
第二个选项可能如下所示:
func replaceViewsWithPlaceholderView() -> Void {
// get an array of the current views in the stack
let viewsToRemove = mainStack.arrangedSubviews
// create a clear view
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .clear
// needs a width
v.widthAnchor.constraint(equalToConstant: 1).isActive = true
// constrain the height of the "place holder" view to the current height of the stack view
v.heightAnchor.constraint(equalToConstant: mainStack.frame.height).isActive = true
// add the "place holder" view to the stack
mainStack.addArrangedSubview(v)
// remove the views that were in the stack
viewsToRemove.forEach {
[=10=].removeFromSuperview()
}
}
然后在根据所选选项卡添加新子视图的函数中,首先:
// remove the "place holder" view
mainStack.arrangedSubviews.forEach {
[=11=].removeFromSuperview()
}
接着(可能是 .forEach
循环)将新的子视图添加到 main.Stack
。
当然,如果您已经滚动,所以您的 "tabs" 位于滚动视图的顶部,并且 "tab B" 没有足够的子视图需要滚动,滚动视图将再次调整- 但仅限于内容视图底部位于滚动视图底部的位置。
滚动视图 - 内容视图 - 1) 图像,2) 选项卡,3) 堆栈视图
以上是我的分镜安排。 选项卡实际上是集合视图。选项卡下方,有堆栈视图 (也在内容视图中)。当我单击每个选项卡时,我 将所选选项卡的索引 发送到 didSelect。它将调用具有以下流程的 refreshData 函数:堆栈视图 中的 当前子视图 将被删除 (使用 vc.mainStack.subviews.forEach({ $0.removeFromSuperview() })) 并将 根据索引 重新加载另一个子视图所选选项卡的。图片的位置将保持不变,即页面顶部。但是,每次我单击该选项卡时,屏幕总是会滚动到顶部。如何保持滚动位置(在我点击另一个标签之前),以便当我点击新标签时,它会保持在相同的滚动位置?
self.yContentOffset = scrollView.contentOffset.y
已经在 scrollViewDidScroll 中添加了上面的代码并且
vc.scrollView.contentOffset.y = self.yContentOffset
删除堆栈中的所有子视图后添加上面的代码,然后我调用新数据(用于子视图)。还尝试在调用新子视图后添加代码,但两者都不起作用。有谁知道如何做到这一点的逻辑?
听起来问题是 UI 在您删除当前子视图和添加新子视图之间 "refreshed"。因此,您的 mainStack
变得非常短,导致内容视图不够高,无法滚动,您的滚动视图会相应地自行调整。
您的选择是等待删除子视图,直到您有新的子视图,然后删除/添加相同的功能,或者用清晰的 "placeholder" 视图替换子视图。
第二个选项可能如下所示:
func replaceViewsWithPlaceholderView() -> Void {
// get an array of the current views in the stack
let viewsToRemove = mainStack.arrangedSubviews
// create a clear view
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .clear
// needs a width
v.widthAnchor.constraint(equalToConstant: 1).isActive = true
// constrain the height of the "place holder" view to the current height of the stack view
v.heightAnchor.constraint(equalToConstant: mainStack.frame.height).isActive = true
// add the "place holder" view to the stack
mainStack.addArrangedSubview(v)
// remove the views that were in the stack
viewsToRemove.forEach {
[=10=].removeFromSuperview()
}
}
然后在根据所选选项卡添加新子视图的函数中,首先:
// remove the "place holder" view
mainStack.arrangedSubviews.forEach {
[=11=].removeFromSuperview()
}
接着(可能是 .forEach
循环)将新的子视图添加到 main.Stack
。
当然,如果您已经滚动,所以您的 "tabs" 位于滚动视图的顶部,并且 "tab B" 没有足够的子视图需要滚动,滚动视图将再次调整- 但仅限于内容视图底部位于滚动视图底部的位置。