Skip to content

Commit edaad3b

Browse files
Oleksandr ZarochintseverichoracekOleksandr Zarochintsev
authored
Add case with TextField (#31)
* Add text field case * Update CHANGELOG.md * Update CHANGELOG.md Co-authored-by: Eric Horacek <[email protected]> * Update Example/EpoxyExample/ViewControllers/TextFieldViewController.swift Co-authored-by: Eric Horacek <[email protected]> * Update Example/EpoxyExample/ViewControllers/TextFieldViewController.swift Co-authored-by: Eric Horacek <[email protected]> * Update TextFieldViewController.swift * Update Example.swift * Run the linter Co-authored-by: Eric Horacek <[email protected]> Co-authored-by: Oleksandr Zarochintsev <[email protected]>
1 parent 4a54d4b commit edaad3b

File tree

6 files changed

+146
-0
lines changed

6 files changed

+146
-0
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased](https://github.com/airbnb/epoxy-ios/compare/0.3.0...HEAD)
88

9+
### Added
10+
- Added an example with text field to show how can we use `avoidsKeyboard` feature
11+
912
## [0.3.0](https://github.com/airbnb/epoxy-ios/compare/0.2.0...0.3.0) - 2021-04-23
1013

1114
### Added

Example/EpoxyExample.xcodeproj/project.pbxproj

+8
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
25FEB79225AE431100F8EFBD /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25FEB79125AE431100F8EFBD /* MainViewController.swift */; };
2222
2E8B007623F47E7E00D82A31 /* CustomSizingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E8B007523F47E7E00D82A31 /* CustomSizingView.swift */; };
2323
2E8B007823F4800000D82A31 /* CustomSelfSizingContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E8B007723F4800000D82A31 /* CustomSelfSizingContentViewController.swift */; };
24+
A5AD02A72637CBF9007261BC /* TextFieldRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5AD02A62637CBF9007261BC /* TextFieldRow.swift */; };
25+
A5AD02AA2637CE5E007261BC /* TextFieldViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5AD02A92637CE5E007261BC /* TextFieldViewController.swift */; };
2426
A61AFF592602B86E005356A8 /* Example.swift in Sources */ = {isa = PBXBuildFile; fileRef = A61AFF582602B86E005356A8 /* Example.swift */; };
2527
A61AFF5C2602B8D7005356A8 /* ReadmeExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = A61AFF5B2602B8D7005356A8 /* ReadmeExample.swift */; };
2628
A61AFF5F2602B99E005356A8 /* TapMeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A61AFF5E2602B99E005356A8 /* TapMeViewController.swift */; };
@@ -56,6 +58,8 @@
5658
25FEB79125AE431100F8EFBD /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
5759
2E8B007523F47E7E00D82A31 /* CustomSizingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSizingView.swift; sourceTree = "<group>"; };
5860
2E8B007723F4800000D82A31 /* CustomSelfSizingContentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomSelfSizingContentViewController.swift; sourceTree = "<group>"; };
61+
A5AD02A62637CBF9007261BC /* TextFieldRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldRow.swift; sourceTree = "<group>"; };
62+
A5AD02A92637CE5E007261BC /* TextFieldViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldViewController.swift; sourceTree = "<group>"; };
5963
A61AFF582602B86E005356A8 /* Example.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Example.swift; sourceTree = "<group>"; };
6064
A61AFF5B2602B8D7005356A8 /* ReadmeExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadmeExample.swift; sourceTree = "<group>"; };
6165
A61AFF5E2602B99E005356A8 /* TapMeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TapMeViewController.swift; sourceTree = "<group>"; };
@@ -136,6 +140,7 @@
136140
25FEB79125AE431100F8EFBD /* MainViewController.swift */,
137141
2518441825B8E35A000B801F /* FlowLayoutViewController.swift */,
138142
A667554325D3028D00AC4FC8 /* CardStackViewController.swift */,
143+
A5AD02A92637CE5E007261BC /* TextFieldViewController.swift */,
139144
A61AFF612602BA20005356A8 /* Helpers */,
140145
);
141146
path = ViewControllers;
@@ -145,6 +150,7 @@
145150
isa = PBXGroup;
146151
children = (
147152
A6F0928A25B9E983007D902B /* TextRow.swift */,
153+
A5AD02A62637CBF9007261BC /* TextFieldRow.swift */,
148154
2E8B007523F47E7E00D82A31 /* CustomSizingView.swift */,
149155
25B6766125AE898B00C00B20 /* ImageRow.swift */,
150156
25B6766725AFA67100C00B20 /* ButtonRow.swift */,
@@ -285,6 +291,7 @@
285291
files = (
286292
A633B24625B6507A0095E464 /* ImageMarquee.swift in Sources */,
287293
25627B95232ABF0F00D7327A /* CompositionalLayoutViewController.swift in Sources */,
294+
A5AD02A72637CBF9007261BC /* TextFieldRow.swift in Sources */,
288295
BACF3E8C23DBB8DC0001CCD1 /* ShuffleViewController.swift in Sources */,
289296
25627B93232ABF0F00D7327A /* AppDelegate.swift in Sources */,
290297
25B6766825AFA67100C00B20 /* ButtonRow.swift in Sources */,
@@ -310,6 +317,7 @@
310317
2518441925B8E35A000B801F /* FlowLayoutViewController.swift in Sources */,
311318
259863A225AE47710065024B /* UICollectionViewCompositionalLayout+List.swift in Sources */,
312319
A667554125D2FEC400AC4FC8 /* CardContainer.swift in Sources */,
320+
A5AD02AA2637CE5E007261BC /* TextFieldViewController.swift in Sources */,
313321
);
314322
runOnlyForDeploymentPostprocessing = 0;
315323
};

