RxAndroid:观察 EditText 同时观察 2 个视图上的触摸
RxAndroid: Observe an EditText while also observing touches on 2 Views
让我为一个小任务征求意见,我花了几天时间才弄明白...
我有一个 EditText,用户将在其中输入一个字符串,该字符串将用于进行维基百科搜索并将结果提供给 ListView。 EditText 应该有 1 秒的限制,并且必须进行过滤才能检查 'inappropriate' 字符串列表。如果输入在该字符串列表中,则搜索不会通过,除非用户同时触摸屏幕 2 个角上的 2 个隐藏视图,否则它将跳过此检查。
这里有一些片段可以帮助您了解我已经拥有的...
// a list of inappropriate content
private static String[] INAPPROPRIATE_CONTENT = {
"test"
};
// subscription to the touches happening on hidden view #1
Subscription subSecretLeft = RxView.touches(vSecretLeft)
.filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP)
.subscribe(motionEvent -> secretLeftClicked = motionEvent.getAction() == MotionEvent.ACTION_DOWN);
// subscription to the touches happening on hidden view #2
RxView.touches(vSecretRight)
.filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP)
.subscribe(motionEvent -> secretRightClicked = motionEvent.getAction() == MotionEvent.ACTION_DOWN);
// subscription to the EditText
RxTextView.textChanges(etxtSearchFilter)
.throttleLast(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.map(c -> c.toString().trim())
.filter(s -> !(s.isEmpty() || isInappropriate(s)))
.subscribe(s -> fetchWikiSearch(s));
其中 isInappropriate(String s) 是检查是否在数组中找到术语的方法,fetchWikiSearch(String s) 执行搜索并填充 ListView。
我尝试了几种方法,最后想到的方法如下:
Observable.zip(
Observable.combineLatest(
RxView.touches(vSecretLeft)
.filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL),
RxView.touches(vSecretRight)
.filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL),
(ev1, ev2) -> ev1.getAction() == MotionEvent.ACTION_DOWN && ev2.getAction() == MotionEvent.ACTION_DOWN
).asObservable(),
RxTextView.textChanges(etxtSearchFilter)
.throttleLast(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.map(c -> c.toString().trim())
.filter(s -> !s.isEmpty()),
(overrideFilter, s) ->
overrideFilter || !isInappropriate(s) ? s : "BLOCKED"
).subscribe(s -> Log.i("ObservableZip", "s: " + s));
但显然,只要我不触及那些视图,它就不会发出任何东西。即使 Observable.combileLatest() 也不能很好地工作,因为只有当两个视图都获得 MotionEvent.ACTION_DOWN...
时它才会发出
如果您有任何提示或实际解决方案,请随时发表评论。谢谢
这还不够吗?
Observable.combineLatest(
RxView.touches(vSecretLeft)
.filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL),
RxView.touches(vSecretRight)
.filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL),
RxTextView.textChanges(etxtSearchFilter)
.debounce(1, TimeUnit.SECONDS)
.map(c -> c.toString().trim())
.filter(s -> !s.isEmpty()),
(motionEventLeft, motionEventRight, entered) -> {
boolean overrideFilter = motionEventLeft.getAction() == MotionEvent.ACTION_DOWN && motionEventRight.getAction() == MotionEvent.ACTION_DOWN;
return overrideFilter || !isInappropriate(entered) ? entered : "BLOCKED";
})
.subscribe(s -> Log.i("ObservableCombineLatest", "s: " + s));
(我也将 throttleLast
更改为 debounce
,因为这样做感觉更好)
编辑
Observable.combineLatest(
RxView.touches(vSecretLeft)
.map(motionEvent -> motionEvent.getAction())
.filter(action -> action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)
.startWith(MotionEvent.ACTION_UP),
RxView.touches(vSecretRight)
.map(motionEvent -> motionEvent.getAction())
.filter(action -> action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)
.startWith(MotionEvent.ACTION_UP),
RxTextView.textChanges(etxtSearchFilter)
.debounce(1, TimeUnit.SECONDS)
.map(c -> c.toString().trim())
.filter(s -> !s.isEmpty()),
(leftAction, rightAction, entered) -> {
boolean overrideFilter = leftAction == MotionEvent.ACTION_DOWN && rightAction == MotionEvent.ACTION_DOWN;
return overrideFilter || !isInappropriate(entered) ? entered : "BLOCKED";
})
.subscribe(s -> Log.i("ObservableCombineLatest", "s: " + s));
您似乎走在正确的轨道上,但您可能想 "initialize" 使用 startsWith
隐藏视图,即
// subscription to the touches happening on hidden view #1
Subscription subSecretLeft = RxView.touches(vSecretLeft)
.filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP)
.startsWith(MotionEvent.ACTION_UP)
.subscribe(motionEvent -> secretLeftClicked = motionEvent.getAction() == MotionEvent.ACTION_DOWN);
让我为一个小任务征求意见,我花了几天时间才弄明白...
我有一个 EditText,用户将在其中输入一个字符串,该字符串将用于进行维基百科搜索并将结果提供给 ListView。 EditText 应该有 1 秒的限制,并且必须进行过滤才能检查 'inappropriate' 字符串列表。如果输入在该字符串列表中,则搜索不会通过,除非用户同时触摸屏幕 2 个角上的 2 个隐藏视图,否则它将跳过此检查。
这里有一些片段可以帮助您了解我已经拥有的...
// a list of inappropriate content
private static String[] INAPPROPRIATE_CONTENT = {
"test"
};
// subscription to the touches happening on hidden view #1
Subscription subSecretLeft = RxView.touches(vSecretLeft)
.filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP)
.subscribe(motionEvent -> secretLeftClicked = motionEvent.getAction() == MotionEvent.ACTION_DOWN);
// subscription to the touches happening on hidden view #2
RxView.touches(vSecretRight)
.filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP)
.subscribe(motionEvent -> secretRightClicked = motionEvent.getAction() == MotionEvent.ACTION_DOWN);
// subscription to the EditText
RxTextView.textChanges(etxtSearchFilter)
.throttleLast(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.map(c -> c.toString().trim())
.filter(s -> !(s.isEmpty() || isInappropriate(s)))
.subscribe(s -> fetchWikiSearch(s));
其中 isInappropriate(String s) 是检查是否在数组中找到术语的方法,fetchWikiSearch(String s) 执行搜索并填充 ListView。
我尝试了几种方法,最后想到的方法如下:
Observable.zip(
Observable.combineLatest(
RxView.touches(vSecretLeft)
.filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL),
RxView.touches(vSecretRight)
.filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL),
(ev1, ev2) -> ev1.getAction() == MotionEvent.ACTION_DOWN && ev2.getAction() == MotionEvent.ACTION_DOWN
).asObservable(),
RxTextView.textChanges(etxtSearchFilter)
.throttleLast(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.map(c -> c.toString().trim())
.filter(s -> !s.isEmpty()),
(overrideFilter, s) ->
overrideFilter || !isInappropriate(s) ? s : "BLOCKED"
).subscribe(s -> Log.i("ObservableZip", "s: " + s));
但显然,只要我不触及那些视图,它就不会发出任何东西。即使 Observable.combileLatest() 也不能很好地工作,因为只有当两个视图都获得 MotionEvent.ACTION_DOWN...
时它才会发出如果您有任何提示或实际解决方案,请随时发表评论。谢谢
这还不够吗?
Observable.combineLatest(
RxView.touches(vSecretLeft)
.filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL),
RxView.touches(vSecretRight)
.filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL),
RxTextView.textChanges(etxtSearchFilter)
.debounce(1, TimeUnit.SECONDS)
.map(c -> c.toString().trim())
.filter(s -> !s.isEmpty()),
(motionEventLeft, motionEventRight, entered) -> {
boolean overrideFilter = motionEventLeft.getAction() == MotionEvent.ACTION_DOWN && motionEventRight.getAction() == MotionEvent.ACTION_DOWN;
return overrideFilter || !isInappropriate(entered) ? entered : "BLOCKED";
})
.subscribe(s -> Log.i("ObservableCombineLatest", "s: " + s));
(我也将 throttleLast
更改为 debounce
,因为这样做感觉更好)
编辑
Observable.combineLatest(
RxView.touches(vSecretLeft)
.map(motionEvent -> motionEvent.getAction())
.filter(action -> action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)
.startWith(MotionEvent.ACTION_UP),
RxView.touches(vSecretRight)
.map(motionEvent -> motionEvent.getAction())
.filter(action -> action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL)
.startWith(MotionEvent.ACTION_UP),
RxTextView.textChanges(etxtSearchFilter)
.debounce(1, TimeUnit.SECONDS)
.map(c -> c.toString().trim())
.filter(s -> !s.isEmpty()),
(leftAction, rightAction, entered) -> {
boolean overrideFilter = leftAction == MotionEvent.ACTION_DOWN && rightAction == MotionEvent.ACTION_DOWN;
return overrideFilter || !isInappropriate(entered) ? entered : "BLOCKED";
})
.subscribe(s -> Log.i("ObservableCombineLatest", "s: " + s));
您似乎走在正确的轨道上,但您可能想 "initialize" 使用 startsWith
隐藏视图,即
// subscription to the touches happening on hidden view #1
Subscription subSecretLeft = RxView.touches(vSecretLeft)
.filter(motionEvent -> motionEvent.getAction() == MotionEvent.ACTION_DOWN || motionEvent.getAction() == MotionEvent.ACTION_UP)
.startsWith(MotionEvent.ACTION_UP)
.subscribe(motionEvent -> secretLeftClicked = motionEvent.getAction() == MotionEvent.ACTION_DOWN);