Skip to content

Instantly share code, notes, and snippets.

@ShoMasegi
Last active November 26, 2018 04:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ShoMasegi/60edd15c80b6ba77e80da3f0af09e3f8 to your computer and use it in GitHub Desktop.
Save ShoMasegi/60edd15c80b6ba77e80da3f0af09e3f8 to your computer and use it in GitHub Desktop.
CustomView + RxSwift
import RxCocoa
import RxSwift
import UIKit
final class FilledTextFieldDelegateProxy:
DelegateProxy<FilledTextField, FilledTextFieldDelegate>,
FilledTextFieldDelegate,
DelegateProxyType {
init(filledTextField: FilledTextField) {
super.init(parentObject: filledTextField, delegateProxy: FilledTextFieldDelegateProxy.self)
}
static func registerKnownImplementations() {
register { FilledTextFieldDelegateProxy(filledTextField: $0) }
}
static func currentDelegate(for object: FilledTextField) -> FilledTextFieldDelegate? {
return object.delegate
}
static func setCurrentDelegate(_ delegate: FilledTextFieldDelegate?, to object: FilledTextField) {
object.delegate = delegate
}
}
extension Reactive where Base: FilledTextField {
var delegate: DelegateProxy<FilledTextField, FilledTextFieldDelegate> {
return FilledTextFieldDelegateProxy.proxy(for: base)
}
var didEndFocusing: ControlEvent<Void> {
let source = delegate.methodInvoked(#selector(FilledTextFieldDelegate.filledTextFieldDidEndFocusing(_:)))
.map { _ in }
return ControlEvent(events: source)
}
var textDidChange: ControlProperty<String?> {
let source = delegate.methodInvoked(#selector(FilledTextFieldDelegate.filledTextField(_:textFieldTextDidChange:)))
.map { params -> String? in
let text = try castOrThrow(String.self, params[1])
return text
}
let bindingObserver = Binder(base) { (filledTextField, text: String?) in
filledTextField.textField.text = text
}
return ControlProperty(values: source, valueSink: bindingObserver)
}
var didReturn: ControlEvent<Void> {
let source = delegate.methodInvoked(#selector(FilledTextFieldDelegate.filledTextFieldDidReturn(_:)))
.map { _ in }
return ControlEvent(events: source)
}
var didBeginFocusing: ControlEvent<Void> {
let source = delegate.methodInvoked(#selector(FilledTextFieldDelegate.filledTextFieldDidBeginFocusing(_:)))
.map { _ in }
return ControlEvent(events: source)
}
}
func castOrThrow<T>(_ resultType: T.Type, _ object: Any) throws -> T {
guard let returnValue = object as? T else {
throw RxCocoaError.castingError(object: object, targetType: resultType)
}
return returnValue
}
import UIKit
import RxCocoa
import RxSwift
import SnapKit
@objc protocol FilledTextFieldDelegate: class {
@objc optional func filledTextFieldDidBeginFocusing(_ textField: FilledTextField)
@objc optional func filledTextFieldDidEndFocusing(_ textField: FilledTextField)
@objc optional func filledTextField(_ filledTextField: FilledTextField, textFieldTextDidChange _: String?)
@objc optional func filledTextFieldDidReturn(_ filledTextField: FilledTextField)
}
class FilledTextField: UIView {
weak var delegate: FilledTextFieldDelegate?
var defaultPlaceholderText = "Placeholder" {
didSet {
placeholderLabel.text = defaultPlaceholderText
}
}
enum Style {
case `default`, noImage
}
init(frame: CGRect, style: Style = .default) {
self.style = style
super.init(frame: frame)
setupSubviews()
}
required init?(coder _: NSCoder) { fatalError() }
private let style: Style
private let bag = DisposeBag()
lazy var iconImageView: UIImageView = {
let view = UIImageView()
view.clipsToBounds = true
view.contentMode = .scaleAspectFit
return view
}()
lazy var textField: UITextField = {
let view = UITextField()
view.font = UIFont.systemFont(ofSize: 18)
view.textColor = .white
view.backgroundColor = .clear
view.delegate = self
view.rx.controlEvent([.editingChanged]).subscribe(onNext: { [unowned self, view] in
self.delegate?.filledTextField?(self, textFieldTextDidChange: view.text)
}).disposed(by: bag)
return view
}()
private lazy var backgroundView: UIView = {
let view = UIView()
view.layer.cornerRadius = 4
view.backgroundColor = UIColor(hex: "27272F")
let tap = UITapGestureRecognizer()
tap.rx.event.subscribe(onNext: { [unowned self] _ in
self.textField.becomeFirstResponder()
}).disposed(by: bag)
view.addGestureRecognizer(tap)
return view
}()
private lazy var placeholderLabel: UILabel = {
let label = UILabel()
label.text = defaultPlaceholderText
label.font = UIFont.systemFont(ofSize: 18)
label.textColor = UIColor.primary_400
return label
}()
private func setupSubviews() {
addSubview(backgroundView)
[placeholderLabel, textField].forEach(backgroundView.addSubview)
if style == .default { backgroundView.addSubview(iconImageView) }
backgroundView.snp.makeConstraints {
$0.edges.equalToSuperview()
}
if style == .default {
iconImageView.snp.makeConstraints {
$0.centerY.equalToSuperview()
$0.height.width.equalTo(24)
$0.top.left.bottom.equalToSuperview().inset(16)
}
}
textField.snp.makeConstraints {
$0.centerY.equalToSuperview()
$0.left.equalToSuperview().inset(style == .default ? 56 : 20)
$0.right.equalToSuperview().inset(16)
$0.top.bottom.equalToSuperview().inset(8)
}
placeholderLabel.snp.makeConstraints {
$0.edges.equalTo(textField)
}
}
private func changeBackgroundColor(isFocused: Bool) {
backgroundView.backgroundColor = isFocused ? UIColor(hex: "43434C") : UIColor(hex: "27272F")
}
}
extension FilledTextField: UITextFieldDelegate {
func textField(_: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let isEmpty = range.location == 0 && string.isEmpty
if isEmpty {
placeholderLabel.text = defaultPlaceholderText
}
placeholderLabel.isHidden = !isEmpty
return true
}
func textFieldDidBeginEditing(_ textField: UITextField) {
let isHidden = textField.text?.isEmpty == false
placeholderLabel.isHidden = isHidden
self.delegate?.filledTextFieldDidBeginFocusing?(self)
changeBackgroundColor(isFocused: true)
}
func textFieldShouldClear(_: UITextField) -> Bool {
placeholderLabel.isHidden = false
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
let isEmpty = textField.text?.isEmpty ?? false
placeholderLabel.isHidden = !isEmpty
changeBackgroundColor(isFocused: !isEmpty)
placeholderLabel.text = defaultPlaceholderText
delegate?.filledTextFieldDidEndFocusing?(self)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if textField == self.textField {
textField.resignFirstResponder()
delegate?.filledTextFieldDidReturn?(self)
return false
}
return true
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment