我正在使用Hero为过渡到UITableViewController
的动画设置动画,这导致我的UITableView
在调用viewDidAppear()
之后才渲染任何单元格。 / p>
我已经确定UITableView 在调用viewDidAppear()
之前(使用日志记录和时间戳记)早已完成加载,并且已使用print语句确定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
实际出现之前,因此稍等一会儿(看起来很糟,请参阅下文)后,它就会闪烁进入视野。
注意:禁用英雄功能后,tableView.reloadSections()
动画将立即播放。
答案 0 :(得分:1)
我没有使用您提到的框架,但是您可以尝试增加重新加载tableview的延迟,直到视图完成渲染为止:
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
self.tableView.reloadSections(IndexSet(arrayLiteral: 0), with: .fade)
}
三秒钟是很长的时间。我喜欢称之为“ caveman”调试。三秒钟是非常荒谬的时间,因此,如果可行,请尝试减少延迟因子。
另一种想法是也将成员设置在主队列上,所以类似这样:
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
}