added test sample
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
parent
d36aa00932
commit
11ad080a69
@ -40,6 +40,7 @@
|
|||||||
EA3C3BB528996775000CA526 /* StoryboardInitable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3C3BB128996775000CA526 /* StoryboardInitable.swift */; };
|
EA3C3BB528996775000CA526 /* StoryboardInitable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3C3BB128996775000CA526 /* StoryboardInitable.swift */; };
|
||||||
EA3C3BB628996775000CA526 /* MenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3C3BB228996775000CA526 /* MenuViewController.swift */; };
|
EA3C3BB628996775000CA526 /* MenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3C3BB228996775000CA526 /* MenuViewController.swift */; };
|
||||||
EA3C3BB728996775000CA526 /* ToggleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3C3BB328996775000CA526 /* ToggleViewController.swift */; };
|
EA3C3BB728996775000CA526 /* ToggleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3C3BB328996775000CA526 /* ToggleViewController.swift */; };
|
||||||
|
EAB1D2C528A6B11D00DAE764 /* TestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D2C428A6B11D00DAE764 /* TestViewController.swift */; };
|
||||||
EAF7F07C2899698800B287F5 /* Components.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EAF7F07A2899698800B287F5 /* Components.storyboard */; };
|
EAF7F07C2899698800B287F5 /* Components.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = EAF7F07A2899698800B287F5 /* Components.storyboard */; };
|
||||||
EAF7F07D2899698800B287F5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EAF7F07B2899698800B287F5 /* Assets.xcassets */; };
|
EAF7F07D2899698800B287F5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EAF7F07B2899698800B287F5 /* Assets.xcassets */; };
|
||||||
EAF7F09C2899B92400B287F5 /* CheckboxViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F09B2899B92400B287F5 /* CheckboxViewController.swift */; };
|
EAF7F09C2899B92400B287F5 /* CheckboxViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F09B2899B92400B287F5 /* CheckboxViewController.swift */; };
|
||||||
@ -95,6 +96,7 @@
|
|||||||
EA3C3BBA289968A0000CA526 /* VDSTypographyTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSTypographyTokens.xcframework; path = ../SharedFrameworks/VDSTypographyTokens.xcframework; sourceTree = "<group>"; };
|
EA3C3BBA289968A0000CA526 /* VDSTypographyTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSTypographyTokens.xcframework; path = ../SharedFrameworks/VDSTypographyTokens.xcframework; sourceTree = "<group>"; };
|
||||||
EA3C3BBB289968A0000CA526 /* VDSFormControlsTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSFormControlsTokens.xcframework; path = ../SharedFrameworks/VDSFormControlsTokens.xcframework; sourceTree = "<group>"; };
|
EA3C3BBB289968A0000CA526 /* VDSFormControlsTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSFormControlsTokens.xcframework; path = ../SharedFrameworks/VDSFormControlsTokens.xcframework; sourceTree = "<group>"; };
|
||||||
EA3C3BC3289968B1000CA526 /* VDS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = VDS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
EA3C3BC3289968B1000CA526 /* VDS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = VDS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
EAB1D2C428A6B11D00DAE764 /* TestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestViewController.swift; sourceTree = "<group>"; };
|
||||||
EAF7F07A2899698800B287F5 /* Components.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Components.storyboard; sourceTree = "<group>"; };
|
EAF7F07A2899698800B287F5 /* Components.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Components.storyboard; sourceTree = "<group>"; };
|
||||||
EAF7F07B2899698800B287F5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
EAF7F07B2899698800B287F5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
EAF7F09B2899B92400B287F5 /* CheckboxViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxViewController.swift; sourceTree = "<group>"; };
|
EAF7F09B2899B92400B287F5 /* CheckboxViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxViewController.swift; sourceTree = "<group>"; };
|
||||||
@ -207,6 +209,7 @@
|
|||||||
EA3C3BB228996775000CA526 /* MenuViewController.swift */,
|
EA3C3BB228996775000CA526 /* MenuViewController.swift */,
|
||||||
EAF7F11928A14A0E00B287F5 /* RadioButtonViewController.swift */,
|
EAF7F11928A14A0E00B287F5 /* RadioButtonViewController.swift */,
|
||||||
EA3C3BB328996775000CA526 /* ToggleViewController.swift */,
|
EA3C3BB328996775000CA526 /* ToggleViewController.swift */,
|
||||||
|
EAB1D2C428A6B11D00DAE764 /* TestViewController.swift */,
|
||||||
);
|
);
|
||||||
path = ViewControllers;
|
path = ViewControllers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -358,6 +361,7 @@
|
|||||||
EAF7F11A28A14A0E00B287F5 /* RadioButtonViewController.swift in Sources */,
|
EAF7F11A28A14A0E00B287F5 /* RadioButtonViewController.swift in Sources */,
|
||||||
EA3C3B9F289966EF000CA526 /* SceneDelegate.swift in Sources */,
|
EA3C3B9F289966EF000CA526 /* SceneDelegate.swift in Sources */,
|
||||||
EA3C3BB428996775000CA526 /* PickerBase.swift in Sources */,
|
EA3C3BB428996775000CA526 /* PickerBase.swift in Sources */,
|
||||||
|
EAB1D2C528A6B11D00DAE764 /* TestViewController.swift in Sources */,
|
||||||
EAF7F09C2899B92400B287F5 /* CheckboxViewController.swift in Sources */,
|
EAF7F09C2899B92400B287F5 /* CheckboxViewController.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|||||||
175
VDSSample/ViewControllers/TestViewController.swift
Normal file
175
VDSSample/ViewControllers/TestViewController.swift
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
//
|
||||||
|
// TestViewController.swift
|
||||||
|
// VDSSample
|
||||||
|
//
|
||||||
|
// Created by Matt Bruce on 8/12/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
class User: ObservableObject {
|
||||||
|
var firstName: String
|
||||||
|
var lastName: String
|
||||||
|
|
||||||
|
init(firstName: String, lastName: String) {
|
||||||
|
self.firstName = firstName
|
||||||
|
self.lastName = lastName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TextFieldCell: UIView {
|
||||||
|
let firstNameTextField = TextField()
|
||||||
|
let lastNameTextField = TextField()
|
||||||
|
var subject: CurrentValueSubject<User, Never>
|
||||||
|
private var subscriptions = Set<AnyCancellable>()
|
||||||
|
var model: User
|
||||||
|
|
||||||
|
private func send() {
|
||||||
|
subject.send(model)
|
||||||
|
}
|
||||||
|
|
||||||
|
init(subject: CurrentValueSubject<User, Never>) {
|
||||||
|
self.model = subject.value
|
||||||
|
self.subject = subject
|
||||||
|
super.init(frame: .zero)
|
||||||
|
|
||||||
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
firstNameTextField.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
lastNameTextField.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
||||||
|
addSubview(firstNameTextField)
|
||||||
|
addSubview(lastNameTextField)
|
||||||
|
print("\(model.firstName) \(model.lastName)")
|
||||||
|
|
||||||
|
firstNameTextField.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
|
||||||
|
firstNameTextField.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
|
||||||
|
firstNameTextField.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
||||||
|
firstNameTextField.heightAnchor.constraint(equalToConstant: 50).isActive = true
|
||||||
|
|
||||||
|
lastNameTextField.topAnchor.constraint(equalTo: firstNameTextField.bottomAnchor, constant: 20).isActive = true
|
||||||
|
lastNameTextField.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
|
||||||
|
lastNameTextField.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
|
||||||
|
lastNameTextField.heightAnchor.constraint(equalToConstant: 50).isActive = true
|
||||||
|
lastNameTextField.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
|
||||||
|
|
||||||
|
//add the logic
|
||||||
|
let firstNameSubject = CurrentValueSubject<String, Never>(model.firstName)
|
||||||
|
firstNameTextField.createBinding(with: firstNameSubject, storeIn: &subscriptions)
|
||||||
|
firstNameSubject.assign(to: \.model.firstName, on: self).store(in: &subscriptions)
|
||||||
|
firstNameSubject.sink {[weak self] value in
|
||||||
|
self?.send()
|
||||||
|
}.store(in: &subscriptions)
|
||||||
|
|
||||||
|
let lastNameSubject = CurrentValueSubject<String, Never>(model.lastName)
|
||||||
|
lastNameTextField.createBinding(with: lastNameSubject, storeIn: &subscriptions)
|
||||||
|
lastNameSubject.assign(to: \.model.lastName, on: self).store(in: &subscriptions)
|
||||||
|
lastNameSubject.sink {[weak self] value in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.send()
|
||||||
|
}.store(in: &subscriptions)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@objcMembers class TestViewController: UIViewController, Initable {
|
||||||
|
var user = User(firstName: "Joe", lastName: "User")
|
||||||
|
var nameTextField: TextFieldCell!
|
||||||
|
var button = UIButton()
|
||||||
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
required init() {
|
||||||
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
view.backgroundColor = .white
|
||||||
|
|
||||||
|
let subject = CurrentValueSubject<User, Never>(user)
|
||||||
|
subject.assign(to: \.user, on: self).store(in: &cancellables)
|
||||||
|
nameTextField = TextFieldCell(subject: subject)
|
||||||
|
|
||||||
|
button.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
||||||
|
view.addSubview(nameTextField)
|
||||||
|
view.addSubview(button)
|
||||||
|
nameTextField.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20).isActive = true
|
||||||
|
nameTextField.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20).isActive = true
|
||||||
|
nameTextField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20).isActive = true
|
||||||
|
button.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20).isActive = true
|
||||||
|
button.topAnchor.constraint(equalTo: nameTextField.bottomAnchor, constant: 20).isActive = true
|
||||||
|
button.heightAnchor.constraint(equalToConstant: 50).isActive = true
|
||||||
|
button.widthAnchor.constraint(equalToConstant: 100).isActive = true
|
||||||
|
button.backgroundColor = .blue
|
||||||
|
button.setTitle("Print", for: .normal)
|
||||||
|
|
||||||
|
button.addAction(UIAction(title: "", handler: { [weak self] action in
|
||||||
|
if let user = self?.user {
|
||||||
|
print("\(user.firstName) \(user.lastName)")
|
||||||
|
}
|
||||||
|
}), for: .touchUpInside)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension UITextField {
|
||||||
|
|
||||||
|
func textPublisher() -> AnyPublisher<String, Never> {
|
||||||
|
NotificationCenter.default
|
||||||
|
.publisher(for: UITextField.textDidChangeNotification, object: self)
|
||||||
|
.compactMap({ ($0.object as? UITextField)?.text })
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
|
func createBinding(with subject: CurrentValueSubject<String, Never>,
|
||||||
|
storeIn subscriptions: inout Set<AnyCancellable>) {
|
||||||
|
|
||||||
|
subject.sink { [weak self] (value) in
|
||||||
|
if value != self?.text {
|
||||||
|
self?.text = value
|
||||||
|
}
|
||||||
|
}.store(in: &subscriptions)
|
||||||
|
|
||||||
|
self.textPublisher().sink { (value) in
|
||||||
|
if value != subject.value {
|
||||||
|
subject.send(value)
|
||||||
|
}
|
||||||
|
}.store(in: &subscriptions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TextField: UITextField {
|
||||||
|
var textPadding = UIEdgeInsets(
|
||||||
|
top: 10,
|
||||||
|
left: 20,
|
||||||
|
bottom: 10,
|
||||||
|
right: 20
|
||||||
|
)
|
||||||
|
|
||||||
|
override func textRect(forBounds bounds: CGRect) -> CGRect {
|
||||||
|
layer.borderColor = UIColor.black.cgColor
|
||||||
|
layer.borderWidth = 1
|
||||||
|
let rect = super.textRect(forBounds: bounds)
|
||||||
|
return rect.inset(by: textPadding)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func editingRect(forBounds bounds: CGRect) -> CGRect {
|
||||||
|
layer.borderColor = UIColor.black.cgColor
|
||||||
|
layer.borderWidth = 1
|
||||||
|
let rect = super.editingRect(forBounds: bounds)
|
||||||
|
return rect.inset(by: textPadding)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user