【问题标题】:UITableView InfiniteScrolling without reloading TableView in SwiftUITableView InfiniteScrolling 无需在 Swift 中重新加载 TableView
【发布时间】:2019-12-03 02:47:44
【问题描述】:

我正在尝试在 UITableView 中使用分页 API 实现无限滚动。因此,当到达底部单元格并重新加载整个 UITableView 时,我正在更新模型(再次调用 API 并附加结果)。我面临的问题是,当重新加载完成时,我看到屏幕上有闪烁,但我只想以平滑的方式在 tableView 中添加更多单元格,而不会出现任何闪烁。这是我写的相同内容:

class FeedViewController: UIViewController {    
    @IBOutlet private weak var tableView: UITableView!
    private var feed: Feed!

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        feed = Feed(delegate: self)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        feed.fetch(nextPage: true)
    }
}

//MARK: TableView
extension FeedViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return feed.articles.count + 1
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.row < feed.articles.count {
            guard let cell = tableView.dequeueReusableCell(withIdentifier: "FeedTableViewCell") as? FeedTableViewCell else {
                return UITableViewCell()
            }
            cell.delegate = self
            cell.setCell(article: feed.articles[indexPath.row])
            return cell
        }
        else if feed.articles.count > 0 && !feed.hasReachedEnd {
            guard let cell = tableView.dequeueReusableCell(withIdentifier: "LoaderTableViewCell") as? LoaderTableViewCell else {
                return UITableViewCell()
            }
            cell.addLoader()
            return cell
        }
        return UITableViewCell()
    }
}

extension FeedViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        if indexPath.row == feed.articles.count && !feed.hasReachedEnd {
            feed.fetch(nextPage: true)
        }
    }
}

//MARK: API Management
extension FeedViewController: FeedProtocol {
    func requestCompletedSuccessfully() {
        DispatchQueue.main.async { [weak self] in
            self?.loader.stopAnimating()
            self?.tableView.reloadData()
        }
    }

    func requestFailedWith(error: NSError?) {}
}

在这里您可能会看到,一旦获取请求完成,使用委托我将在那里重新加载整个 tableView,但如果可能的话,我需要一些更好的解决方案来避免这种闪烁。 请让我知道是否需要其他内容。谢谢

【问题讨论】:

    标签: ios swift uitableview reloaddata


    【解决方案1】:

    你应该做的是调用tableView.reloadRows 而不是tableView.reloadData。但为了做到这一点,您需要知道当 requestCompletedSuccessfully 执行时您的提要中有多少新元素。比如:

    let indexPaths = Array(previousFeedCount..<newFeedCount)
        .map { IndexPath(row: $0, section: 0) }
    tableView.reloadRows(at: indexPaths, with: .automatic)
    

    【讨论】:

    • 嗨 Rob,但这给了我以下错误.. 'NSInternalInconsistencyException',原因:'尝试从第 0 节中删除第 19 行,更新前仅包含 1 行',而 api 请求在打开时成功应用程序..
    • 嗨,Kautsya,我对这个错误很熟悉,但我必须看看你在代码中做了什么。
    • 你可以在这里找到完整的代码..github.com/kautsiitd/NewsApp我只是想知道比重新加载tableView更好的解决方案,同时在成功的Api调用上添加更多数据。如果我还有更多内容,请告诉我需要..
    • 好的,我明白你在做什么了。由于您使用的是核心数据,因此您应该使用 NSFetchResultsController。您可以自动检测新文章何时添加到核心数据中。发生这种情况时,您只需使用新数据更新表视图。这里有几篇很棒的文章可以帮助你前进。 cocoacasts.com/… 和 cocoacasts.com/…
    • 是的,但我只在打开应用程序时第一次使用 CoreData,如果有人点击刷新,那么我使用分页 API 来获取 20 块的标题。如何在远程情况下处理无限滚动然后?您可能会再次看到更新的项目。在 FeedViewController 中,您会注意到我只是在底部成功的 api 上重新加载整个 tableView。
    【解决方案2】:

    只需使用scrollView Delegate,tableview默认继承自UIScrollView,并将delegate设置为self。

    extension FeedViewController: UIScrollViewDelegate {
           func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    
            if self.tableView.contentOffset.y <= -10  {
    
                // table view reached top place your pull to refresh call here
            } else if ((tableView.contentOffset.y + tableView.frame.size.height) >= tableView.contentSize.height) {
                //table view reached last record, fetch next records here
                // tableview usually flickers if content to be reloaded is out of screen bounds. There is one hack to avoid that, add replace these three lines with tableView.reloadData() line
                UIView.setAnimationsEnabled(false)
                tableView.reloadData()
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                    UIView.setAnimationsEnabled(true)
                }
           }
        }
    }
    

    【讨论】:

    • 那将是非常糟糕的黑客攻击但是..我更喜欢@umer的任何其他解决方案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-21
    • 2016-06-19
    相关资源
    最近更新 更多