Swift iOS : 如何一拖tableview到底的時候更新資料

RecoReco發表於2019-03-03

拖動tableView到最底下,隨即更新之後的資料,是一個常見的應用場景。使用MJRefresh,或者GTMRefresh都是不錯的更新方法。但是自己做的話,就可以更加簡單,而無需第三方依賴,並且可以瞭解到第三方庫的原理。

如下案例,顯示了一個超出一螢幕的資料的tableview,當拖動到接近最下的時候(有一個值設為為100,就是還差100就到最底下),就會觸發一次onRefresh函式的執行:

 import UIKit
 @UIApplicationMain
 class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        self.window = UIWindow(frame: UIScreen.main.bounds)
        let page = Page()
        page.view.backgroundColor = .blue
        self.window!.rootViewController = page
        self.window?.makeKeyAndVisible()
        return true
    }
 }
 class Page: UIViewController {
    var a : Table!
    override func viewDidLoad() {
        super.viewDidLoad()
        a  = Table()
        a.frame = UIScreen.main.bounds
        self.view.addSubview(a)
    }
 }

class Table : UITableView,UITableViewDataSource,UITableViewDelegate{
    let lang = "java,swift,js,java,swift,js,java,swift,js,java,swift,js,java,swift,js,java,swift,js,java,swift,js,java,swift,js,java,swift,js,java,swift,js,java,swift,js,".components(separatedBy: ",")
    let os = ["Windows","OS X","Linux"]
    override init(frame: CGRect, style: UITableViewStyle) {
        super.init(frame:frame,style:style)
        self.dataSource = self
        self.delegate = self
//        lang = split(langStr) {$0 == ","}
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder:aDecoder)
    }
    func numberOfSections(in: UITableView) -> Int {
        return 1
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return lang.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let arr = lang
        let a = UITableViewCell(style: .default, reuseIdentifier: nil)
        a.textLabel?.text = String(describing:arr[indexPath.row])
        return a
    }
    let threshold : CGFloat = 100.0 // threshold from bottom of tableView
    var isLoadingMore = false // flag
    func onRefresh(){
        print("new data")
    }
    private func addObserver() {
        self.addObserver(self, forKeyPath: "contentOffset", options: .new, context: nil)
    }

    private func removeAbserver() {
        self.removeObserver(self, forKeyPath:"contentOffset")
    }
    var curentContentHeight : CGFloat = 0
    override open func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        print(contentOffset.y)
    }
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
//        print(scrollView.contentOffset.y,self.contentSize.height,UIScreen.main.bounds.height)

        let contentOffset = scrollView.contentOffset.y
        let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;
//        print(maximumOffset ,contentOffset)
        // 還差100就翻到底的時候 。。。
        if !isLoadingMore && (maximumOffset - contentOffset <= threshold) {
            self.isLoadingMore = true
            let when = DispatchTime.now() + 2
            DispatchQueue.main.asyncAfter(deadline: when) {
                self.onRefresh()
                self.isLoadingMore = false
            }
        }
    }
 }複製程式碼

拖動tableview時,整體內容會發生偏移,以便增強操作效果。這裡的實現的關鍵,是tableView做了UIScrollViewDelegate的委託,只要在加入

func scrollViewDidScroll(_ scrollView: UIScrollView) 複製程式碼

實現,那麼拖動時,就會呼叫此函式,讓tableview類得到通知,在此函式內就可以判斷載入新資料的時機。此處我們以一個變數threshold作為限定,當拖動到離最底下(也就是完整的內容的高度)還差這麼多的時候,就開始觸發onRefresh事件。此事件內,可以加入你需要載入資料的程式碼。

參考: anasimtiaz.com/?p=254

相關文章