在Swift Firebase中滚动时分页 [英] Pagination while scrolling in Swift Firebase

查看:225
本文介绍了在Swift Firebase中滚动时分页的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从Firebase数据库加载数据。我正试图加载数据,而用户滚动。例如,如果他已经滚动了大约20 cells ,那么我想加载更多大约5 cells 。我试图做到这一点,但它不工作︰
$ b $ pre $ func parseSnusBrands(
let ref = (),{},} {} {} {} {} { (snapshot)in
if snapshot.exists(){
if let all =(snapshot.value?.allKeys)!as?[String] {
self.snusBrandsArray = all
self.snusBrandsTableView.reloadData()

}
}
})
}

并检测有多少个单元格滚动:

  override func tableView(tableView :UITableView,willDisplayCell cell:UITableViewCell,forRowAtIndexPath indexPath:NSIndexPath){$ b $ if if indexPath.row == 20 {
let ref = FIRDatabase.database()。reference()。child(Snuses)。孩子(品牌)

如果使用了快照。()。(
,如果let all =(snapshot.value?.allKeys)),则返回false。 !如? [String] {
self.snusBrandsArray = all
self.snusBrandsTableView.reloadData()
$ b}
}
})
}

这是我的 Firebase 结构:





有更好的解决方案还是应该继续这样的尝试?

这里可以看到整个代码。我知道它缺少OO,但我正在学习:)

解决方案

您可能需要使用 offset 在您的应用中实现分页。

首先,在您的子路径中添加一个顺序键,可能是当前插入的时间戳,以便您可以订单并在分页中使用它。



例如

  品牌:{
catch:{
...
...
pOrder:555
},
etan :{
...
...
pOrder:444
},
general:{
...
...
pOrder:555
}。
.....
}

现在,要实现分页,您会检索21个记录,在这些记录中,前20个将是在表视图中使用的记录,而最后一个记录将是用于检索下一个集合的 offset 创建一个从 firebase 获取数据的函数:

  // MARK:正在检索数据:Firebase 
