重新加载表会导致闪烁

下面有一个search栏和一个表格视图。 当我search一些networking调用时,10个项目被添加到一个数组来填充表格。 当我滚动到表格的底部时,另一个networking电话是另外10个项目,所以现在有20个项目在数组…这可以继续下去,因为它是一个无限的滚动类似Facebook的新闻饲料。

每次我进行networking调用时,我也在主线程上调用self.tableView.reloadData()由于每个单元格都有一个图像,因此您可以看到闪烁 – 单元格图像闪烁白色

我试着实现这个解决scheme,但我不知道把它放在我的代码或如何。 我的代码是Swift,那就是Objective-C。

有什么想法吗?

更新到问题1

 override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier(R.reuseIdentifier.searchCell.identifier, forIndexPath: indexPath) as! CustomTableViewCell let book = booksArrayFromNetworkCall[indexPath.row] // Set dynamic text cell.titleLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline) cell.authorsLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleFootnote) // Update title cell.titleLabel.text = book.title // Update authors cell.authorsLabel.text = book.authors /* - Getting the CoverImage is done asynchronously to stop choppiness of tableview. - I also added the Title and Author inside of this call, even though it is not necessary because there was a problem if it was outside: the first time a user presses Search, the call for the CoverImage was too slow and only the Title and Author were displaying. */ Book.convertURLToImagesAsynchronouslyAndUpdateCells(book, cell: cell, task: task) return cell } 

cellForRowAtIndexPath在里面使用这个方法:

  class func convertURLToImagesAsynchronouslyAndUpdateCells(bookObject: Book, cell: CustomTableViewCell, var task: NSURLSessionDataTask?) { guard let coverImageURLString = bookObject.coverImageURLString, url = NSURL(string: coverImageURLString) else { return } // Asynchronous work being done here. task = NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data, response, error) -> Void in dispatch_async(dispatch_get_main_queue(), { // Update cover image with data guard let data = data else { return } // Create an image object from our data let coverImage = UIImage(data: data) cell.coverImageView.image = coverImage }) }) task?.resume() } 

当我滚动到桌子的底部时,我发现我是否用willDisplayCell触及底部。 如果是底部,则再次进行相同的networking呼叫。

  override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { if indexPath.row+1 == booksArrayFromNetworkCall.count { // Make network calls when we scroll to the bottom of the table. refreshItems(currentIndexCount) } } 

这是networking通话代码。 当我在search栏上按下Enter时,它会被第一次调用,然后每当我到达单元格的底部,就会调用它,就像你在willDisplayCell看到的willDisplayCell

  func refreshItems(index: Int) { // Make to network call to Google Books GoogleBooksClient.getBooksFromGoogleBooks(self.searchBar.text!, startIndex: index) { (books, error) -> Void in guard let books = books else { return } self.footerView.hidden = false self.currentIndexCount += 10 self.booksArrayFromNetworkCall += books dispatch_async(dispatch_get_main_queue()) { self.tableView.reloadData() } } } 

如果只有图像闪烁白色,并且旁边的文本没有显示,可能当您调用reloadData() ,图像再次从源下载,从而导致闪存。 在这种情况下,您可能需要将图像保存在caching中。

我build议使用SDWebImagecaching图像并asynchronous下载。 这是非常简单的,我用在我的大部分项目。 为了确认是这样的,只需从你的资产添加一个静态图像到单元格,而不是调用convertURLToImagesAsynchronouslyAndUpdateCells ,你会看到它不会再次闪烁。

我不'编程在斯威夫特,但我看到它就像cell.imageView.sd_setImageWithURL(myImageURL)一样简单。 它完成了!

这是一个使用insertRowsAtIndexPaths(_:withRowAnimation:)的无限滚动示例

 class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { @IBOutlet weak var tableView: UITableView! var dataSource = [String]() var currentStartIndex = 0 // We use this to only fire one fetch request (not multiple) when we scroll to the bottom. var isLoading = false override func viewDidLoad() { super.viewDidLoad() // Load the first batch of items. loadNextItems() } // Loads the next 20 items using the current start index to know from where to start the next fetch. func loadNextItems() { MyFakeDataSource().fetchItems(currentStartIndex, callback: { fetchedItems in self.dataSource += fetchedItems // Append the fetched items to the existing items. self.tableView.beginUpdates() var indexPathsToInsert = [NSIndexPath]() for i in self.currentStartIndex..<self.currentStartIndex + 20 { indexPathsToInsert.append(NSIndexPath(forRow: i, inSection: 0)) } self.tableView.insertRowsAtIndexPaths(indexPathsToInsert, withRowAnimation: .Bottom) self.tableView.endUpdates() self.isLoading = false // The currentStartIndex must point to next index. self.currentStartIndex = self.dataSource.count }) } // #MARK: - Table View Data Source Methods func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return dataSource.count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = UITableViewCell() cell.textLabel!.text = dataSource[indexPath.row] return cell } // #MARK: - Table View Delegate Methods func scrollViewDidScroll(scrollView: UIScrollView) { if isLoading == false && scrollView.contentOffset.y + scrollView.bounds.size.height > scrollView.contentSize.height { isLoading = true loadNextItems() } } } 

MyFakeDataSource是无关紧要的,它可能是你的GoogleBooksClient.getBooksFromGoogleBooks ,或者你正在使用的任何数据源。

尝试在调用[tableView reloadData]方法之前和之后更改表阿尔法值..类似

 dispatch_async(dispatch_get_main_queue()) { self.aTable.alpha = 0.4f; self.tableView.reloadData() [self.aTable.alpha = 1.0f; } 

我已经用相同的方法在UIWebView重新加载..它为我工作。