| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- //
- // Operators.swift
- // O2Platform
- //
- // Created by FancyLou on 2018/7/23.
- // Copyright © 2018 zoneland. All rights reserved.
- //
- import RxSwift
- import RxCocoa
- import UIKit
- // Two way binding operator between control property and variable, that's all it takes {
- infix operator <-> : DefaultPrecedence
- func nonMarkedText(_ textInput: UITextInput) -> String? {
- let start = textInput.beginningOfDocument
- let end = textInput.endOfDocument
-
- guard let rangeAll = textInput.textRange(from: start, to: end),
- let text = textInput.text(in: rangeAll) else {
- return nil
- }
-
- guard let markedTextRange = textInput.markedTextRange else {
- return text
- }
-
- guard let startRange = textInput.textRange(from: start, to: markedTextRange.start),
- let endRange = textInput.textRange(from: markedTextRange.end, to: end) else {
- return text
- }
-
- return (textInput.text(in: startRange) ?? "") + (textInput.text(in: endRange) ?? "")
- }
- func <-> <Base: UITextInput>(textInput: TextInput<Base>, variable: Variable<String>) -> Disposable {
- let bindToUIDisposable = variable.asObservable()
- .bind(to: textInput.text)
- let bindToVariable = textInput.text
- .subscribe(onNext: { [weak base = textInput.base] n in
- guard let base = base else {
- return
- }
-
- let nonMarkedTextValue = nonMarkedText(base)
-
- /**
- In some cases `textInput.textRangeFromPosition(start, toPosition: end)` will return nil even though the underlying
- value is not nil. This appears to be an Apple bug. If it's not, and we are doing something wrong, please let us know.
- The can be reproed easily if replace bottom code with
-
- if nonMarkedTextValue != variable.value {
- variable.value = nonMarkedTextValue ?? ""
- }
-
- and you hit "Done" button on keyboard.
- */
- if let nonMarkedTextValue = nonMarkedTextValue, nonMarkedTextValue != variable.value {
- variable.value = nonMarkedTextValue
- }
- }, onCompleted: {
- bindToUIDisposable.dispose()
- })
-
- return Disposables.create(bindToUIDisposable, bindToVariable)
- }
- func <-> <T>(property: ControlProperty<T>, variable: Variable<T>) -> Disposable {
- if T.self == String.self {
- #if DEBUG
- fatalError("It is ok to delete this message, but this is here to warn that you are maybe trying to bind to some `rx.text` property directly to variable.\n" +
- "That will usually work ok, but for some languages that use IME, that simplistic method could cause unexpected issues because it will return intermediate results while text is being inputed.\n" +
- "REMEDY: Just use `textField <-> variable` instead of `textField.rx.text <-> variable`.\n" +
- "Find out more here: https://github.com/ReactiveX/RxSwift/issues/649\n"
- )
- #endif
- }
-
- let bindToUIDisposable = variable.asObservable()
- .bind(to: property)
- let bindToVariable = property
- .subscribe(onNext: { n in
- variable.value = n
- }, onCompleted: {
- bindToUIDisposable.dispose()
- })
-
- return Disposables.create(bindToUIDisposable, bindToVariable)
- }
|