问题描述
我正在使用RxSwift,目前,我有一个可以内联编辑的地址列表
IE:用户单击一个按钮,单元格就转换为编辑模式,基本上显示了几个UITextFields
现在的问题是,当我将TextField的输入绑定到我的模型时,TableView被重新加载,因此键盘被关闭,我也尝试了RxAnimatableDataSource,但无济于事,它仍然在每次击键时都关闭了键盘。
viewmodel:
user_id | one | two
1 | a | No Update
这是我的ViewController数据源到tableview的绑定
class UpdateAddressviewmodel: viewmodel,viewmodelType {
struct Input {
let viewDidLoad: AnyObserver<Void>
let selectItemTrigger: AnyObserver<Int>
let editButtonTrigger: AnyObserver<Int>
let editTrigger: AnyObserver<Int>
let firstNameIndexed: AnyObserver<(String,Int)>
let lastNameIndexed: AnyObserver<(String,Int)>
let address1Indexed: AnyObserver<(String,Int)>
let address2Indexed: AnyObserver<(String,Int)>
let zipIndexed: AnyObserver<(String,Int)>
let cityIndexed: AnyObserver<(String,Int)>
let stateIndexed: AnyObserver<(String,Int)>
let phoneIndexed: AnyObserver<(String,Int)>
}
struct Output {
let addresses: Driver<[Addressviewmodel]>
let reloadAndScroll: Driver<(Int,Bool)>
let showMenu: Driver<Int>
let error: Driver<Error>
}
private(set) var input: Input!
private(set) var output: Output!
//Input
private let viewDidLoad = PublishSubject<Void>()
private let editButtonTrigger = PublishSubject<Int>()
private let editTrigger = PublishSubject<Int>()
private let firstNameIndexed = ReplaySubject<(String,Int)>.create(bufferSize: 1)
private let lastNameIndexed = ReplaySubject<(String,Int)>.create(bufferSize: 1)
private let address1Indexed = ReplaySubject<(String,Int)>.create(bufferSize: 1)
private let address2Indexed = ReplaySubject<(String,Int)>.create(bufferSize: 1)
private let zipIndexed = ReplaySubject<(String,Int)>.create(bufferSize: 1)
private let cityIndexed = ReplaySubject<(String,Int)>.create(bufferSize: 1)
private let stateIndexed = ReplaySubject<(String,Int)>.create(bufferSize: 1)
private let phoneIndexed = ReplaySubject<(String,Int)>.create(bufferSize: 1)
//Output
private let addresses = BehaviorRelay<[Addressviewmodel]>(value: [Addressviewmodel()])
override init() {
super.init()
observeViewDidLoad()
observeEditAddress()
.bind(to: addresses)
.disposed(by: disposeBag)
firstNameIndexed
.withLatestFrom(addresses) { firstNameIndexed,viewmodels -> (String,Int,[Addressviewmodel]) in
let (firstName,index) = firstNameIndexed
return (firstName,index,viewmodels)
}
.map { firstName,viewmodels in
var viewmodels = viewmodels
viewmodels[index].address.firstName = firstName
return viewmodels
}
.bind(to: addresses)
.disposed(by: disposeBag)
input = Input(
viewDidLoad: viewDidLoad.asObserver(),selectItemTrigger: selectItemTrigger.asObserver(),editButtonTrigger: editButtonTrigger.asObserver(),editTrigger: editTrigger.asObserver(),firstNameIndexed: firstNameIndexed.asObserver(),lastNameIndexed: lastNameIndexed.asObserver(),address1Indexed: address1Indexed.asObserver(),address2Indexed: address2Indexed.asObserver(),zipIndexed: zipIndexed.asObserver(),cityIndexed: cityIndexed.asObserver(),stateIndexed: stateIndexed.asObserver(),phoneIndexed: phoneIndexed.asObserver()
)
output = Output(
addresses: addresses.asDriver(onErrorJustReturn: []),reloadAndScroll: reloadAndScroll,showMenu: editButtonTrigger.asDriverOnErrorJustComplete(),error: errorTracker.asDriver()
)
}
private func observeViewDidLoad() {
//Loading work here
}
private func observeEditAddress() -> Observable<[Addressviewmodel]> {
editTrigger
.withLatestFrom(addresses) { index,viewmodels in
return (index,viewmodels)
}
.map { index,viewmodels in
var viewmodels = viewmodels
for currentIndex in viewmodels.indices {
viewmodels[currentIndex].isSelected = currentIndex == index
viewmodels[currentIndex].isEditing = currentIndex == index
if currentIndex == index {
viewmodels[currentIndex].copyAddress()
}
}
return viewmodels
}
}
}
解决方法
您需要从更改地址的流中断开导致表视图更新的流。
示例可能类似于:
jq
表视图将绑定到typealias ID = Int // an example
typealias Address = String // probably needs to be more involved.
struct Input {
let updateAddress: Observable<(ID,Address)>
}
struct Output {
let cells: Observable<[ID]>
let addresses: Observable<[ID: Address]>
}
,而每个单元格都将绑定到cells
,而后者可以通过compactMap观察以提取其特定信息。
这样,您可以更新特定的单元格而无需重新加载表视图中的任何单元格。
可以在我的BashFAQ #1中找到充实的示例。