Skip to content

Instantly share code, notes, and snippets.

@moderateepheezy
Created July 21, 2020 23:27
Show Gist options
  • Save moderateepheezy/7cecc38cbc78d3ddb56ffa13c7c7d668 to your computer and use it in GitHub Desktop.
Save moderateepheezy/7cecc38cbc78d3ddb56ffa13c7c7d668 to your computer and use it in GitHub Desktop.
A drop down textfield with RxSwift
import UIKit
import RxSwift
import RxCocoa
final class DropdownTextField: CustomTextField, UIPickerViewDataSource, UIPickerViewDelegate {
var onDoneClicked: BehaviorRelay<Void?> = BehaviorRelay(value: nil)
var source: [String] = []
let selectedValue: BehaviorRelay<String?> = BehaviorRelay(value: nil)
let hasValidData = BehaviorRelay(value: false)
let hasValueSelected = BehaviorRelay(value: false)
private let picker = UIPickerView()
private let disposeBag = DisposeBag()
override func setup() {
super.setup()
setupViewHierarchy()
setupBehavior()
}
private let iconImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = Asset.Common.chevronDown.image
imageView.contentMode = .scaleAspectFit
return imageView.layoutable()
}()
private let activityIndicator = UIActivityIndicatorView(style: .gray).layoutable()
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if !source.isEmpty {
text = source[row]
hasValueSelected.accept(true)
selectedValue.accept(text)
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return source[row]
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return source.count
}
private func setupViewHierarchy() {
addSubviews([iconImageView, activityIndicator])
iconImageView.constraintCenterToSuperview(axis: [.vertical], withConstant: .zero)
iconImageView.constraintToConstant(CGSize(width: 13, height: 13))
iconImageView.rightAnchor.constraint(equalTo: rightAnchor, constant: -18).isActive = true
activityIndicator.constraintCenter(to: iconImageView)
}
private func setupBehavior() {
picker.delegate = self
inputView = picker
let flexBarButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let doneBarButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismissInputView))
keyboardToolbar.items = [doneBarButton, flexBarButton]
self.inputAccessoryView = keyboardToolbar
hasValidData
.observeOn(MainScheduler.instance)
.subscribe(onNext: { [weak self] hasData in
self?.iconImageView.isHidden = !hasData
self?.activityIndicator.isHidden = hasData
hasData ? self?.activityIndicator.stopAnimating() : self?.activityIndicator.startAnimating()
})
.disposed(by: disposeBag)
}
@objc private func dismissInputView() {
self.onDoneClicked.accept(())
self.endEditing(true)
}
}
@vincent-peng
Copy link

Thanks for sharing!
Do you mind to tell what's in CustomTextField please?

@moderateepheezy
Copy link
Author

moderateepheezy commented Mar 26, 2021

Welcome!

So CustomTextField can be any of your custom textfields, or default UITextField in my case it's the following.

class CustomTextField: UITextField {
	
	var textInset: UIEdgeInsets { .zero }
	
	var textPlaceholderColor: UIColor = .textPlaceholderColor
	
	override var placeholder: String? {
		didSet {
			attributedPlaceholder = NSAttributedString(string: placeholder ?? "", attributes:  [NSAttributedString.Key.foregroundColor: textPlaceholderColor, NSAttributedString.Key.font: UIFont.medium(ofSize: 16)])
		}
	}
	
	override init(frame: CGRect) {
		super.init(frame: frame)
 		setup()
	}
	
	required init?(coder: NSCoder) {
		fatalError()
	}
	
	override func textRect(forBounds bounds: CGRect) -> CGRect {
		return bounds.inset(by: textInset)
	}
	
	override func editingRect(forBounds bounds: CGRect) -> CGRect {
		return bounds.inset(by: textInset)
	}
	
	func setup() {
		autocorrectionType = .no
		font = .medium(ofSize: 18)
	}
}

@vincent-peng
Copy link

Appreciated once again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment