Create a done button for RxPickerViewAttributedStringAdapter

28 views Asked by At

self.genderSource = RxPickerViewAttributedStringAdapter<[[DKProfileOption]]>.init(components:[]) { dataSource, pickerView, components in return 1 } numberOfRowsInComponent: { [weak self] dataSource, pickerView, components, component in return self?.genderDetail.value.count ?? 0 } attributedTitleForRow: { [weak self] dataSource, pickerView, components, row, component in let title:String = self?.genderDetail.value[row].title ?? "" let attr_title = NSAttributedString(string: title, attributes:[.font:DKAppFont.Medium.font(size: 13) ?? UIFont.systemFont(ofSize:13)]) return attr_title }

This is my viewModel codes. I don't have done button but I want add done button inside. RxSwift codes also.

My viewCodes is here.

if let genderSource = castedViewModel.genderSource { castedViewModel .gender .bind(to: genderPicker.rx.items(adapter: genderSource)) .disposed(by: bag) } self.genderField?.inputView = genderPicker

I want add done button inside.

1

There are 1 answers

0
Daniel T. On

I'm going to assume you want something like this:

extension UITextField {
    func setUpWithPicker<T>(elements: Observable<[T]>, description: @escaping (T) -> String) -> Observable<T> {
        precondition(inputAccessoryView == nil && inputView == nil, "The text view is already set up")
        let pickerView = UIPickerView()
        let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: nil, action: nil)
        let toolBar = {
            let result = UIToolbar()
            let flexibleSapce = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
            result.frame.size.height = 44
            result.autoresizingMask = [.flexibleWidth]
            result.items = [flexibleSapce, doneButton]
            return result
        }()

        _ = elements
            .take(until: rx.deallocating)
            .bind(to: pickerView.rx.itemAttributedTitles) { _, element in
                NSAttributedString(string: description(element), attributes: [.font: UIFont.systemFont(ofSize: 13)])
            }

        _ = doneButton.rx.tap
            .take(until: rx.deallocating)
            .bind(onNext: { [weak self] in
                self?.resignFirstResponder()
            })

        inputAccessoryView = toolBar
        inputView = pickerView

        return doneButton.rx.tap
            .withLatestFrom(pickerView.rx.modelSelected(T.self))
            .compactMap { $0.first }
    }
}

Just copy/paste the above into your code. You can use it like this:

let elements = [DKProfileOption(title: "One"), DKProfileOption(title: "Two"), DKProfileOption(title: "Three")]
textField.setUpWithPicker(elements: .just(elements), description: { $0.title })
    .bind(onNext: { response in
        print(response)
    })
    .disposed(by: disposeBag)