当前位置: > > > Swift - 表格tableView上拉加载新数据的功能实现(附样例)

Swift - 表格tableView上拉加载新数据的功能实现(附样例)

(本文代码已升级至Swift4)

对于表格(tableView)来说,下拉刷新数据、上拉加载数据应该是两个最常用的数据更新操作了。对于前者,我原来写过一篇相关的文章:Swift - 下拉刷新数据的功能实现(使用UIRefreshControl)。本次我来讲讲后者的实现。
说是上拉加载数据,其实就是当我们将表格内容滚动到最后一行时,系统就会自动获取新的内容并添加到列表尾部(具体效果可以参考百度贴吧的App)。下面我们通过一个小样例来演示上拉加载的实现。

1,样例效果图
(1)当初次进入程序时,先加载前20条数据。
(2)当 tableView 滚动条移到底部时,会看到表格底部有正在加载的提示,并继续加载接下来的20条数据。
(3)数据加载完毕后,会把新数据添加到表格底部。
(4)如果表格再次滚到底部,则循环上面的操作,继续加载新数据。
        

2,实现原理
(1)上拉加载的关键点在于判断何时开始加载新数据。这里我们在最后一条数据项显示出来的时候就自动开始加载。也就是当用户上拉表格,等到看到最后一条数据的时候就加载。
(2)同时我们在表格的 tableFooterView 中添加一个提示视图,用来告诉用户数据正在加载中。
(3)每次收到数据后,就将新数据并到本地的数据集合中,再调用 tableView的reloadData() 方法重新刷新下表格数据。
(4)这里要注意每次发起请求的时候要做个保护,保证在原来的请求没有返回时就不会发起新的请求。防止用户在最后一页来回滚动造成多次请求。
(5)实际的项目这些数据是通过网络请求的。这里就直接本地生成,并使用计时器加个延时,可以更好地看到效果。

3,完整代码
import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    //表格视图
    @IBOutlet weak var tableView: UITableView!
    
    //数据集合
    var dataArray = [String]()
    
    //表格底部用来提示数据加载的视图
    var loadMoreView:UIView?
    
    //计数器(用来做延时模拟网络加载效果)
    var timer: Timer!
    
    //用了记录当前是否允许加载新数据(正则加载的时候会将其设为false,放置重复加载)
    var loadMoreEnable = true
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.tableView.delegate = self
        self.tableView.dataSource = self
        
        //上拉刷新
        self.setupInfiniteScrollingView()
        self.tableView.tableFooterView = self.loadMoreView
        
        //首次加载数据
        loadMore()
    }
    
    //上拉刷新视图
    private func setupInfiniteScrollingView() {
        self.loadMoreView = UIView(frame: CGRect(x:0, y:self.tableView.contentSize.height,
                                                 width:self.tableView.bounds.size.width, height:60))
        self.loadMoreView!.autoresizingMask = UIViewAutoresizing.flexibleWidth
        self.loadMoreView!.backgroundColor = UIColor.orange
        
        //添加中间的环形进度条
        let activityViewIndicator = UIActivityIndicatorView(activityIndicatorStyle: .white)
        activityViewIndicator.color = UIColor.darkGray
        let indicatorX = self.view.frame.width/2-activityViewIndicator.frame.width/2
        let indicatorY = self.loadMoreView!.frame.size.height/2-activityViewIndicator.frame.height/2
        activityViewIndicator.frame = CGRect(x:indicatorX, y:indicatorY,
                                             width:activityViewIndicator.frame.width,
                                             height:activityViewIndicator.frame.height)
        activityViewIndicator.startAnimating()
        self.loadMoreView!.addSubview(activityViewIndicator)
    }
    
    // 返回记录数
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataArray.count;
    }
    
    //单元格数据设置
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
        -> UITableViewCell {
            //设置单元格数据
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
            cell.textLabel?.text = self.dataArray[indexPath.row]
            
            //当下拉到底部,执行loadMore()
            if (loadMoreEnable && indexPath.row == self.dataArray.count-1) {
                loadMore()
            }
            
            return cell
    }
    
    //加载更多数据
    func loadMore(){
        print("加载新数据!")
        loadMoreEnable = false
        timer = Timer.scheduledTimer(timeInterval: 2.0, target: self,
                selector: #selector(ViewController.timeOut), userInfo: nil, repeats: true)
    }
    
    //计时器时间到
    @objc func timeOut() {
        let start = self.dataArray.count + 1
        //随机添加10条新数据(时间是当前时间)
        for i in start..<start+20 {
            self.dataArray.append("新闻标题\(i)")
        }
        self.tableView.reloadData()
        loadMoreEnable = true
        
        timer.invalidate()
        timer = nil
    }
}
源码下载hangge_1254.zip
评论3
  • 3楼
    2018-09-11 10:20
    失眠的波妞

    有一个bug,如果数据只有1条的时候会触发自动下滑下一页的事件

    站长回复

    实际项目中,加载下一页时,服务器除了返回下一页数据外,还需返回个当前页码。如果加载最后一页的话(比如你说的只有一条数据返回),那前端就需要把loadMoreEnable设为false, 同时将 tableFooterView 给移除。

  • 2楼
    2018-09-08 17:43
    失眠的波妞

    UIView(frame: CGRectMake(0, self.tableView.contentSize.height, self.tableView.bounds.size.width, 60))报错,'CGRectMake' is unavailable in Swift

    站长回复

    多些提醒。这篇文章写的比较早,后来语法有变。代码现已更新,你可以再看下。

  • 1楼
    2016-09-01 09:22
    走,咋们去逛窑子

    请问,比如,我在网上请求下来的是20数据, 现在我只想要他先加载显示5条, 每次上拉加载一次,再显示随后的五条,有什么办法呢

    站长回复

    你可以定义两个数据集合,一个allData,一个showData。下载下来的数据都放在allData里,而表格展示的是showData里的数据。每次上拉,从allData里捞出5条数据添加到showData中并刷新表格。