RxSwift:立即交付第一个项目,消除后续项目
Posted
技术标签:
【中文标题】RxSwift:立即交付第一个项目,消除后续项目【英文标题】:RxSwift: Deliver the first item immediately, debounce following items 【发布时间】:2018-07-15 00:05:30 【问题描述】:我有一个要验证的文本字段,我想在用户输入时禁用按钮。用户停止输入后(反跳 1 秒),将执行验证并根据结果有条件地启用按钮。请注意当用户只输入一个字符时的极端情况,仍然应该进行验证。
--"a"-"ab"-"abc"------------------"ab"--"a"------------------"ab"-----------------
--false---------validate("abc")---false----validate("a")-----false--validate("ab")
这个 SO (Deliver the first item immediately, 'debounce' following items) 在 RxJava 中提出了以下解决方案。但它似乎只返回第一个元素,而不是当用户在去抖动后再次开始输入时?如果我错了,请纠正我
Observable.from(items).publish(publishedItems ->
publishedItems.limit(1).concatWith(
publishedItems.skip(1).debounce(1, TimeUnit.SECONDS)
)
)
【问题讨论】:
您是否希望在用户输入时禁用按钮,并在输入完成后与验证功能的结果相匹配? 没错,他们是否完成打字是由debounce
决定的
【参考方案1】:
一种选择是将“用户是否在输入”这个问题与“输入是否有效”分开。
描述用户是否在打字的一种(有点笨拙)的方式:
let isTyping = PublishSubject<Bool>()
textField.rx.text
.map _ in true
.bind(to: isTyping)
.disposed(by: disposeBag)
textField.rx.text
.debounce(1.0, scheduler: MainScheduler.instance)
.map _ in false
.bind(to: isTyping)
.disposed(by: disposeBag)
然后,您可以像这样描述按钮启用状态:
isTyping.withLatestFrom(isValid) !$0 && $1
.bind(to: button.rx.isEnabled)
当然,要让这种方法在用户开始输入时立即生效,最好isValid
以一个值开头。
您还可以通过以下方式简化此过程。如果这些值只在本地使用,这可能没问题。
textField.rx.text
.map _ in false
.bind(to: button.rx.isEnabled)
.disposed(by: disposeBag)
textField.rx.text
.debounce(1.0, scheduler: MainScheduler.instance)
.flatMap [weak self] in self?.validate($0)
.bind(to: button.rx.isEnabled)
.disposed(by: disposeBag)
请注意,使用这种方法时,需要在用户继续输入时取消异步验证操作。
希望有人可以提出更清洁的解决方案,但我认为这是一个不错的起点。
【讨论】:
其实我也想过第二种方法。一旦用户再次输入,是否有一种反应方式来取消异步操作或忽略其结果? 如果不了解您的应用程序的网络层,我很难回答这个问题。一般来说,重新启动观察的“大锤”选项是重新分配相关的处理包,但我认为这不是你想要的。另一种选择是检查 textField 在验证过程中是否没有更改:【参考方案2】:经过一番思考,我能够通过以下方式完全解决它,一切都按我的意图进行
let input = textField.rx.text.distinctUntilChanged()
let keystroke = input.map _ in Observable.just(false)
let validate = input
.flatMap Observable.from(optional: $0) // 1
.filter $0.count >= minimumTextLength
.debounce(1, scheduler: MainScheduler.instance)
.map self.networkManager.validate($0).asObservable() // 2
return Observable.merge(keystroke, validate).switchLatest().distinctUntilChanged() // 3
-
安全地解开可选字符串
validate
在我的例子中返回 Single<Bool>
,所以我把它变成 Observable
。请注意,我故意使用 map
而不是 flatMap
,以便使用步骤 3 中 switchLatest
提供的功能
我合并 a 和 b 以创建 Observable<Observable<Bool>>
,switchLatest
允许我在用户再次开始输入时忽略 validate
结果。 distinctUntilChanged
丢弃重复的 false
s
【讨论】:
以上是关于RxSwift:立即交付第一个项目,消除后续项目的主要内容,如果未能解决你的问题,请参考以下文章