Swift - RxSwift的使用詳解57(結(jié)合MJRefresh使用2:上拉加載、以及上下拉組合)

三最铁、上拉加載的樣例

1讯赏,效果圖

(1)頁面打開后會自動加載 15 條數(shù)據(jù)垮兑,并顯示在表格中。

(2)而每次上拉表格又會隨機(jī)生成 15 條新的數(shù)據(jù)漱挎,并拼接到原數(shù)據(jù)下方顯示系枪。

2,樣例代碼

(1)ViewModel.swift

由于“加載更多”功能需要把新數(shù)據(jù)添加到老數(shù)據(jù)尾部磕谅,這里我使用 BehaviorRelay 作為表格數(shù)據(jù)序列私爷,因?yàn)樗梢垣@取到之前的數(shù)據(jù)。

import RxSwift
import RxCocoa
 
class ViewModel {
     
    //表格數(shù)據(jù)序列
    let tableData = BehaviorRelay<[String]>(value: [])
     
    //停止上拉加載刷新狀態(tài)序列
    let endFooterRefreshing: Driver<Bool>
     
    //ViewModel初始化(根據(jù)輸入實(shí)現(xiàn)對應(yīng)的輸出)
    init(footerRefresh: Driver<Void>,
         dependency: (
            disposeBag:DisposeBag,
            networkService: NetworkService )) {
         
        //上拉結(jié)果序列
        let footerRefreshData = footerRefresh
            .startWith(()) //初始化完畢時(shí)會自動加載一次數(shù)據(jù)
            .flatMapLatest{ return dependency.networkService.getRandomResult() }
         
        //生成停止上拉加載刷新狀態(tài)序列
        self.endFooterRefreshing = footerRefreshData.map{ _ in true }
         
        //上拉加載時(shí)膊夹,將查詢到的結(jié)果拼接到原數(shù)據(jù)底部
        footerRefreshData.drive(onNext: { items in
            self.tableData.accept(self.tableData.value + items )
        }).disposed(by: dependency.disposeBag)
    }
}

(2)ViewController.swift

ViewModel 初始化后衬浑,將表格數(shù)據(jù)序列綁定到 tableView上顯示數(shù)據(jù)。同時(shí)將停止刷新序列綁定到 tableViewmj_footer 上讓其自動停止刷新放刨。

import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    //表格
    var tableView:UITableView!
     
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //創(chuàng)建表格視圖
        self.tableView = UITableView(frame: self.view.frame, style:.plain)
        //創(chuàng)建一個(gè)重用的單元格
        self.tableView!.register(UITableViewCell.self,
                                 forCellReuseIdentifier: "Cell")
        self.view.addSubview(self.tableView!)
         
        //設(shè)置尾部刷新控件
        self.tableView.mj_footer = MJRefreshBackNormalFooter()
         
        //初始化ViewModel
        let viewModel = ViewModel(
            footerRefresh: self.tableView.mj_footer.rx.refreshing.asDriver(),
            dependency: (
                disposeBag: self.disposeBag,
                networkService: NetworkService()))
         
        //單元格數(shù)據(jù)的綁定
        viewModel.tableData.asDriver()
            .drive(tableView.rx.items) { (tableView, row, element) in
                let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
                cell.textLabel?.text = "\(row+1)工秩、\(element)"
                return cell
            }
            .disposed(by: disposeBag)
         
        //上拉刷新狀態(tài)結(jié)束的綁定
        viewModel.endFooterRefreshing
            .drive(self.tableView.mj_footer.rx.endRefreshing)
            .disposed(by: disposeBag)
    }
}

四、下拉刷新 + 上拉加載的樣例

1宏榕,效果圖

(1)頁面打開后會自動加載 15 條數(shù)據(jù)拓诸,并顯示在表格中。

(2)當(dāng)下拉表格時(shí)會隨機(jī)生成 15 條新的數(shù)據(jù)麻昼,并替換表格里的原數(shù)據(jù)奠支。

