iOS 11 使用大标题无法正常滚动到顶部
iOS 11 scroll to top when using large titles doesn't work properly
当使用大标题并点击状态栏滚动到 UIScrollView
或 UITableView
的顶部时(可能还有 UICollectionView
,还没有测试过)总是这样有点过分了。
我在我的 TableView
上启用了刷新,当点击状态栏时,它显示为这样并保持这种状态,直到我点击屏幕。
我在另一个 ViewController
中有一个 ScrollView
,如果我点击那里的状态栏,它也会滚动得有点远,使导航栏太高。当我点击某处或滚动一点点时,这也 returns 正常。
正常:
点击状态栏后:
这也只发生在我激活大标题时,使用普通标题一切正常。
有什么解决办法吗?
如何重新创建:
- 创建一个新项目,其中包含一个导航控制器和一个
UIViewController
,里面有一个 TableView
。
- 将导航控制器设置为更喜欢大标题。关闭半透明。在
UIViewController
上设置标题
- 在
TableView
上设置约束以固定到 ViewController
的边缘
- 在
ViewController
中为 TableView
创建出口
- 实施委托并设置行数,例如 100
- 启动应用程序
- 向下滚动,使大标题变成普通标题
- 点击状态栏使
tableView
滚动到顶部
现在标题不在应有的位置,如果您现在向上或向下滚动一点点,它会快速回到正常位置。
ViewController
代码:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath)
return cell
}
}
好的,所以我找到了问题发生的原因,但没有找到在那种情况下如何解决它。
如果您使用大标题和导航栏半透明设置为关闭的 UITableViewController,则会出现问题。
当您重新打开半透明时,问题就消失了。
如果您在普通的 UIViewController 中使用 TableView,问题总是会发生。
编辑
事实证明,如果您使用的是半透明导航栏,设置 "extendedLayoutIncludesOpaqueBars = true" 可以解决问题![=11=]
经过几个小时的测试,我找到了一个适用于 UIViewController 的解决方案。
在带有 UITableView 的 UIViewController 中,您应该:
- 在 viewDidLoad 中设置 extendedLayoutIncludesOpaqueBars = true
- 在情节提要中,将 tableView 顶部约束固定到 superview 顶部,常量 = 0(当导航栏半透明时,tableView 将位于导航栏和状态栏下方)
之后,如果您点击状态栏,tableview 会停在正确的位置。
我已经通过在滚动到顶部后手动将 contentOffset 设置为 0 来修复它。
func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
return true
}
func scrollViewDidScrollToTop(_ scrollView: UIScrollView) {
scrollView.contentOffset.y = 0.0
}
在您的 ViewController 中声明一个 Bool 类型的 var didBeginScrollToTop。
将控制器指定为 scrollView 的委托。然后
func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
didBeginScrollToTop = true
return true
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard didBeginScrollToTop, scrollToTopGestureTargetView?.contentOffset.y ?? 0 < -25 else { return }
scrollToTopGestureTargetView?.setContentOffset(.zero, animated: true)
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
didBeginScrollToTop = false
}
这样做是在弹跳时调整您的内容偏移量。该标志用于捕获 scrollToTop 手势并在滚动时重置。您也可以在设置 .zero 偏移量后将其关闭。如果您有子 VC 的实现,请不要忘记在重写这 3 个委托方法时调用 super。
现在我的第一个方法是跟踪内容 offSet 何时 < 0,但是在某些设备上它没有展开导航项并且魔法 -25 似乎适用于所有模拟器。您可以将此方法与 returns 导航栏大小的实现结合起来并替换它,但据我所知,没有一种简单的方法可以如此轻松地获得导航栏 frame/bounds .
注意你可能还需要处理这个:
我遇到了同样的问题。我在 UINavigationController 中嵌入了 UIViewController 中的集合视图。 Collectionview 对安全区域有前导、尾随、顶部、底部约束。
要解决此问题,您需要:
- 将 collectionview 的顶部约束更改为 supervises(非安全区域)
- 在 viewDidLoad 方法中设置 extendedLayoutIncludesOpaqueBars = true
当使用大标题并点击状态栏滚动到 UIScrollView
或 UITableView
的顶部时(可能还有 UICollectionView
,还没有测试过)总是这样有点过分了。
我在我的 TableView
上启用了刷新,当点击状态栏时,它显示为这样并保持这种状态,直到我点击屏幕。
我在另一个 ViewController
中有一个 ScrollView
,如果我点击那里的状态栏,它也会滚动得有点远,使导航栏太高。当我点击某处或滚动一点点时,这也 returns 正常。
正常:
点击状态栏后:
这也只发生在我激活大标题时,使用普通标题一切正常。
有什么解决办法吗?
如何重新创建:
- 创建一个新项目,其中包含一个导航控制器和一个
UIViewController
,里面有一个TableView
。 - 将导航控制器设置为更喜欢大标题。关闭半透明。在
UIViewController
上设置标题
- 在
TableView
上设置约束以固定到ViewController
的边缘
- 在
ViewController
中为 - 实施委托并设置行数,例如 100
- 启动应用程序
- 向下滚动,使大标题变成普通标题
- 点击状态栏使
tableView
滚动到顶部
TableView
创建出口
现在标题不在应有的位置,如果您现在向上或向下滚动一点点,它会快速回到正常位置。
ViewController
代码:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TestCell", for: indexPath)
return cell
}
}
好的,所以我找到了问题发生的原因,但没有找到在那种情况下如何解决它。
如果您使用大标题和导航栏半透明设置为关闭的 UITableViewController,则会出现问题。 当您重新打开半透明时,问题就消失了。
如果您在普通的 UIViewController 中使用 TableView,问题总是会发生。
编辑
事实证明,如果您使用的是半透明导航栏,设置 "extendedLayoutIncludesOpaqueBars = true" 可以解决问题![=11=]
经过几个小时的测试,我找到了一个适用于 UIViewController 的解决方案。
在带有 UITableView 的 UIViewController 中,您应该:
- 在 viewDidLoad 中设置 extendedLayoutIncludesOpaqueBars = true
- 在情节提要中,将 tableView 顶部约束固定到 superview 顶部,常量 = 0(当导航栏半透明时,tableView 将位于导航栏和状态栏下方)
之后,如果您点击状态栏,tableview 会停在正确的位置。
我已经通过在滚动到顶部后手动将 contentOffset 设置为 0 来修复它。
func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
return true
}
func scrollViewDidScrollToTop(_ scrollView: UIScrollView) {
scrollView.contentOffset.y = 0.0
}
在您的 ViewController 中声明一个 Bool 类型的 var didBeginScrollToTop。 将控制器指定为 scrollView 的委托。然后
func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
didBeginScrollToTop = true
return true
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard didBeginScrollToTop, scrollToTopGestureTargetView?.contentOffset.y ?? 0 < -25 else { return }
scrollToTopGestureTargetView?.setContentOffset(.zero, animated: true)
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
didBeginScrollToTop = false
}
这样做是在弹跳时调整您的内容偏移量。该标志用于捕获 scrollToTop 手势并在滚动时重置。您也可以在设置 .zero 偏移量后将其关闭。如果您有子 VC 的实现,请不要忘记在重写这 3 个委托方法时调用 super。 现在我的第一个方法是跟踪内容 offSet 何时 < 0,但是在某些设备上它没有展开导航项并且魔法 -25 似乎适用于所有模拟器。您可以将此方法与 returns 导航栏大小的实现结合起来并替换它,但据我所知,没有一种简单的方法可以如此轻松地获得导航栏 frame/bounds .
注意你可能还需要处理这个:
我遇到了同样的问题。我在 UINavigationController 中嵌入了 UIViewController 中的集合视图。 Collectionview 对安全区域有前导、尾随、顶部、底部约束。
要解决此问题,您需要:
- 将 collectionview 的顶部约束更改为 supervises(非安全区域)
- 在 viewDidLoad 方法中设置 extendedLayoutIncludesOpaqueBars = true