ios - UITableView 直到 viewDidAppear 才会呈现
问题描述
我正在使用Hero动画过渡到 a UITableViewController
,它以某种方式导致我在被调用UITableView
之前不渲染任何单元格。viewDidAppear()
我已经确定 UITableView确实在调用之前很久就完成了加载viewDidAppear()
(使用日志记录和时间戳),并且已经使用打印语句来确定在调用UITableView
时出现的确切时间。viewDidAppear()
其他一些堆栈溢出帖子建议放在tableView.reloadData()
主线程上,我已经这样做了(无济于事)。
import UIKit
import os.log
import Hero
class MemberTableViewController: UITableViewController, UIGestureRecognizerDelegate {
// MARK: Properties
var members: [Member]?
// drag to exit
var panGestureRecognizer: UIPanGestureRecognizer!
var progressBool: Bool = false
var dismissBool: Bool = false
// MARK: Overrides
override func viewDidLoad() {
super.viewDidLoad()
// register cells
tableView.register(UINib(nibName: "MemberTableViewCell", bundle: Bundle.main), forCellReuseIdentifier: "MemberCell")
// configure hero
view.hero.isEnabled = true
view.hero.isEnabledForSubviews = false
view.hero.id = "members"
view.hero.modifiers = [.arc(), .useLayerRenderSnapshot]
// fetch members
API.shared.getMembers { members in
self.members = members
DispatchQueue.main.async {
self.tableView.reloadSections(IndexSet(arrayLiteral: 0), with: .fade)
}
}
// setup drag to exit
panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(exit))
panGestureRecognizer.delegate = self
view.addGestureRecognizer(panGestureRecognizer)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// customize navigationbar
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.backgroundColor = self.tableView.backgroundColor
self.navigationController?.setNavigationBarHidden(false, animated: animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("appeared")
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
override var prefersHomeIndicatorAutoHidden: Bool {
return true
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return members?.count ?? 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "MemberCell", for: indexPath) as? MemberTableViewCell else {
fatalError("Dequeued cell not an instance of MemberTableViewCell")
}
// Configure the cell...
cell.load(from: members![indexPath.row])
return cell
}
// MARK: Private Methods
@objc private func exit(recognizer: UIPanGestureRecognizer) {
let translation = recognizer.translation(in: nil)
let progressY = (translation.y / 2) / view.bounds.height
if recognizer.direction == .down && tableView.isAtTop {
if dismissBool {
dismissBool = false
hero.dismissViewController()
self.hero.modalAnimationType = .uncover(direction: .down)
progressBool = true
recognizer.setTranslation(.zero, in: view)
}
}
switch recognizer.state {
case .changed:
if progressBool {
let currentPos = CGPoint(x: view.center.x, y: translation.y + view.center.y)
Hero.shared.update(progressY)
Hero.shared.apply(modifiers: [.position(currentPos)], to: view)
}
default:
dismissBool = true
progressBool = false
if abs(progressY + recognizer.velocity(in: nil).y / view.bounds.height) > 0.5 {
Hero.shared.finish()
} else {
Hero.shared.cancel()
}
}
}
// MARK: UIGestureRecognizerDelegate
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
// MARK: UIScrollViewDelegate
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.isAtTop && scrollView.panGestureRecognizer.direction == .down {
scrollView.contentOffset = CGPoint(x: 0, y: -(UIApplication.shared.keyWindow?.safeAreaInsets.top ?? 0)
)
}
}
}
我希望UITableView
在动画完成的那一刻出现,并且tableView.reloadSections()
动画要播放,但似乎动画在UITableView
实际出现之前发生,所以它只是在一点延迟后才闪现(看起来很糟糕,见下文)。
注意:禁用 Hero 后,tableView.reloadSections()
动画播放没有延迟。
解决方案
我没有使用您提到的框架,但是您可以尝试添加延迟以重新加载 tableview,直到视图完成渲染:
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
self.tableView.reloadSections(IndexSet(arrayLiteral: 0), with: .fade)
}
三秒钟是很长的时间。我喜欢称其为“穴居人”调试。三秒是一个奇怪的时间,所以如果它有效,请尝试减少延迟因素。
另一个想法是在主队列上也设置成员,所以是这样的:
DispatchQueue.main.async {
self.members = members
self.tableView.reloadSections(IndexSet(arrayLiteral: 0), with: .fade)
}
另一个想法是将您的重新加载移动到viewDidAppear()
.
更新
这是一个断言,您可以使用它来等待视图完全加载并完成调整大小:
var tableViewLoaded: Bool = false
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
guard isViewLoaded, view.window != nil, !tableViewLoaded else { return }
tableView.reloadSections(IndexSet(arrayLiteral: 0), with: .fade)
tableViewLoaded = true // flip it to true so you don't constantly reload
}
推荐阅读
- java - 什么相当于 Flux 中 Mono 的 doOnSuccess 方法?
- c - 如何使用以下结构初始化双向链表?
- excel - 计算符合条件的唯一值
- java - 乘法数组表
- python - Python在列表中找到相似的元素组合
- web-applications - 我可以将哪种 OAuth2 授权类型用于 LAN Web 应用程序?
- javascript - 传单地图未完全加载。在开始时它正确加载,但是当我想以大的高度和宽度打开它时,它只会加载一半的瓷砖
- c# - 从 ListView 获取 ListViewItem 而不是 Item
- angular - 基于模块的项目结构角度
- c++ - 内联函数/变量的外部链接