Swift - 分页时添加加载单元

Swift -Add loading cell while paginating

现在我使用这个问题底部的代码进行分页,一切正常,但我想在分页开始后向 collectionView 添加一个加载单元,并在分页停止后将其删除。

我尝试了以下方法,但它只是将加载单元添加到 cv 的底部并且加载单元永远不会离开。

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

    return datasource.count + 1
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    if indexPath.item == tableData.count {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: loadingCell, for: indexPath) as! LoadingCell
        cell.spinner.startAnimating()
        return cell
    }

    return cell // this is a normal cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

    if indexPath.item == tableData.count {

        return CGSize(width: collectionView.frame.width, height: 40) // loading cell is 40 pts
    }

    return CGSize(width: width, height: 80) // normal cell is 80 pts
}

我也试过使用sections但是出现了同样的问题

func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 2
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    if section == 0 {
        return datasource.count
    } else {
        return 1
    }
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    if indexPath.section == 1 {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: loadingCell, for: indexPath) as! LoadingCell
        cell.spinner.startAnimating()
        return cell
    }

    return cell // this is a normal cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

    if indexPath.section == 1 {

        return CGSize(width: collectionView.frame.width, height: 40) // loading cell is 40 pts
    }

    return CGSize(width: width, height: 80) // normal cell is 80 pts
}

如何仅在 handlePaginating() 为 called/finished 时删除添加和删除加载单元?

var startKey: String?

override func viewDidLoad() {
    super.viewDidLoad()

    handlePagination()
}

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {

    let contentOffset = scrollView.contentOffset.y

    let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height

    if maximumOffset - contentOffset <= 10 {

        handlePagination()
    }
}

func handlePagination() {

    if startKey == nil {

        Database...Ref?.queryOrderedByKey().queryLimited(toLast: 10).observeSingleEvent(of: .value, with: { [weak self](snapshot) in

            guard let children = snapshot.children.allObjects.first as? DataSnapshot else { return}

            for child in snapshot.children.allObjects as! [DataSnapshot] {
                    // append child to datasource
            }
            self?.startKey = children.key
        })

    } else {

        Database...Ref?.queryOrderedByKey().queryEnding(atValue: startKey!).queryLimited(toLast: 11).observeSingleEvent(of: .value, with: { [weak self](snapshot) in

            guard let children = snapshot.children.allObjects.first as? DataSnapshot else { return}

            for child in snapshot.children.allObjects as! [DataSnapshot] {
                // insert child in datasource at statIndex
            }
            self?.startKey = children.key
        })
    }
}

您必须在当前代码中添加一个额外的标志变量才能正常工作。当前代码中发生的事情是,当最后一个要显示的单元格将调用 handlePagination 时,然后您添加加载单元格,而没有任何条件表明 handlePagination 当前正在处理中。所以在你添加加载单元之后,willDisplay 方法再次调用 api。

希望对您有所帮助。

例如:

var isApiCalling = false

 func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { 
       let lastElement = tableData.count - 1 
       if indexPath.item == lastElement && !isApiCalling { 
              isApiCalling = true
              handlePagination() 
       } 
  }


func handlePagination() {
   //After you get response from API called. reset isApiCalling to false.
  isApiCalling  = false.
}

我将@PratikPrajapati 回答中的标志 属性 的想法与问题的第一部分结合使用。

我声明了一个 属性 并最初将其设置为 var isPaging = false。然后在 cellForItemsizeForItem 里面,我检查布尔值是 true 还是 false.

handlePagination()else 子句中,我将标志设置为 isPaging = true,然后调用 collectionView.reloadData(),以便在重新加载 cv 时,cellForItemsizeForItem 现在将在加载单元内显示微调器并将其高度设置为 40。

最后在 else 子句的回调中,我将标志设置回 false 并再次调用 collectionView.reloadData() 以便更新所有单元格,微调器不再旋转,并且加载单元的大小为 .zero:

Database...Ref?.queryOrderedByKey() ....
    // callback
    self?.isPaging = false
    // ...
    UIView.performWithoutAnimation {
        self?.collectionView.reloadData()
    }
...

完整代码如下:

var isPaging = false
var startKey: String?

override func viewDidLoad() {
    super.viewDidLoad()

    handlePagination()
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

    return datasource.count + 1 // *** make sure to add the + 1 to this ***
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    if indexPath.item == tableData.count {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: loadingCell, for: indexPath) as! LoadingCell

        if isPaging {
            cell.spinner.startAnimating()
        } else {
            cell.spinner.stopAnimating()
        }

        return cell
    }

    return cell // this is a normal cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

    if indexPath.item == tableData.count {

        if isPaging {
            return CGSize(width: collectionView.frame.width, height: 40) // if it's true then set the loading cell's size
        } else {
            return .zero // if it's false then set the loading cell's size to .zero
        }
    }

    return CGSize(width: width, height: 80) // normal cell is 80 pts
}

func handlePagination() {

    if startKey == nil {

        Database...Ref?.queryOrderedByKey().queryLimited(toLast: 10).observeSingleEvent(of: .value, with: { [weak self](snapshot) in

            guard let children = snapshot.children.allObjects.first as? DataSnapshot else { return}

            for child in snapshot.children.allObjects as! [DataSnapshot] {
                    // append child to datasource
            }
            self?.startKey = children.key
        })

    } else {

        isPaging = true
        collectionView.reloadData()
        // add a function to auto scroll to the last cell

        Database...Ref?.queryOrderedByKey().queryEnding(atValue: startKey!).queryLimited(toLast: 11).observeSingleEvent(of: .value, with: { [weak self](snapshot) in

            self?.isPaging = false

            guard let children = snapshot.children.allObjects.first as? DataSnapshot else { return}

            for child in snapshot.children.allObjects as! [DataSnapshot] {
                // insert child in datasource at statIndex
            }

            self?.startKey = children.key
            UIView.performWithoutAnimation {
               self?.collectionView.reloadData()
            }
        })
    }
}

func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {

    let contentOffset = scrollView.contentOffset.y

    let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height

    if maximumOffset - contentOffset <= 10 {

        handlePagination()
    }
}