限制tableView中显示的单元格数量,滚动到最后一个单元格时加载更多单元格

Posted

技术标签:

【中文标题】限制tableView中显示的单元格数量,滚动到最后一个单元格时加载更多单元格【英文标题】:Limit the amount of cells shown in tableView, load more cells when scroll to last cell 【发布时间】:2017-12-13 17:05:33 【问题描述】:

我正在尝试设置仅显示特定数量的单元格的表格视图。显示该单元格后,用户可以继续滚动以显示更多单元格。截至目前,我正在检索要在 viewDidLoad 中显示的所有 JSON 数据并将它们存储在一个数组中。仅出于示例目的,我首先尝试仅显示 2 个单元格,用户滚动到屏幕底部的一个单元格将出现下一个单元格。到目前为止,这是我的代码:

class DrinkViewController: UIViewController 

  @IBOutlet weak var drinkTableView: UITableView!


  private let networkManager = NetworkManager.sharedManager

  fileprivate var totalDrinksArray: [CocktailModel] = []
  fileprivate var drinkImage: UIImage?

  fileprivate let DRINK_CELL_REUSE_IDENTIFIER = "drinkCell"
  fileprivate let DRINK_SEGUE = "detailDrinkSegue"

  var drinksPerPage = 2
  var loadingData = false

  override func viewDidLoad() 
    super.viewDidLoad()

    drinkTableView.delegate = self
    drinkTableView.dataSource = self

    networkManager.getJSONData(function: urlFunction.search, catagory: urlCatagory.cocktail, listCatagory: nil, drinkType: "margarita", isList: false, completion:  data in

      self.parseJSONData(data)

    )
  



extension DrinkViewController 

  //MARK: JSON parser
  fileprivate func parseJSONData(_ jsonData: Data?)
    if let data = jsonData 

      do 
        let jsonDictionary = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String : AnyObject]//Parses data into a dictionary

        // print(jsonDictionary!)
        if let drinkDictionary = jsonDictionary!["drinks"] as? [[String: Any]] 
          for drink in drinkDictionary 
            let drinkName = drink["strDrink"] as? String ?? ""
            let catagory = drink["strCategory"] as? String
            let drinkTypeIBA = drink["strIBA"] as? String
            let alcoholicType = drink["strAlcoholic"] as? String
            let glassType = drink["strGlass"] as? String
            let drinkInstructions = drink["strInstructions"] as? String
            let drinkThumbnailUrl = drink["strDrinkThumb"] as? String

            let cocktailDrink = CocktailModel(drinkName: drinkName, catagory: catagory, drinkTypeIBA: drinkTypeIBA, alcoholicType: alcoholicType, glassType: glassType, drinkInstructions: drinkInstructions, drinkThumbnailUrl: drinkThumbnailUrl)

            self.totalDrinksArray.append(cocktailDrink)
          
        
       catch let error as NSError 
        print("Error: \(error.localizedDescription)")

      
    

    DispatchQueue.main.async 
      self.drinkTableView.reloadData()
    
  


  //MARK: Image Downloader
  func updateImage (imageUrl: String, onSucceed: @escaping () -> Void, onFailure: @escaping (_ error:NSError)-> Void)
    //named imageData because this is the data to be used to get image, can be named anything
    networkManager.downloadImage(imageUrl: imageUrl, onSucceed:  (imageData) in
      if let image = UIImage(data: imageData) 
       self.drinkImage = image
      
      onSucceed()//must call completion handler
    )  (error) in
      onFailure(error)
    
  



//MARK: Tableview Delegates
extension DrinkViewController: UITableViewDelegate, UITableViewDataSource 

  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 

    //return numberOfRows
    return drinksPerPage
  

  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = drinkTableView.dequeueReusableCell(withIdentifier: DRINK_CELL_REUSE_IDENTIFIER) as! DrinkCell


    //get image from separate url
    if let image = totalDrinksArray[indexPath.row].drinkThumbnailUrl//index out of range error here
      updateImage(imageUrl: image, onSucceed: 
        if let currentImage = self.drinkImage
          DispatchQueue.main.async 
            cell.drinkImage.image = currentImage
          
        
      , onFailure:  (error) in
        print(error)
      )
    
    cell.drinkLabel.text = totalDrinksArray[indexPath.row].drinkName
    return cell
  

  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
    if let image = totalDrinksArray[indexPath.row].drinkThumbnailUrl
      updateImage(imageUrl: image, onSucceed: 
      , onFailure:  (error) in
        print(error)
      )
    
    performSegue(withIdentifier: DRINK_SEGUE, sender: indexPath.row)
  


  func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) 
    let lastElement = drinksPerPage
      if indexPath.row == lastElement 
         self.drinkTableView.reloadData()
      
  

我看到了这篇文章:tableview-loading-more-cell-when-scroll-to-bottom 并实现了 willDisplay 函数,但出现“索引超出范围”错误。

【问题讨论】:

UITableView load more when scrolling to bottom的可能重复 【参考方案1】:

如果您一次获得所有结果,您能告诉我为什么要这样做,那么您不必限制显示,因为它是由 tableview 自动管理的。在 tableview 中,所有的单元格都被重用,所以不会有内存问题。 UITableViewCell 将在显示时创建。

所以不需要限制细胞数。

我现在不知道你在代码中做了什么,但是:

  func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) 
     let lastElement = drinksPerPage // no need to write this line
     if indexPath.row == lastElement  // if block will never be executed since indexPath.row is never equal to drinksPerPage.
     // As indexPath starts from zero, So its value will never be 2.
        self.drinkTableView.reloadData()
  

您的应用程序可能会崩溃,因为您可能只从服务器获取了一项。

如果你真的想加载更多,那么你可以试试这个代码:

声明 numberOfItem 应该等于 drinksPerPage

   var numberOfItem = drinksPerPage

   func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 

     //return numberOfRows
     return numberOfItem
   

   func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) 
     if indexPath.row == numberOfItem - 1  
        if self.totalDrinksArray.count > numberOfItem 
           let result = self.totalDrinksArray.count - numberOfItem
           if result > drinksPerPage 
              numberOfItem = numberOfItem + drinksPerPage
           
           else 
              numberOfItem = result
              
           self.drinkTableView.reloadData()
        
     
   

【讨论】:

我只想一次显示特定数量的表格视图单元格,然后用户可以决定是否要加载更多。 @Rahul Dasgupta 还有一个叫做 cmets 的东西。 @SwiftyJD 有什么按钮可以加载更多。 @RahulDasgupta 没有,但是一旦用户滚动到页面底部,它会加载更多。 @SwiftyJD 如果有效,请为我的答案投票。

以上是关于限制tableView中显示的单元格数量,滚动到最后一个单元格时加载更多单元格的主要内容,如果未能解决你的问题,请参考以下文章

如何根据单元格数量更改滚动视图大小?

滚动时 TableView 单元格很慢

如何使用 UIImage 从 tableview 单元格中的 url 平滑滚动

tvOS tableView 从一个单元格到另一个单元格平滑滚动

iPhone Tableview 在水平滚动而不是垂直中使用单元格

添加具有行动画的单元格时,将 tableview 保持在相同的滚动位置