Skip to content

Instantly share code, notes, and snippets.

@moderateepheezy
Created July 21, 2020 23:27
Show Gist options
  • Select an option

  • Save moderateepheezy/7cecc38cbc78d3ddb56ffa13c7c7d668 to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown

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

@moderateepheezy

moderateepheezy commented Mar 26, 2021

Copy link
Copy Markdown
Author

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
Copy Markdown

Appreciated once again!

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