Используя RxSwift, как включить UIButton на основе действительного текста?

В RxSwift/RxCocoa 2.0.0-beta 3 у меня есть ViewModel с:

let someString = Variable("")

func isValidSomeString() -> Observable<Bool>  {

    if someString.value.characters.count == 0 {
        return just(false)
    }
    return just(true)
}   

У меня уже есть строка someString, привязанная к текстовому полю в ViewController.

Всякий раз, когда изменяется какая-то строка (или, возможно, текстовое поле, если это лучше), я хочу, чтобы кнопка была включена в зависимости от того, действительна ли какая-то строка.

Я попытался использовать «Observable‹ Bool>», но начал идти по другому пути. Я мог бы сделать это в ViewController:

    someViewModel.someString.subscribeNext { text -> Void in

        // could just someUIButton.enabled = someViewModel.isValidSomeString(text)

    }.addDisposableTo(disposeBag)

Нет ли другого способа, менее подробного, чем подход isValidSomeString(text)? Мы уже добились хорошего успеха с isValidLogin, который возвращает Observable‹ Bool >, который использует combLatest.


person finneycanhelp    schedule 30.11.2015    source источник
comment
В качестве примечания, используя приведенный выше пример, можно также просто вернуть self.someString.map { !$0.isEmpty } в isValidSomeString. В контроллере представления привяжите someUIButton.rx_enabled к someViewModel.isValidSomeString().   -  person finneycanhelp    schedule 04.12.2015


Ответы (2)


Похоже, Action — идеальный инструмент для использования в этом случае. Вы захотите создать Action в своей ViewModel, пусть его наблюдаемое enabledIf будет результатом изменений в строке, и соедините это действие с вашим UIButton. Таким образом, кнопка будет активирована автоматически.

В вашей ViewModel вам нужно будет добавить это:

var buttonAction: CocoaAction {
    let hasString = self.someString.map { !$0.isEmpty }
    return CocoaAction(enabledIf: hasString) {
        // do something when button tapped
        return empty()
    }
}

И при привязке вашего ViewController к вашей ViewModel вы сделаете:

myButton.rx_action = viewModel.buttonAction
person fpillet    schedule 30.11.2015

Похоже, вам просто нужно map привязать someString к Obserable<Bool>, а затем привязать его к rx_enabled из UIButton Что-то вроде этого:

someViewModel.someString
             .asObservable()
             .map { (str) -> Bool in
                 return someViewModel.isValidSomeString(text)
             }
            .bindTo(someUIButton.rx_enabled)
            .addDisposableTo(disposeBag)  

но я думаю, что было бы проще, если бы у вас было Variable<Bool> в вашей модели просмотра

struct ViewModel {
....
    canLogIn = Variable(false)
}

В этом случае вы сможете привязать его к rx_enabled следующим образом:

  let userNameValidation = loginTextField
     .rx_text
     .map({!$0.isEmpty})
     .shareReplay(1)

  let passwordValidation = passwordTextField
     .rx_text
     .map({!$0.isEmpty})
     .shareReplay(1)

  let loginEnabled = combineLatest(userNameValidation, passWordValidation) { (username, password) in
     return username && password
  }

  loginEnabled
     .bindTo(loginViewModel.canlogIn)
     .addDisposableTo(disposeBag)

  loginViewModel.canlogIn
         .bindTo(loginButton.rx_enabled)
         .addDisposableTo(disposeBag)
person Serg Dort    schedule 20.12.2015