Example/EpoxyExample/Data/Example.swift

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ enum Example: CaseIterable {
1010
case flowLayout
1111
case shuffle
1212
case customSelfSizing
13+
case textField
1314

1415
// MARK: Internal
1516

@@ -29,6 +30,8 @@ enum Example: CaseIterable {
2930
return "Flow Layout demo"
3031
case .cardStack:
3132
return "Card Stack"
33+
case .textField:
34+
return "Text Field"
3235
}
3336
}
3437

@@ -48,6 +51,8 @@ enum Example: CaseIterable {
4851
return "A CollectionView with a UICollectionViewFlowLayout"
4952
case .cardStack:
5053
return "A CollectionView with BarStackView items that have a card drawn around each stack"
54+
case .textField:
55+
return "An example that combines collections, bars, and text field with keyboard avoidance"
5156
}
5257
}
5358
}

Example/EpoxyExample/ViewControllers/MainViewController.swift

+2
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ final class MainViewController: NavigationController {
9696
viewController = FlowLayoutViewController()
9797
case .cardStack:
9898
viewController = CardStackViewController()
99+
case .textField:
100+
viewController = TextFieldViewController()
99101
}
100102
viewController.title = example.title
101103
return viewController
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Created by oleksandr_zarochintsev on 4/26/21.
2+
// Copyright © 2021 Airbnb Inc. All rights reserved.
3+
4+
import Epoxy
5+
import UIKit
6+
7+
final class TextFieldViewController: CollectionViewController {
8+
9+
// MARK: Lifecycle
10+
11+
init() {
12+
super.init(layout: UICollectionViewCompositionalLayout.listNoDividers)
13+
setSections([.init(items: [textFieldRowItem])], animated: true)
14+
}
15+
16+
// MARK: Internal
17+
18+
override func viewDidLoad() {
19+
super.viewDidLoad()
20+
bottomBarInstaller.install()
21+
}
22+
23+
// MARK: Private
24+
25+
private enum DataID {
26+
case username
27+
case button
28+
}
29+
30+
private lazy var bottomBarInstaller = BottomBarInstaller(
31+
viewController: self,
32+
avoidsKeyboard: true,
33+
bars: [buttonRowBar])
34+
35+
private var textFieldRowItem: ItemModeling {
36+
TextFieldRow.itemModel(
37+
dataID: DataID.username,
38+
content: .init(placeholder: "Username"),
39+
style: .base)
40+
}
41+
42+
private var buttonRowBar: BarModeling {
43+
ButtonRow.barModel(
44+
dataID: DataID.button,
45+
content: .init(text: "Submit"),
46+
behaviors: .init(didTap: { [weak self] in
47+
self?.view.endEditing(true)
48+
}))
49+
}
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Created by oleksandr_zarochintsev on 4/26/21.
2+
// Copyright © 2021 Airbnb Inc. All rights reserved.
3+
4+
import Epoxy
5+
import UIKit
6+
7+
final class TextFieldRow: UIView, EpoxyableView {
8+
9+
// MARK: Lifecycle
10+
11+
init(style: Style) {
12+
self.style = style
13+
super.init(frame: .zero)
14+
translatesAutoresizingMaskIntoConstraints = false
15+
setUpViews()
16+
setUpConstraints()
17+
}
18+
19+
required init?(coder aDecoder: NSCoder) {
20+
fatalError("init(coder:) has not been implemented")
21+
}
22+
23+
// MARK: Internal
24+
25+
enum Style {
26+
case base
27+
}
28+
29+
struct Content: Equatable {
30+
var text: String?
31+
var placeholder: String?
32+
}
33+
34+
func setContent(_ content: Content, animated: Bool) {
35+
text = content.text
36+
placeholder = content.placeholder
37+
}
38+
39+
// MARK: Private
40+
41+
private let style: Style
42+
private let textField = UITextField()
43+
44+
private var text: String? {
45+
get { textField.text }
46+
set {
47+
guard textField.text != newValue else { return }
48+
textField.text = newValue
49+
}
50+
}
51+
52+
private var placeholder: String? {
53+
get { textField.placeholder }
54+
set {
55+
guard textField.placeholder != newValue else { return }
56+
textField.placeholder = newValue
57+
}
58+
}
59+
60+
private func setUpViews() {
61+
setUpTextField()
62+
}
63+
64+
private func setUpTextField() {
65+
textField.translatesAutoresizingMaskIntoConstraints = false
66+
textField.borderStyle = .roundedRect
67+
addSubview(textField)
68+
}
69+
70+
private func setUpConstraints() {
71+
NSLayoutConstraint.activate([
72+
textField.topAnchor.constraint(equalTo: topAnchor, constant: 16),
73+
textField.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
74+
textField.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
75+
textField.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -16),
76+
])
77+
}
78+
}

0 commit comments

Comments
 (0)