(3)而當(dāng)上拉表格又會隨機(jī)生成 15 條新的數(shù)據(jù),并拼接到原數(shù)據(jù)下方顯示抚芦。

2倍谜,樣例代碼

(1)ViewModel.swift

這里同樣使用 BehaviorRelay 作為表格數(shù)據(jù)序列,同時(shí)還定義了兩個(gè)停止刷新序列(分別表示停止下拉刷新叉抡、停止上拉刷新)尔崔。

import RxSwift
import RxCocoa
 
class ViewModel {
     
    //表格數(shù)據(jù)序列
    let tableData = BehaviorRelay<[String]>(value: [])
     
    //停止頭部刷新狀態(tài)
    let endHeaderRefreshing: Driver<Bool>
     
    //停止尾部刷新狀態(tài)
    let endFooterRefreshing: Driver<Bool>
     
    //ViewModel初始化(根據(jù)輸入實(shí)現(xiàn)對應(yīng)的輸出)
    init(input: (
            headerRefresh: Driver<Void>,
            footerRefresh: Driver<Void> ),
         dependency: (
            disposeBag:DisposeBag,
            networkService: NetworkService )) {
         
        //下拉結(jié)果序列
        let headerRefreshData = input.headerRefresh
            .startWith(()) //初始化時(shí)會先自動加載一次數(shù)據(jù)
            .flatMapLatest{ return dependency.networkService.getRandomResult() }
         
        //上拉結(jié)果序列
        let footerRefreshData = input.footerRefresh
            .flatMapLatest{ return dependency.networkService.getRandomResult() }
         
        //生成停止頭部刷新狀態(tài)序列
        self.endHeaderRefreshing = headerRefreshData.map{ _ in true }
         
        //生成停止尾部刷新狀態(tài)序列
        self.endFooterRefreshing = footerRefreshData.map{ _ in true }
         
        //下拉刷新時(shí),直接將查詢到的結(jié)果替換原數(shù)據(jù)
        headerRefreshData.drive(onNext: { items in
            self.tableData.accept(items)
        }).disposed(by: dependency.disposeBag)
         
        //上拉加載時(shí)褥民,將查詢到的結(jié)果拼接到原數(shù)據(jù)底部
        footerRefreshData.drive(onNext: { items in
            self.tableData.accept(self.tableData.value + items )
        }).disposed(by: dependency.disposeBag)
    }
}

(2)ViewController.swift

ViewModel 初始化后季春,將表格數(shù)據(jù)序列綁定到 tableView上顯示數(shù)據(jù)。同時(shí)將兩個(gè)停止刷新序列分別綁定到 tableViewmj_headermj_footer 上讓其自動停止刷新消返。

import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    //表格
    var tableView:UITableView!
     
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //創(chuàng)建表格視圖
        self.tableView = UITableView(frame: self.view.frame, style:.plain)
        //創(chuàng)建一個(gè)重用的單元格
        self.tableView!.register(UITableViewCell.self,
                                 forCellReuseIdentifier: "Cell")
        self.view.addSubview(self.tableView!)
         
        //設(shè)置頭部刷新控件
        self.tableView.mj_header = MJRefreshNormalHeader()
        //設(shè)置尾部刷新控件
        self.tableView.mj_footer = MJRefreshBackNormalFooter()
         
        //初始化ViewModel
        let viewModel = ViewModel(
            input: (
                headerRefresh: self.tableView.mj_header.rx.refreshing.asDriver(),
                footerRefresh: self.tableView.mj_footer.rx.refreshing.asDriver()),
            dependency: (
                disposeBag: self.disposeBag,
                networkService: NetworkService()))
         
        //單元格數(shù)據(jù)的綁定
        viewModel.tableData.asDriver()
            .drive(tableView.rx.items) { (tableView, row, element) in
                let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
                cell.textLabel?.text = "\(row+1)载弄、\(element)"
                return cell
            }
            .disposed(by: disposeBag)
         
        //下拉刷新狀態(tài)結(jié)束的綁定
        viewModel.endHeaderRefreshing
            .drive(self.tableView.mj_header.rx.endRefreshing)
            .disposed(by: disposeBag)
         
        //上拉刷新狀態(tài)結(jié)束的綁定
        viewModel.endFooterRefreshing
            .drive(self.tableView.mj_footer.rx.endRefreshing)
            .disposed(by: disposeBag)
    }
}