/ *
检索当前帖子集,按帖子的更新时间排序
* /
func retrievePost(offset:NSNumber,callFlag:Bool,completion:(result:AnyObject ?, error:NSError?) - >()){
//由于这个方法是从viewDidLoad中调用的,记录。
//稍后当用户向下滚动到底部时,再次调用
let postsRef = ref.child(kDBPostRef)
var startingValue:AnyObject?
//当由于未设置偏移量而从viewDidLoad调用此方法时,起始值将为零

if callFlag {
如果偏移量== 0 {
startingValue = nil
}
else {
startingValue = offset
}
} else {
//从offsetArray获得偏移量
startingValue = self .findOffsetFromArray()


//通过pOrder获取偏移量排序记录+1记录
self.refHandler = postsRef.queryOrderedByChild(pOrder)。queryStartingAtValue(startingValue)。 queryLimitedToFirst(kPostLimit + 1).observeEventType(FIRDataEventType.Value,withBlock:{(snapshot)in
// flag是用于设置最后一条记录/ 21st作为偏移
var flag = 0

let tempPost = NSMutableSet()
//遍历子元素并添加到tempPost
在snapshot.children {

//检查offet,最后一行(第21行)是偏移的;不要在主表列表中添加最后一个元素
flag + = 1
if flag == 21&& callFlag == true {
//这行是偏移
self.kOffset = item.value?[pOrder] as! NSNumber
self.offSetArray?.append(self.kOffset)
continue
}
//创建Post对象
let post = Post(snapshot:item as!FIRDataSnapshot )

//追加到tempPost
tempPost.addObject(后)
}
//返回闭包
完成(result:tempPost,error :nil)
))
}

调用 updateNewRecords 方法从 viewDidLoad 传递 0 来检索前20条记录。

  func updateNewRecords(offset:NSNumber,callFlag:Bool){
self.retrievePost(offset,callFlag:callFlag) {(结果,错误) - >无效
//让tempArray = result as! (Post)
let oldSet = Set(self.posts)
var unionSet = oldSet.union(result as!Set< Post>)
unionSet = unionSet.union(unionSet)
self.posts = Array(unionSet)
self.postsCopy = self.posts
// print(self.posts.count)
self.posts.sortInPlace({$ 0.pOrder> $ 1 )
self.reloadTableData()
}
}



<再次当用户滚动到表视图底部时,调用这个方法,将 updateNewRecords 传递给offset,检索下一组20条记录。
$ b $ pre $ func scrollViewDidEndDragging(scrollView:UIScrollView,willDecelerate decelerate:Bool){

// UITableView只向一个方向移动,y轴
let currentOffset = scrollView.contentOffset.y
let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height

//改变10.0来调整距底部的距离
如果maximumOffset - currentOffset <= 10.0 {
self.updateNewRecords(self.kOffset,callFlag:true)
}



$ b

你可以维护一个数组 offsetArray 用于在 firebase 中修改数据时更新表值。



例如假设某些数据在表中的某处被修改,那么 observeEventType 将被调用,并且应该只从 firebase 。您可以使用偏移量的数组来实现它。所以,当任何记录更新时, retrievePost 将被调用,从 offsetArray中相应的 offset 。在正常情况下(从 viewDidLoad scrollViewDidEndDragging 中检索数据时),偏移量将为 kOffset ,在其他情况下(在监听数据变化时),偏移量将从 offsetArray



您可以定义一个函数来返回特定更新列的 offset 值:

  //找到偏移量offsetDict 
func findOffsetFromArray() - > NSNumber {
let idx = self.kClickedRow / 20 // kClickedRow是表视图中已更新的行
return self.offSetArray![idx]

}

您也可以修改 retrievePost 方法并传递额外的参数检索一定数量的记录。

I am loading data from Firebase Database. I am trying to load data while user scrolls. For example if he has scrolled about 20 cells then I want to load a little more about 5 cells. I am trying to achieve it like this but it is not working:

func parseSnusBrands(){
        let ref = FIRDatabase.database().reference().child("Snuses").child("Brands")

        ref.queryOrderedByKey().queryLimitedToLast(20).observeEventType(.Value, withBlock: { (snapshot) in
            if snapshot.exists() {
                if let all = (snapshot.value?.allKeys)! as? [String]{
                    self.snusBrandsArray = all
                    self.snusBrandsTableView.reloadData()

                }
            }
        })
    }

and to detect how many cells are scrolled:

override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    if indexPath.row == 20 {
        let ref = FIRDatabase.database().reference().child("Snuses").child("Brands")

        ref.queryOrderedByKey().queryLimitedToLast(20).observeEventType(.Value, withBlock: { (snapshot) in
            if snapshot.exists() {
                if let all = (snapshot.value?.allKeys)! as? [String]{
                    self.snusBrandsArray = all
                    self.snusBrandsTableView.reloadData()

                }
            }
        })
    }
}

This is my Firebase structure:

Is there better solution or should I keep trying like this?

Here you can see the whole code. I know that it lacks of OO but I am learning :)

解决方案

You may want to use offset to achieve pagination in your app.

First, add an order key in your child path, may be current time stamp of insertion so that you can order it and use it in pagination.

For eg.

"brands": {
         "catch" : {
           ...
           ...
           "pOrder" : 555
         },
         "etan" : {
           ...
           ...
           "pOrder" : 444
         },
         "general" : {
           ...
           ...
           "pOrder" : 555
         }.
         .....
       }

Now, to achieve pagination you would retrieve 21 records and in those records, the first 20 will be the records to use in table view, while the last record will be the offset that will be used to retrieve next set of records.

Create a function that fetches data from firebase:

 // MARK: Retrieving Data: Firebase
    /*
     retrieve current set of posts sorted by updated time of posts
     */
    func retrievePost(offset: NSNumber, callFlag: Bool, completion: (result: AnyObject?, error: NSError?)->()){
        // As this method is called from viewDidLoad and fetches 20 records at first.
        // Later when user scrolls down to bottom, its called again
        let postsRef = ref.child(kDBPostRef)
        var startingValue:AnyObject?
        // starting  value will be nil when this method is called from viewDidLoad as the offset is not set

        if callFlag{
            if offset == 0{
                startingValue = nil
            }
            else{
                startingValue = offset
            }
        } else{
            // get offset from the offsetArray
            startingValue = self.findOffsetFromArray()

        }
        // sort records by pOrder fetch offset+1 records
        self.refHandler = postsRef.queryOrderedByChild("pOrder").queryStartingAtValue(startingValue).queryLimitedToFirst(kPostLimit + 1).observeEventType(FIRDataEventType.Value, withBlock: { (snapshot) in
            // flag is for setting the last record/ 21st as offset
            var flag = 0

            let tempPost = NSMutableSet()
                // iterate over children and add to tempPost
                for item in snapshot.children {

                    // check for offet, the last row(21st) is offset ; Do not add last element in the main table list
                    flag += 1
                    if flag == 21 && callFlag == true{
                        // this row is offset
                        self.kOffset = item.value?["pOrder"] as! NSNumber
                        self.offSetArray?.append(self.kOffset)
                        continue
                    }
                    // create Post object
                    let post = Post(snapshot: item as! FIRDataSnapshot)

                    // append to tempPost
                    tempPost.addObject(post)
                }
                // return to the closure
                completion(result:tempPost, error:nil)
        })
    }

And call this updateNewRecords method from viewDidLoad, passing 0 to retrieve first 20 records.

 func updateNewRecords(offset:NSNumber, callFlag: Bool){
        self.retrievePost(offset,callFlag:callFlag) { (result,error) -> Void in
//            let tempArray = result as! [Post]
            let oldSet = Set(self.posts)
            var unionSet = oldSet.union(result as! Set<Post>)
            unionSet = unionSet.union(unionSet)
            self.posts = Array(unionSet)
            self.postsCopy = self.posts
//          print(self.posts.count)
            self.posts.sortInPlace({ $0.pOrder> $1.pOrder})
            self.reloadTableData()
        }
    }

Again when the user scrolls to bottom in the table view, call this method, updateNewRecords passing the offset, to retrieve next set of 20 records.

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

        // UITableView only moves in one direction, y axis
        let currentOffset = scrollView.contentOffset.y
        let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height

        // Change 10.0 to adjust the distance from bottom
        if maximumOffset - currentOffset <= 10.0 {
            self.updateNewRecords(self.kOffset, callFlag:true)
        }
    } 

You can maintain an array offsetArray for updating table values when your data is modified in firebase .

For e.g. suppose some data is modified somewhere in your table, in that case observeEventType will be called and you should fetch only those range of records from firebase. You can achieve it using maintaining an array of offsets. So when any record is updated, the retrievePost will be called with the corresponding offset from offsetArray. In normal case, ( while retrieving data from viewDidLoad and scrollViewDidEndDragging), the offset will be kOffset and in rest of the cases(while listening to data change), the offset will be from offsetArray.

You can define a function that will return the offset value for a particular updated column:

// find the offset from the offsetDict
    func findOffsetFromArray() -> NSNumber{
        let idx = self.kClickedRow/20 // kClickedRow is the updated row in the table view
        return self.offSetArray![idx]

    }

You can also modify retrievePost method and pass an extra parameter to retrieve a certain number of records.

这篇关于在Swift Firebase中滚动时分页的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