上拉\下拉刷新思路

请求参数说明:(新浪微博为例)

since_id  若指定此参数,则返回ID比since_id大的微博(即比since_id时间晚的微博),默认为0。
max_id  若指定此参数,则返回ID小于或等于max_id的微博,默认为0。

如果 下拉刷新 MaxId = 0 代表我要拿时间最新的微博
如果 上啦加载更多 SinceId = 0 代表我要拿时间更早的微博

封装网络请求方法时,加上since_id和max_id两个参数
内部拼接请求参数

func loadPublicStatusInfo(since_id: Int64 , max_id: Int64 , success: (response: AnyObject?)->(), failure: (error: NSError)->() ) -> Void

1、将tableView的footView赋值为一个UIActivityIndicatorView
2、上拉刷新操作时,监听当前显示的Cell,如果当前显示的是最后一个Cell,并且UIActivityIndicatorView的动画未开启状态时:
- 开启UIActivityIndicatorView的动画,并以isAnimating()值作为参数传入请求数据的方法内(开始请求数据时,停止动画)
- 通过UIActivityIndicatorView的isAnimating()值判断当前是上拉加载更多操作,还是下拉刷新操作的标识
- 通过since_id和max_id这两个参数决定微博数据
- 请求数据完成后,根据上拉\下拉,判断数据的排序问题
每一条微博都有唯一的标识:id--升序,id值越大,发布时间越接近当前时间,id值越小,发布的时间越早
显示数据时,界面越往上,数组角标越小,数据越新,id越大;反之越往下,微博的发布时间越早,id越小
所以请求新数据后的数据排序为
上拉加载更多时: 原始数据(前) + 新数据(后)
下拉刷新数据时: 新数据(前) + 原始数据(后)

示例代码:
import UIKit
private let cellReusedId  = "cellReusedId"
class JSHomeTableViewController: JSVistorTableViewController {

    //数据容器 (因为后面使用数组参与了运算,可选项不能直接参与运算,需要解包,避免使用麻烦,所以直接初始化了一个空数组)
    private var statusArr: [JSStatusModel] = [JSStatusModel]()
    
    ////下拉刷新
    private let refresh: UIRefreshControl = UIRefreshControl()
    
    //刷新动画View
    private lazy var activityView: UIActivityIndicatorView = {
        
        let activity = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)
        activity.backgroundColor = UIColor.whiteColor()
        activity.frame = CGRectMake(0, 0, 0, 40)
        return activity
        
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if !isLogin {
            //设置VistorView(未登录)
            vistorView?.setupVistorViewInfo(nil, title: nil)
            return
        }
        //首次请求数据
        loadStatusData(activityView.isAnimating())

        //设置tableView相关信息
        setupTableViewInfo()
        
    }
    
    //请求数据  pullUp为true 代表上拉加载更多
    private func loadStatusData (pullUp: Bool) -> () {
        
        /*
         请求参数说明:
         since_id   若指定此参数,则返回ID比since_id大的微博(即比since_id时间晚的微博),默认为0。
         max_id     若指定此参数,则返回ID小于或等于max_id的微博,默认为0。
         
         如果 下拉刷新 MaxId = 0 代表我要拿时间最新的微博
         如果 上啦加载更多 SinceId = 0 代表我要拿时间更早的微博
         
         */
        
        //请求完数据,停止activityView的动画下拉刷新(不论请求是否成功)
        activityView.stopAnimating()
        self.refresh.endRefreshing()
        
        // 让 since_id 和 max_id 默认为0 (默认均为0时,首次请求数组长度为0,服务器会默认提供20条数据,对第一次请求没有影响)
        var since_id: Int64 = 0
        var max_id: Int64 = 0
        
        if pullUp {
            
            //上拉加载更多
            max_id = statusArr.last?.id ?? 0
            if max_id > 0 {
                //返回ID小于或等于max_id的微博,防止重复,所以减 1
                max_id -= 1
                
            }
            
        } else {
            
            //下拉刷新
            since_id = statusArr.first?.id ?? 0
            
            
        }
        
        // 请求数据
        JSNetworkTool.sharedNetworkTool.loadPublicStatusInfo(since_id, max_id: max_id, success: { (response) in
            
            guard let res = response?["statuses"] as? [[String: AnyObject]] else {
                return
            }
            var tempArr: [JSStatusModel] = [JSStatusModel]()
            for dict in res {
                
                let statusModel = JSStatusModel(dict: dict);
                tempArr.append(statusModel)
                
            }
            
            //赋值并刷新数据
            //self.statusArr = tempArr
            
            if pullUp {
                
                //上拉加载更多 因为数组参与了运算,可选项不能直接参与运算,需要解包,避免使用麻烦,所以直接初始化了一个空数组
                self.statusArr = self.statusArr + tempArr
                
            } else {
                
                //下拉刷新
                self.statusArr = tempArr + self.statusArr
                
            }
            
            //刷新数据
            self.tableView.reloadData()
            
            }) { (error) in
                
                print("请求出错\(error)")
        }
        
        
        
    }
    
    //tableView相关信息设置
    private func setupTableViewInfo() {
        
        tableView.separatorStyle = .None
        tableView.rowHeight = UITableViewAutomaticDimension
        tableView.estimatedRowHeight = 200
        tableView.registerClass(JSHomeStatusTableViewCell.self, forCellReuseIdentifier: cellReusedId)
        
        // 设置footerView
        tableView.tableFooterView = activityView
        
        //下拉刷新
        refresh.addTarget(self, action: #selector(refreshAction), forControlEvents: UIControlEvents.ValueChanged)
        //类似于通知,发送了一个ValueChanged的通知,监测当UIRefreshControl动画转满一周时,执行 #selector(refreshAction)方法
        // refresh.sendActionsForControlEvents(UIControlEvents.ValueChanged)
        // 添加控件
        tableView.addSubview(refresh)
        
    }
    //监听 下拉刷新事件
    @objc private func refreshAction () -> () {
        
        // 下拉刷新 请求数据
        loadStatusData(activityView.isAnimating())
        
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}
数据源方法
extension JSHomeTableViewController {
    
    // MARK: - Table view data source
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return statusArr.count
    }
    
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCellWithIdentifier(cellReusedId, forIndexPath: indexPath) as! JSHomeStatusTableViewCell
        
        cell.statusModel = statusArr[indexPath.row]

        return cell
    }
    
    
    
}
监听当前显示Cell
extension JSHomeTableViewController {
    
    //将要显示Cell
    override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
        
        //数组长度-1就是当前最后一条数据 而且 activityView没有开启动画 才申请数据
        if statusArr.count == indexPath.row + 1 && !activityView.isAnimating() {
            
            //开启动画
            activityView.startAnimating()
            //请求数据
            loadStatusData(activityView.isAnimating())
            
            
        }
    }
    
}

你可能感兴趣的:(上拉\下拉刷新思路)