用 RxSwift 實現 UITableView 的響應式綁定(超實用示例)

目錄

前言

一、環境準備

1.安裝 RxSwift 和 RxCocoa

2.導入模塊

二、實現一個簡單的UITableView

1.實現一個簡單的 UITableView

1.實現步驟

1.我們聲明一個ViewModel

2.ViewModel和UITableView 綁定

2.實現 UITableView 的代理方法

三、處理點擊事件


前言

????????在 iOS 開發中,UITableView 是我們最常使用的組件之一。傳統的寫法需要設置 delegate、datasource,實現多個方法。而使用 RxSwift + RxCocoa,我們可以讓列表渲染邏輯更清晰、響應式,更符合 MVVM 模式。

????????這篇文章將手把手教你用 RxSwift 來綁定 UITableView,構建一個“設置”頁面,包括多個 section 和點擊事件。

一、環境準備

1.安裝 RxSwift 和 RxCocoa

????????首先我們要安裝 RxSwift 和 RxCocoa。你可以選擇你喜歡的方式,我這里以 cocoapods 為例:

? ? ? ? 這里我使用的Xcode 的版本為Xcode 16.3,RxSwift 和 RxCocoa的版本號為 6.9.0。

pod 'RxSwift'
pod 'RxCocoa'

2.導入模塊

import RxSwift
import RxCocoa

二、實現一個簡單的UITableView

? ? ? ? 我們以一個簡單的 UITableView 為例,看看如何實現一個最簡單的 UITableView。具體要實現的 UI 效果如圖所示:

圖 1.簡單的 UITableView

1.實現一個簡單的 UITableView

1.實現步驟

????????我們看一下詳細的實現步驟:

1.我們聲明一個ViewModel

class SimpleTableViewModel {

? ? // 模擬數據源

? ? let items = Observable.just([

? ? ? ? "第一行", "第二行", "第三行", "第四行", "第五行"

? ? ])

}

2.ViewModel和UITableView 綁定

? ? ? ? 設置好數據之后,我們調用 bind 方法把 UITableView 和 ViewModel 綁定即可實現一個簡單的 UITableView。

? ? private func setupBindingUITableView(){

? ? ? ? tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")

? ? ? ? tableView.dataSource = nil

? ? ? ? tableView.delegate = nil

? ? ? ? // 綁定 ViewModel 數據到 tableView

? ? ? ? viewModel.items

? ? ? ? ? ? .bind(to: tableView.rx.items(cellIdentifier: "Cell")) { index, model, cell in

? ? ? ? ? ? ? ? cell.textLabel?.text = "\(index + 1).\(model)"

? ? ? ? ? ? ? ? cell.accessoryType = .disclosureIndicator

? ? ? ? ? ? }

? ? ? ? ? ? .disposed(by: disposeBag)

? ? }

? ? ? ? 完整的代碼如下:

