3

Im using RxSwift and RxCocoa in my project.

I have some UITextField named "lastNameTF", and there is a UILabel name "lastNameTitle".

I wanna know if there is any way to set the isHidden value of lastNameTitle always be equal to isHidden value of lastNameTF using RxSwift.

Asi Givati
  • 1,348
  • 1
  • 15
  • 31

3 Answers3

2

I believe you can use KVO as described here - https://github.com/ReactiveX/RxSwift/blob/master/Documentation/GettingStarted.md#kvo

Maxim Volgin
  • 3,957
  • 1
  • 23
  • 38
1

It is super easy to use KVO. Here is an example of exactly what you are trying to do, just without using RxSwift (don't know what that is...)

Here is the gist of it

class ViewController: UIViewController {
    private var lastNameTextFieldHiddenContext = 0
    private var lastNameObservingView:UIView? = nil
    @IBOutlet weak var lastNameLabel: UILabel!
    @IBOutlet weak var lastNameTextField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()
        // add the observer
        lastNameTextField.addObserver(
            self,
            forKeyPath: "hidden",
            options: [.new],
            context: &self.lastNameTextFieldHiddenContext
        )
    }

    /// function will be called whenever an added observer is triggered
    override func observeValue(
        forKeyPath keyPath: String?,
        of object: Any?,
        change: [NSKeyValueChangeKey : Any]?,
        context: UnsafeMutableRawPointer?
    ) {
        // make sure it is our text field isHidden observer
        if context == &self.lastNameTextFieldHiddenContext {
            // get the new value that was set
            if let newValue = change?[NSKeyValueChangeKey.newKey] as? Bool {
                // do what needs to be done when the observer is triggered
                self.lastNameLabel.isHidden = newValue
            }
        }
    }

    deinit {
        // remove the observer
        if let view = self.lastNameObservingView {
            view.removeObserver(self, forKeyPath: "hidden")
            self.lastNameObservingView = nil
        }
    }

    @IBAction func showHideButtonAction(_ sender: Any) {
        self.lastNameTextField.isHidden = !self.lastNameTextField.isHidden
    }
}
Popmedic
  • 1,791
  • 1
  • 16
  • 21
  • Your answer is not exactly what i looked for, but it helped me in some way. RxSwift is awesome you should check it out. My problem was that i tried to listen to property with "keyPath" named "isHidden", but after reading your answer i saw that u used "hidden" as keyPath and it worked for me :) – Asi Givati Jul 12 '18 at 14:12
  • This explains why it is "hidden" not "isHidden". https://stackoverflow.com/questions/41746751/hidden-vs-keypathuiview-ishidden – Popmedic Jul 14 '18 at 13:32
0

If you still need a simple RxSwift approach please try this:

// Controls are visible by default (isHidden = false)
let isControlHidden = BehaviorRelay<Bool>(value: false)

override func viewDidLoad() {
  super.viewDidLoad()

  let isHiddenDriver = self.isControlHidden.asDriver()

  isHiddenDriver
    .drive(self.lastNameTitle.rx.isHidden)
    .disposed(by: disposeBag)

  isHiddenDriver
    .drive(self.lastNameTF.rx.isHidden)
    .disposed(by: disposeBag)
}

Since you need both control visibilities bound to each other, you can use a Subject or Relay to achieve that, in this case isControlHidden. So, if you want to show/hide the, you just emit a new signal:

@IBAction func hide(_ sender: Any) {
  self.isControlHidden.accept(true)
}

@IBAction func show(_ sender: Any) {
  self.isControlHidden.accept(false)
}
juliancadi
  • 987
  • 1
  • 8
  • 23
  • It looks great but there is compile error - Value of type 'Binder' has no member 'asDriver' – Asi Givati Jul 20 '18 at 19:09
  • You are right. 'lastNameTF.rx.isHidden' is not a ControlProperty but a Binder. However, I updated my answer with a still clean feasible solution that might help you. – juliancadi Jul 23 '18 at 12:01