RxSwift 修改 select 上的表格视图单元格
RxSwift modify tableview cell on select
我的应用程序中有一个 table 视图。我使用以下代码
为此 table 生成了数据源
struct ContactNameNumberBlockStatus {
var contactThumbnail: Data?
var contactName : String
var contactNumber: String
var blockStatus : Bool
}
class BlockListTableViewCell: UITableViewCell {
@IBOutlet weak var contactImage: UIImageView!
@IBOutlet weak var contactName: UILabel!
@IBOutlet weak var contactNumber: UILabel!
@IBOutlet weak var blockButton: UIButton!
var eachCell : ContactNameNumberBlockStatus! {
didSet {
// setting ui
}
}
}
private func showTableContent(data : Observable<[ContactNameNumberBlockStatus]>) {
data.bindTo(tableView.rx.items(
cellIdentifier: "BlockListTableViewCell")) {
row, contributor, cell in
if let cell2 = cell as? BlockListTableViewCell {
cell2.eachCell = contributor
}
}.addDisposableTo(disposeBag)
}
现在,当我点击单元格时,我想将 ui 更新为 showing/hiding blockButton
上面提到的
如何操作??
在使用 rx 之前我使用了 table 的 didSelectRowAt 视图如下
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
contacts[indexPath.row].blockStatus = false
self?.tableView.reloadData()
}
我发现 tableView.rx.itemSelected
与上面的 didSelectRowAt
相同,但我找不到如何使用以下代码更新 table 视图
tableView.rx.itemSelected
.subscribe(onNext: { [weak self]indexPath in
}).addDisposableTo(disposeBag)
那么如何更新单元格呢?
您可以像这样访问单元格
tableView.rx.itemSelected
.subscribe(onNext: { [weak self] indexPath in
let cell = self?.tableview.cellForRow(at: indexPath) as? SomeCellClass
cell.button.isEnabled = false
}).addDisposableTo(disposeBag)
//访问模型
tableView.rx.modelSelected(Item.self)
.subscribe(onNext: { [weak self] model in
guard let self = self else { return }
self.selectedItem = model
}).disposed(by: disposeBag)
//访问indexPath
eg: var names = ["A", "B", "C"]
tableView.rx.itemSelected
.subscribe(onNext: { [weak self] indexPath in
guard let self = self else { return }
self.selectedName = self.names[indexPath.row]
self.performSegue(withIdentifier: "ItemDetail", sender: self)
}).disposed(by: disposeBag)
如果你想获得模型的句柄和索引路径,你可以在文件中同时拥有两者
我不太喜欢已接受的答案,因为在那个答案中,没有跟踪块状态的模型。相反,它只是禁用按钮。让视图的状态遵循模型很重要,接受的答案忽略了这一点。
下面的显然更复杂,但是它设置了模型并使视图的状态反映了底层模型而不是避免模型。
enum Input {
case reset([ContactNameNumberBlockStatus])
case blockTapped(UUID)
}
struct State {
var order: [UUID] = []
var values: [UUID: ContactNameNumberBlockStatus] = [:]
}
let taps = PublishSubject<UUID>()
let state = Observable.merge(
contacts.map { Input.reset([=10=]) },
taps.map { Input.blockTapped([=10=]) }
)
.scan(into: State()) { (state, input) in
switch input {
case .reset(let contacts):
state.order = contacts.map { _ in UUID() }
state.values = Dictionary.init(zip(state.order, contacts), uniquingKeysWith: { lhs, _ in lhs })
case .blockTapped(let uuid):
state.values[uuid]!.blockStatus = true
}
}
state
.map { [=10=].order }
.bind(to: tableView.rx.items(cellIdentifier: "BlockListTableViewCell", cellType: BlockListTableViewCell.self)) { row, uuid, cell in
let cellState = state.compactMap { [=10=].values[uuid] }
cell.disposeBag.insert(
cellState.map { [=10=].contactThumbnail.flatMap { UIImage(data: [=10=]) } }.bind(to: cell.contactImage.rx.image),
cellState.map { [=10=].contactName }.bind(to: cell.contactName.rx.text),
cellState.map { [=10=].contactNumber }.bind(to: cell.contactNumber.rx.text),
cellState.map { [=10=].blockStatus }.bind(to: cell.blockButton.rx.isHidden),
cell.blockButton.rx.tap.map { uuid }.bind(to: taps)
)
}
.disposed(by: disposeBag)
以上代码设置了一个状态机,用于跟踪用户并在必要时更新用户模型,进而导致视图更新。它更具可扩展性;当发现新的用户输入时,只需将大小写添加到 Input
类型。此外,当发现新状态时,可以将其添加到状态类型中。
该代码还有一个额外的好处;更新模型中某个项目的状态 不会 导致整个 table 视图重新加载。只会更改该单元格。
我的应用程序中有一个 table 视图。我使用以下代码
为此 table 生成了数据源struct ContactNameNumberBlockStatus {
var contactThumbnail: Data?
var contactName : String
var contactNumber: String
var blockStatus : Bool
}
class BlockListTableViewCell: UITableViewCell {
@IBOutlet weak var contactImage: UIImageView!
@IBOutlet weak var contactName: UILabel!
@IBOutlet weak var contactNumber: UILabel!
@IBOutlet weak var blockButton: UIButton!
var eachCell : ContactNameNumberBlockStatus! {
didSet {
// setting ui
}
}
}
private func showTableContent(data : Observable<[ContactNameNumberBlockStatus]>) {
data.bindTo(tableView.rx.items(
cellIdentifier: "BlockListTableViewCell")) {
row, contributor, cell in
if let cell2 = cell as? BlockListTableViewCell {
cell2.eachCell = contributor
}
}.addDisposableTo(disposeBag)
}
现在,当我点击单元格时,我想将 ui 更新为 showing/hiding blockButton
上面提到的
如何操作??
在使用 rx 之前我使用了 table 的 didSelectRowAt 视图如下
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
contacts[indexPath.row].blockStatus = false
self?.tableView.reloadData()
}
我发现 tableView.rx.itemSelected
与上面的 didSelectRowAt
相同,但我找不到如何使用以下代码更新 table 视图
tableView.rx.itemSelected
.subscribe(onNext: { [weak self]indexPath in
}).addDisposableTo(disposeBag)
那么如何更新单元格呢?
您可以像这样访问单元格
tableView.rx.itemSelected
.subscribe(onNext: { [weak self] indexPath in
let cell = self?.tableview.cellForRow(at: indexPath) as? SomeCellClass
cell.button.isEnabled = false
}).addDisposableTo(disposeBag)
//访问模型
tableView.rx.modelSelected(Item.self)
.subscribe(onNext: { [weak self] model in
guard let self = self else { return }
self.selectedItem = model
}).disposed(by: disposeBag)
//访问indexPath
eg: var names = ["A", "B", "C"]
tableView.rx.itemSelected
.subscribe(onNext: { [weak self] indexPath in
guard let self = self else { return }
self.selectedName = self.names[indexPath.row]
self.performSegue(withIdentifier: "ItemDetail", sender: self)
}).disposed(by: disposeBag)
如果你想获得模型的句柄和索引路径,你可以在文件中同时拥有两者
我不太喜欢已接受的答案,因为在那个答案中,没有跟踪块状态的模型。相反,它只是禁用按钮。让视图的状态遵循模型很重要,接受的答案忽略了这一点。
下面的显然更复杂,但是它设置了模型并使视图的状态反映了底层模型而不是避免模型。
enum Input {
case reset([ContactNameNumberBlockStatus])
case blockTapped(UUID)
}
struct State {
var order: [UUID] = []
var values: [UUID: ContactNameNumberBlockStatus] = [:]
}
let taps = PublishSubject<UUID>()
let state = Observable.merge(
contacts.map { Input.reset([=10=]) },
taps.map { Input.blockTapped([=10=]) }
)
.scan(into: State()) { (state, input) in
switch input {
case .reset(let contacts):
state.order = contacts.map { _ in UUID() }
state.values = Dictionary.init(zip(state.order, contacts), uniquingKeysWith: { lhs, _ in lhs })
case .blockTapped(let uuid):
state.values[uuid]!.blockStatus = true
}
}
state
.map { [=10=].order }
.bind(to: tableView.rx.items(cellIdentifier: "BlockListTableViewCell", cellType: BlockListTableViewCell.self)) { row, uuid, cell in
let cellState = state.compactMap { [=10=].values[uuid] }
cell.disposeBag.insert(
cellState.map { [=10=].contactThumbnail.flatMap { UIImage(data: [=10=]) } }.bind(to: cell.contactImage.rx.image),
cellState.map { [=10=].contactName }.bind(to: cell.contactName.rx.text),
cellState.map { [=10=].contactNumber }.bind(to: cell.contactNumber.rx.text),
cellState.map { [=10=].blockStatus }.bind(to: cell.blockButton.rx.isHidden),
cell.blockButton.rx.tap.map { uuid }.bind(to: taps)
)
}
.disposed(by: disposeBag)
以上代码设置了一个状态机,用于跟踪用户并在必要时更新用户模型,进而导致视图更新。它更具可扩展性;当发现新的用户输入时,只需将大小写添加到 Input
类型。此外,当发现新状态时,可以将其添加到状态类型中。
该代码还有一个额外的好处;更新模型中某个项目的状态 不会 导致整个 table 视图重新加载。只会更改该单元格。