附:“下拉刷新 + 上拉加載”的功能改進(jìn)

1,功能說明

在前面的樣例中下拉刷新和上拉加載這兩個(gè)行為是獨(dú)立的撵颊,互不影響宇攻。也就是說當(dāng)我們下拉刷新后,在數(shù)據(jù)返回前又進(jìn)行了次上拉操作倡勇,那么之后表格便會連續(xù)刷新兩次逞刷,影響體驗(yàn)。這里對功能做個(gè)改進(jìn):

  • 當(dāng)下拉刷新時(shí),如果數(shù)據(jù)還未返回夸浅。這時(shí)進(jìn)行上拉加載會取消前面的下拉刷新操作(包括下拉刷新的數(shù)據(jù))仑最,只進(jìn)行上拉數(shù)據(jù)的加載。
  • 同樣的题篷,當(dāng)上拉加載時(shí)词身,如果數(shù)據(jù)還未放回。這時(shí)進(jìn)行下拉刷新會取消上拉加載操作(包括上拉加載的數(shù)據(jù))番枚,只進(jìn)行下拉數(shù)據(jù)的加載法严。

同時(shí)這次我們不使用 Driver 這個(gè)特征序列,而是用普通的 Observable 序列葫笼。

2深啤,樣例代碼

(1)NetworkService.swift

import RxSwift
import RxCocoa
 
//網(wǎng)絡(luò)請求服務(wù)
class NetworkService {
     
    //獲取隨機(jī)數(shù)據(jù)
    func getRandomResult() -> Observable<[String]> {
        print("正在請求數(shù)據(jù)......")
        let items = (0 ..< 15).map {_ in
            "隨機(jī)數(shù)據(jù)\(Int(arc4random()))"
        }
        let observable = Observable.just(items)
        return observable
            .delay(2, scheduler: MainScheduler.instance)
    }
}

(2)ViewModel.swift

import RxSwift
import RxCocoa
 
class ViewModel {
     
    //表格數(shù)據(jù)序列
    let tableData = BehaviorRelay<[String]>(value: [])
     
    //停止頭部刷新狀態(tài)
    let endHeaderRefreshing: Observable<Bool>
     
    //停止尾部刷新狀態(tài)
    let endFooterRefreshing: Observable<Bool>
     
    //ViewModel初始化(根據(jù)輸入實(shí)現(xiàn)對應(yīng)的輸出)
    init(input: (
            headerRefresh: Observable<Void>,
            footerRefresh: Observable<Void> ),
         dependency: (
            disposeBag:DisposeBag,
            networkService: NetworkService )) {
         
        //下拉結(jié)果序列
        let headerRefreshData = input.headerRefresh
            .startWith(()) //初始化時(shí)會先自動加載一次數(shù)據(jù)
            .flatMapLatest{ _ in
                dependency.networkService.getRandomResult()
                    .takeUntil(input.footerRefresh)
            }.share(replay: 1) //讓HTTP請求是被共享的
         
         
        //上拉結(jié)果序列
        let footerRefreshData = input.footerRefresh
            .flatMapLatest{ _ in
                dependency.networkService.getRandomResult()
                    .takeUntil(input.headerRefresh)
            }.share(replay: 1) //讓HTTP請求是被共享的
         
        //生成停止頭部刷新狀態(tài)序列
        self.endHeaderRefreshing = Observable.merge(
            headerRefreshData.map{ _ in true },
            input.footerRefresh.map{ _ in true }
        )
         
        //生成停止尾部刷新狀態(tài)序列
        self.endFooterRefreshing = Observable.merge(
            footerRefreshData.map{ _ in true },
            input.headerRefresh.map{ _ in true }
         )
         
        //下拉刷新時(shí),直接將查詢到的結(jié)果替換原數(shù)據(jù)
        headerRefreshData.subscribe(onNext: { items in
            self.tableData.accept(items)
        }).disposed(by: dependency.disposeBag)
         
        //上拉加載時(shí)路星,將查詢到的結(jié)果拼接到原數(shù)據(jù)底部
        footerRefreshData.subscribe(onNext: { items in
            self.tableData.accept(self.tableData.value + items )
        }).disposed(by: dependency.disposeBag)
    }
}

