实现一个需求 —— 使用 RxSwift 订阅 UIView 的
最近在做项目的时候,遇到了一个需求。我有三个 View(View1, View2, View3),View1 和 View2 其中一个显示,View3 就显示。
稍微思考了一下,觉得订阅 isHidden 属性的改变,然后通过 CombineLatest
组合 Observable
来实现。
问题
而问题就来了。。。
14907957629836.jpgisHidden
居然是个 UIBindingObserver<UIView, Bool>
尝试使用 KVO
我在使用 OC 时,会使用 ReactiveCocoa
。而在 ReactiveCocoa
我经常使用 KVO 去监控属性。或者在 RxSwift
也有类似的方法吧?
好像的确有类似的东西,那就到源码中查看怎么使用吧。。。
14907966551999.jpg从这些注释,大概知道了使用方法,那就开干吧。。。
14907975018713.jpg只打印了 next(Optional(false))
, 并不能监控到 isHidden
值的变化=。=
为什么呢?难道我使用方法不对?找找可参照的例子。
在 KVOObservableTests.swift
找到了一段测试代码:
注意,这里的属性都使用了 dynamic
, 感觉好像抓到了些什么?先尝试定义一个类试试看。
起作用了😎,那把 dynamic
删了呢?
又不好使了😔 为什么呢?
其实喵神在《Swift 开发必备 Tips》中就提过这个问题。
所以,只能另想办法了😒
使用 methodInvoked
还记得 UITextField
经常使用的 text
属性么?它又是怎么实现的呢?
查看源码,发现它使用了 UIControl
的 value
方法。继续往下看。。。
这里是通过监控控件事件来实现的。。🤔那么 textField.rx.text.subscribe
同样存在一个问题
textField.text = "test"
这样的操作,也是没法得到事件的。。
但可以从这个段代码中得到给启发,我是否可以通过订阅方法处理来完成我想要的需求呢?我们在设置属性时必然会走 set
方法。
嗯,这个好像是我们需要的方法,那就看看能否实现吧。
14908006443769.jpg好像起作用了,但我们可以做进一步的优化。我希望事件就给我返回个 Bool
,而且包含一开始的默认属性。
这样就得到我想要的结果了🙃,但我可以让它变得更好用点,把它封装到 rx
中作为一个 hidden
属性好了
extension Reactive where Base: UIView {
var hidden: Observable<Bool> {
return self.methodInvoked(#selector(setter: self.base.isHidden))
.map { event -> Bool in
guard let isHidden = event.first as? Bool else {
fatalError()
}
return isHidden
}
.startWith(self.base.isHidden)
}
}
14908014060346.jpg
嗯,现在就可以愉快的订阅 hidden
属性了 (^-^)V
如果大家有更好的方法,欢迎分享讨论。
最后:欢迎讨论、批评、指错。