-
[iOS] UITextField를 RxDelegateProxy를 이용하여 사용해보자스위프트 2023. 7. 29. 13:27
TextField에서 엔터를 쳤을 때 동작을 하고 싶은데..
생각보다 RxSwift에서 UITextField에 대한 지원이 아쉬웠습니다.
// RxCocoa에 있는 UITextField+Rx extension Reactive where Base: UITextField { /// Reactive wrapper for `text` property. public var text: ControlProperty<String?> { value } /// Reactive wrapper for `text` property. public var value: ControlProperty<String?> { return base.rx.controlPropertyWithDefaultEvents( getter: { textField in textField.text }, setter: { textField, value in // This check is important because setting text value always clears control state // including marked text selection which is important for proper input // when IME input method is used. if textField.text != value { textField.text = value } } ) } /// Bindable sink for `attributedText` property. public var attributedText: ControlProperty<NSAttributedString?> { return base.rx.controlPropertyWithDefaultEvents( getter: { textField in textField.attributedText }, setter: { textField, value in // This check is important because setting text value always clears control state // including marked text selection which is important for proper input // when IME input method is used. if textField.attributedText != value { textField.attributedText = value } } ) } }
UITextFieldDelegate를 이용한 동작
extension SomeViewController: UITextFieldDelegate { func textFieldShouldReturn(_ textField: UITextField) -> Bool { if textField == nameTextField { // Do something } else if textField == urlTextField { // Do something } else if textField == descTextField { // Do something } return true } }
Delegate를 이용해서 구현하면 저런 식으로 구현할 수 있습니다.
TextField가 하나만 존재하면 괜찮지만 개수가 늘어나면 동일하게 if-else (또는 switch) 가 늘어납니다.
뭔가 아쉽습니다. 😢
RxDelegateProxy를 활용하자
Delegate에 있는 동작을 RxDelegateProxy로 추가할 수 있습니다.
extension UITextField: HasDelegate { public typealias Delegate = UITextFieldDelegate }
먼저 UITextField가 HasDelegate를 준수하도록 만듭니다.
open class RxTextFieldDelegateProxy: DelegateProxy<UITextField, UITextFieldDelegate>, DelegateProxyType { public weak private(set) var textField: UITextField? public init(textField: ParentObject) { self.textField = textField super.init(parentObject: textField, delegateProxy: RxTextFieldDelegateProxy.self) } public static func registerKnownImplementations() { self.register { RxTextFieldDelegateProxy(textField: $0) } } private var _returnKeyDidTapPublishSubject: PublishSubject<()>? internal var returnKeyDidTapPublishSubject: PublishSubject<()> { if let subject = _returnKeyDidTapPublishSubject { return subject } let subject = PublishSubject<()>() _returnKeyDidTapPublishSubject = subject return subject } deinit { if let subject = _returnKeyDidTapPublishSubject { subject.on(.completed) } } }
다음으로 DelegateProxy 를 준수하여 필요한 동작을 추가합니다.
그리고 textFieldShouldReturn 를 활용하기 위한 PublishSubject인 returnKeyDidTapPublishSubject 를 추가합니다.
extension RxTextFieldDelegateProxy: UITextFieldDelegate { public func textFieldShouldReturn(_ textField: UITextField) -> Bool { if let subject = _returnKeyDidTapPublishSubject { subject.on(.next(())) } return self._forwardToDelegate?.textFieldShouldReturn(textField) ?? true } }
추가한 PublishSubject에 textFieldShouldReturn 이 호출될 때 onNext를 보냅니다.
public extension Reactive where Base: UITextField { var returnKeyDidTap: ControlEvent<Void> { let source = RxTextFieldDelegateProxy.proxy(for: base).returnKeyDidTapPublishSubject return ControlEvent(events: source) } }
마지막으로 ControlEvent를 만들어 사용해 줍시다.
활용
nameTextField.rx.returnKeyDidTap .withUnretained(self.urlTextField) .subscribe(onNext: { nextTextField, _ in nextTextField.becomeFirstResponder() }) .disposed(by: disposeBag) urlTextField.rx.returnKeyDidTap .withUnretained(self.descTextField) .subscribe(onNext: { nextTextField, _ in nextTextField.becomeFirstResponder() }) .disposed(by: disposeBag)
이런 식으로 사용하면 다음 TextField에 포커싱이 가도록 구현할 수 있습니다.
'스위프트' 카테고리의 다른 글
[iOS] ViewController Life Cycle (+ ViewIsAppearing) (0) 2023.09.02 [iOS] RxSwift를 이용하여 키보드 컨트롤하기 (NotificationCenter) (0) 2023.08.22 [Swift] 티스토리 블로그를 자동으로 Github에 업데이트 (Git Actions) (6) 2023.08.07 [iOS] Life Cycle (App, Scene 생명 주기) (0) 2023.07.30 RxSwift KeyBoard (RxKeyBoard) 간단한 사용법 (0) 2021.10.07