(3)ViewController.swift

import UIKit
import RxSwift
import RxCocoa
 
class ViewController: UIViewController {
     
    //表格
    var tableView:UITableView!
     
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
        super.viewDidLoad()
         
        //創(chuàng)建表格視圖
        self.tableView = UITableView(frame: self.view.frame, style:.plain)
        //創(chuàng)建一個(gè)重用的單元格
        self.tableView!.register(UITableViewCell.self,
                                 forCellReuseIdentifier: "Cell")
        self.view.addSubview(self.tableView!)
         
        //設(shè)置頭部刷新控件
        self.tableView.mj_header = MJRefreshNormalHeader()
        //設(shè)置尾部刷新控件
        self.tableView.mj_footer = MJRefreshBackNormalFooter()
         
        //初始化ViewModel
        let viewModel = ViewModel(
            input: (
                headerRefresh: self.tableView.mj_header.rx.refreshing.asObservable() ,
                footerRefresh: self.tableView.mj_footer.rx.refreshing.asObservable()),
            dependency: (
                disposeBag: self.disposeBag,
                networkService: NetworkService()))
         
        //單元格數(shù)據(jù)的綁定
        viewModel.tableData
            .bind(to: tableView.rx.items) { (tableView, row, element) in
                let cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!
                cell.textLabel?.text = "\(row+1)溯街、\(element)"
                return cell
            }
            .disposed(by: disposeBag)
         
        //下拉刷新狀態(tài)結(jié)束的綁定
        viewModel.endHeaderRefreshing
            .bind(to: self.tableView.mj_header.rx.endRefreshing)
            .disposed(by: disposeBag)
         
        //上拉刷新狀態(tài)結(jié)束的綁定
        viewModel.endFooterRefreshing
            .bind(to: self.tableView.mj_footer.rx.endRefreshing)
            .disposed(by: disposeBag)
    }
}

RxSwift使用詳解系列
原文出自:www.hangge.com轉(zhuǎn)載請保留原文鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市洋丐,隨后出現(xiàn)的幾起案子呈昔,更是在濱河造成了極大的恐慌,老刑警劉巖友绝,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件堤尾,死亡現(xiàn)場離奇詭異,居然都是意外死亡迁客,警方通過查閱死者的電腦和手機(jī)郭宝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掷漱,“玉大人粘室,你說我怎么就攤上這事〔贩叮” “怎么了衔统?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長海雪。 經(jīng)常有香客問我锦爵,道長,這世上最難降的妖魔是什么喳魏? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任棉浸,我火速辦了婚禮怀薛,結(jié)果婚禮上刺彩,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好创倔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布嗡害。 她就那樣靜靜地躺著,像睡著了一般畦攘。 火紅的嫁衣襯著肌膚如雪霸妹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天知押,我揣著相機(jī)與錄音叹螟,去河邊找鬼。 笑死台盯,一個(gè)胖子當(dāng)著我的面吹牛罢绽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播静盅,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼良价,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蒿叠?” 一聲冷哼從身側(cè)響起明垢,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎市咽,沒想到半個(gè)月后痊银,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡魂务,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年曼验,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粘姜。...
    茶點(diǎn)故事閱讀 39,834評論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鬓照,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出孤紧,到底是詐尸還是另有隱情豺裆,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布号显,位于F島的核電站臭猜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏押蚤。R本人自食惡果不足惜誊册,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一恐锦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽裸违。三九已至,卻和暖如春本昏,著一層夾襖步出監(jiān)牢的瞬間供汛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工涌穆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留怔昨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓宿稀,卻偏偏與公主長得像朱监,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子原叮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容