当视图首次加载其项目时,我尝试滚动到collectionView的底部。我在viewDidLoad中运行此函数:
private func fetchMessages() {
guard let r = replyTo else { return }
let urlString = "\(Config.URL)/api/messages/replyTo/\(r)/offset/\(offset)"
guard let authToken = Auth.getToken() else { return }
let headers = ["Authorization": "Bearer \(authToken)"]
Alamofire.request(urlString, headers: headers).responseJSON { (response) in
guard let value = response.result.value else { return }
let json = JSON(value)
for messagesJSON in json["messages"].arrayValue {
let message = Message(json: messagesJSON.dictionaryObject ?? [:])
self.messages.append(message)
}
self.messages.reverse()
DispatchQueue.main.async {
self.collectionView?.reloadData()
let indexPath = IndexPath(item: self.messages.count - 1, section: 0)
self.collectionView?.scrollToItem(at: indexPath, at: .bottom, animated: false)
}
}
}
我得到最后一个indexPath,然后使用scrollToItem滚动到底部,但它不想滚动到底部。它根本不滚动。除了滚动之外,一切都有效。
答案 0 :(得分:3)
Taimoor的回答是正确的(本质上)但我想添加一些背景为什么:
当整个视图加载到内存中时,会调用 viewDidLoad()
,包括所有子视图。但是,此时视图尚未布局,即所有子视图的帧尚未正确设置或换句话说:使用自动布局时,您的约束尚未解决但是当viewDidLoad()
被调用时。
因此,集合视图的框架未正确设置,但其大小可能仍为.zero
。因此,集合视图无法将任何单元格滚动到其框架中 - 或者至少方法scrollToItem(at:, at:, animated:)
会出现意外行为。
您可以确定布局完成的一点是viewDidLayoutSubviews()
。但是,请注意,在视图控制器的生命周期内可能会多次调用此方法 - 只要布局中的某些内容发生更改,就会触发另一个布局过程。您可能不希望在发生这种情况时一次又一次地获取数据,因此您需要以某种方式跟踪此情况。
如果你想保持简单,viewDidAppear()
也会起作用,因为当视图可见时,它显然已经布局,但用户可能会看到集合视图的滚动/跳转。
viewWillAppear()
也可能有用但不保证。
答案 1 :(得分:2)
viewDidLoad ,因此无法很好地操作某些UI元素。比如在工作中移动按钮但处理子视图通常不会(比如滚动CollectionView)。
大多数这些操作在viewWillAppear或viewDidAppear中调用时效果最佳。所以尝试在 viewWillAppear 或 viewDidAppear 中执行此操作。