import UIKit
import RxSwift
import RxCocoaclass SimpleTableViewModel {// 模擬數據源let items = Observable.just(["第一行", "第二行", "第三行", "第四行", "第五行"])
}class SimpleTableViewController: UITableViewController {private let disposeBag = DisposeBag()private let viewModel = SimpleTableViewModel()override func viewDidLoad() {super.viewDidLoad()self.title = "Rx 簡單列表"setupBindingUITableView()}private func setupBindingUITableView(){tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")tableView.dataSource = niltableView.delegate = nil// 綁定 ViewModel 數據到 tableViewviewModel.items.bind(to: tableView.rx.items(cellIdentifier: "Cell")) { index, model, cell incell.textLabel?.text = "\(index + 1).\(model)"cell.accessoryType = .disclosureIndicator}.disposed(by: disposeBag)}
}

2.實現 UITableView 的代理方法

? ? ? ? RxCocoa 還封裝了UITableView的DataSource方法,例如我們想要實現 cell的點擊方法,僅需要調用下面的代碼即可:

? ? ? ? tableView.rx.itemSelected.subscribe {[weak self] indexPath in

? ? ? ? ? ? debugPrint("點擊了 Section: \(indexPath.section), Row: \(indexPath.row)")

? ? ? ? }.disposed(by: disposeBag)

? ? ? ? 除此之外,封裝了 itemDeselected(反選)、itemHighlighted(高亮)、itemUnhighlighted(取消高亮)、itemAccessoryButtonTapped(itemAccessory 點擊)、itemInserted(item 增加)、itemDeleted(item 刪除)等方法,這里您可以調用下看看。

? ? ? ? 這里我寫了一個簡單的 UITableView 數據源的增加和刪除功能 demo,完整代碼如下:

import UIKit
import SnapKit
import RxSwift
import RxCocoaclass RxSwiftTableViewModel {// 模擬數據源var items = BehaviorSubject(value: ["第一行", "第二行", "第三行", "第四行", "第五行"])// 增加一行數據func addItem() {var currentItems = try! items.value()currentItems.append("新的一行")items.onNext(currentItems)}// 刪除一行數據func removeItem(at index: Int) {var currentItems = try! items.value()if index >= 0 && index < currentItems.count {currentItems.remove(at: index)items.onNext(currentItems)}}}class RxSwiftUITableViewDemosVC: UIViewController {private let disposeBag = DisposeBag()private let viewModel = RxSwiftTableViewModel()private let tableView = UITableView()private let addButton = UIButton(type: .system)private let removeButton = UIButton(type: .system)override func viewDidLoad() {super.viewDidLoad()self.title = "RxSwift UITableView Demo"view.backgroundColor = .white// 使用 SnapKit 設置 tableView 布局setupTableView()// 使用 SnapKit 設置按鈕布局setupButtons()// 綁定 ViewModel 數據到 tableViewviewModel.items.bind(to: tableView.rx.items(cellIdentifier: "Cell")) { index, model, cell incell.textLabel?.text = model}.disposed(by: disposeBag)// 處理點擊事件tableView.rx.itemSelected.subscribe(onNext: { [weak self] indexPath inself?.tableView.deselectRow(at: indexPath, animated: true)print("點擊了 Section: \(indexPath.section), Row: \(indexPath.row)")}).disposed(by: disposeBag)// 增加數據按鈕點擊事件addButton.rx.tap.subscribe(onNext: { [weak self] inself?.viewModel.addItem()}).disposed(by: disposeBag)// 刪除數據按鈕點擊事件removeButton.rx.tap.subscribe(onNext: { [weak self] in// 刪除最后一行數據let currentCount = (try? self?.viewModel.items.value().count ?? 0) ?? 0let lastIndex = currentCount - 1if lastIndex >= 0 {self?.viewModel.removeItem(at: lastIndex)}}).disposed(by: disposeBag)//選中 modeltableView.rx.modelSelected(String.self).subscribe { element indebugPrint("you selected section:\(element)")}.disposed(by: disposeBag)}private func setupTableView() {// 添加 tableView 到視圖view.addSubview(tableView)// 使用 SnapKit 設置 tableView 布局tableView.snp.makeConstraints { make inmake.top.equalToSuperview()make.left.right.equalToSuperview()make.bottom.equalToSuperview().offset(-100) // 留出按鈕位置}// 注冊 UITableViewCelltableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")}private func setupButtons() {// 添加按鈕到視圖view.addSubview(addButton)view.addSubview(removeButton)// 設置按鈕標題addButton.setTitle("增加一行數據", for: .normal)removeButton.setTitle("刪除一行數據", for: .normal)// 使用 SnapKit 設置按鈕布局addButton.snp.makeConstraints { make inmake.left.equalToSuperview().inset(20)make.bottom.equalToSuperview().inset(20)make.height.equalTo(44)make.width.equalToSuperview().dividedBy(2).offset(-30)}removeButton.snp.makeConstraints { make inmake.right.equalToSuperview().inset(20)make.bottom.equalToSuperview().inset(20)make.height.equalTo(44)make.width.equalToSuperview().dividedBy(2).offset(-30)}}
}

三、處理點擊事件

? ? ? ? 當你需要實現更復雜的 UITableView,可以實用 RxSwift+RxDataSource 實現更復雜的 UITableView。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/81415.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/81415.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/81415.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【C++】通過紅黑樹封裝map和set

前言&#xff1a; 通過之前的學習&#xff0c;我們已經學會了紅黑樹和map、set。這次我們要實現自己的map和set&#xff0c;對&#xff0c;使用紅黑樹進行封裝&#xff01; 當然&#xff0c;紅黑樹內容這里就不在贅述&#xff0c;我們會復用紅黑樹的代碼&#xff0c;所以先將…

非凸科技受邀出席AI SPARK活動,共探生成式AI驅動金融新生態

4月19日&#xff0c;由AI SPARK社區主辦的“生成式AI創新與應用構建”主題沙龍在北京舉行。活動聚焦生成式AI的技術突破與產業融合&#xff0c;圍繞大模型優化、多模態應用、存內計算等前沿議題展開深度探討。非凸科技受邀出席并發表主題演講&#xff0c;深入解析金融垂直大模型…

【Java IO流】IO流詳解

參考筆記&#xff1a;【Java基礎-3】吃透Java IO&#xff1a;字節流、字符流、緩沖流_javaio-CSDN博客 目錄 1.IO流簡介 1.1 什么是IO流&#xff1f; 1.2 IO流的分類 1.3 字符流和字節流的其他區別 1.4 Java IO流體系圖 2.字符編碼詳解 3. Java的char類型與 Unicode、U…

驅動開發系列56 - Linux Graphics QXL顯卡驅動代碼分析(三)顯示模式設置

一:概述 如之前介紹,在qxl_pci_probe 中會調用 qxl_modeset_init 來初始化屏幕分辨率和刷新率,本文詳細看下 qxl_modeset_init 的實現過程。即QXL設備的顯示模式設置,是如何配置CRTC,Encoder,Connector 的以及創建和更新幀緩沖區的。 二:qxl_modeset_init 分析 in…

Vue3開發常見性能問題知多少

文章目錄 1 常見性能優化瓶頸及原因1.1 響應式數據的過度使用1.2 虛擬 DOM 的頻繁更新1.3 組件渲染的冗余1.4 大列表渲染的性能問題1.5 計算屬性和偵聽器的濫用1.6 事件處理函數的頻繁綁定1.7 異步組件的加載性能2 解決方案與優化技巧2.1 合理使用響應式數據2.2 優化虛擬 DOM 更…

Rust Ubuntu下編譯生成環境win程序踩坑指南

前言&#xff1a; 1&#xff0c;公司要給一線搞一個升級程序&#xff0c;需要在win下跑。 之前都是找開發總監幫忙&#xff0c;但是他最近比較忙。就讓我自己搞。有了下文.。說來慚愧&#xff0c;之前寫過一篇ubuntu下編譯windows的文章。里面的demo就一句話 fuck world。依賴…

openharmony 4.1 運行busybox工具包(保姆教程)

1.下載 鏈接&#xff1a;Index of /downloads/binaries 進入其中后&#xff0c;找到 挑選適合你系統架構的版本&#xff0c;例如我這邊是 https://busybox.net/downloads/binaries/1.31.0-defconfig-multiarch-musl/busybox-armv7r 右鍵復制鏈接 打開迅雷&#xff0c;直接粘…

算法四 習題 1.3

數組實現棧 #include <iostream> #include <vector> #include <stdexcept> using namespace std;class MyStack { private:vector<int> data; // 用于存儲棧元素的數組public:// 構造函數MyStack() {}// 入棧操作void push(int val) {data.push_back…

GD32F407單片機開發入門(十七)內部RTC實時時鐘及實戰含源碼

文章目錄 一.概要二.RTC基本特點三.GD32單片機RTC內部結構圖四.配置一個RTC走秒例程五.工程源代碼下載六.小結 一.概要 RTC&#xff08;Real-Time Clock&#xff09;是一種用于追蹤和記錄實際時間的時鐘系統。RTC模塊提供了一個包含日期&#xff08;年/月/日&#xff09;和時間…

新能源汽車運動控制器核心芯片選型與優化:MCU、DCDC與CANFD協同設計

摘要&#xff1a;隨著新能源汽車產業的迅猛發展&#xff0c;汽車運動控制器的性能和可靠性面臨著更高的要求。本文深入探討了新能源汽車運動控制器中MCU&#xff08;微控制單元&#xff09;、DCDC電源管理芯片和CANFD總線通信芯片的選型要點、優化策略及其協同設計方案。通過綜…

2.maven 手動安裝 jar包

1.背景 有的時候&#xff0c;maven倉庫無法下載&#xff0c;可以手動安裝。本文以pentaho-aggdesigner-algorithm-5.1.5-jhyde.jar為例。 2.預先準備 下載文件到本地指定位置。 2.1.安裝pom mvn install:install-file \-Dfile/home/wind/tmp/pentaho-aggdesigner-5.1.5-jh…

OpenCV 圖形API(75)圖像與通道拼接函數-----將 4 個單通道圖像矩陣 (GMat) 合并為一個 4 通道的多通道圖像矩陣函數merge4()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 由4個單通道矩陣創建一個4通道矩陣。 該函數將多個矩陣合并為一個單一的多通道矩陣。也就是說&#xff0c;輸出矩陣的每一個元素都是輸入矩陣對…

AI日報 · 2025年05月02日 | 再見GPT-4!OpenAI CEO 確認 GPT-4 已從 ChatGPT 界面正式移除

1、OpenAI CEO 確認 GPT-4 已從 ChatGPT 界面正式移除 在處理 GPT-4o 更新問題的同時&#xff0c;OpenAI CEO Sam Altman 于 5 月 1 日在 X 平臺發文&#xff0c;正式確認初代 GPT-4 模型已從 ChatGPT 主用戶界面中移除。此舉遵循了 OpenAI 此前公布的計劃&#xff0c;即在 4 …

patch命令在代碼管理中的應用

patch 是一個用于將差異文件&#xff08;補丁&#xff09;應用到源代碼的工具&#xff0c;常用于修復 bug、添加功能或調整代碼結構。在您提供的代碼中&#xff0c;patch 命令通過一系列補丁文件&#xff08;.patch&#xff09;修改了 open-amp 庫的源代碼。 patch 命令的核心作…

spring-ai集成langfuse

1、pom文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.…

PyTorch 與 TensorFlow:深度學習框架的深度剖析與實戰對比

PyTorch 與 TensorFlow&#xff1a;深度學習框架的深度剖析與實戰對比 摘要 &#xff1a;本文深入對比 PyTorch 與 TensorFlow 兩大深度學習框架&#xff0c;從核心架構、優缺點、適用場景等多維度剖析&#xff0c;結合實例講解&#xff0c;幫助開發者清晰理解兩者特性&#x…

如何配置NGINX作為反向代理服務器來緩存后端服務的響應?

大家好&#xff0c;我是鋒哥。今天分享關于【如何配置NGINX作為反向代理服務器來緩存后端服務的響應&#xff1f;】面試題。希望對大家有幫助&#xff1b; 如何配置NGINX作為反向代理服務器來緩存后端服務的響應&#xff1f; 1000道 互聯網大廠Java工程師 精選面試題-Java資源…

DiT:文檔圖像Transformer 的自監督預訓練

摘要 圖像transformer&#xff08;Image Transformer&#xff09;最近在自然圖像理解方面取得了顯著進展&#xff0c; 無論是使用監督&#xff08;ViT、DeiT等&#xff09;還是自監督&#xff08;BEiT、MAE等&#xff09;預訓練技術。在本文中&#xff0c;我們提出了DiT&#…

51c嵌入式~電路~合集4

我自己的原文哦~ https://blog.51cto.com/whaosoft/11888986 一、電流檢測電路 電流檢測的應用 電路檢測電路常用于&#xff1a;高壓短路保護、電機控制、DC/DC換流器、系統功耗管理、二次電池的電流管理、蓄電池管理等電流檢測等場景。電路專輯 對于大部分應用&#xff…

【Git】萬字詳解 Git 的原理與使用(上)

&#x1f970;&#x1f970;&#x1f970;來都來了&#xff0c;不妨點個關注叭&#xff01; &#x1f449;博客主頁&#xff1a;歡迎各位大佬!&#x1f448; 文章目錄 1. 初識 Git1.1 Git 是什么&#xff1f;1.2 為什么要有 Git 2. 安裝 Git2.1 Linux-Ubuntu 安裝 Git2.2 Windo…