Skip to content

Commit 3c0fdf7

Browse files
author
Kyle Begeman
committed
Initial commit.
1 parent 45b27bd commit 3c0fdf7

8 files changed

Lines changed: 182 additions & 96 deletions

File tree

Example/ViewController.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,9 @@ class ViewController: UIViewController, InlineTagControllerDelegate {
1717
super.viewDidLoad()
1818
// Do any additional setup after loading the view, typically from a nib.
1919

20+
tagController.setConfiguration(CustomConfiguration())
2021
tagController.tagDelegate = self
2122
tagController.setPlaceholderText(text: "Enter new tags...")
22-
23-
InlineTagControllerConfiguration.itemValidation = InlineTagControllerValidation.testEmptiness
24-
InlineTagControllerConfiguration.numberOfTags = .quantity(5) // .unlimited also available
2523
}
2624

2725
func inlineTagController(_ controller: InlineTagController, didFinishEditing text: String) {
@@ -34,3 +32,9 @@ class ViewController: UIViewController, InlineTagControllerDelegate {
3432

3533
}
3634

35+
class CustomConfiguration: InlineTagConfigurable {
36+
var backgroundColor: ColorCollection = (view: UIColor.black, edit: UIColor.lightGray, invalid: UIColor.blue, placeholder: UIColor.green)
37+
var radius: ValueCollection = (view: 4.0, edit: 0.0, invalid: 8.0)
38+
39+
var cellHeight: Float = 12.0
40+
}

InlineTagController.xcodeproj/project.pbxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
27BD79251F13F1DE0018832A /* InlineTagController.h in Headers */ = {isa = PBXBuildFile; fileRef = 27BD79231F13F1DE0018832A /* InlineTagController.h */; settings = {ATTRIBUTES = (Public, ); }; };
1111
27BD79321F13F2060018832A /* InlineTagCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27BD792D1F13F2060018832A /* InlineTagCell.swift */; };
1212
27BD79331F13F2060018832A /* InlineTagController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27BD792E1F13F2060018832A /* InlineTagController.swift */; };
13-
27BD79341F13F2060018832A /* InlineTagControllerConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27BD792F1F13F2060018832A /* InlineTagControllerConfiguration.swift */; };
13+
27BD79341F13F2060018832A /* InlineTagConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27BD792F1F13F2060018832A /* InlineTagConfigurable.swift */; };
1414
27BD79351F13F2060018832A /* InlineTagControllerFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27BD79301F13F2060018832A /* InlineTagControllerFlowLayout.swift */; };
1515
27BD79361F13F2060018832A /* InlineTagControllerValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27BD79311F13F2060018832A /* InlineTagControllerValidation.swift */; };
1616
27BD793E1F13F2680018832A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27BD793D1F13F2680018832A /* AppDelegate.swift */; };
@@ -26,7 +26,7 @@
2626
27BD79241F13F1DE0018832A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
2727
27BD792D1F13F2060018832A /* InlineTagCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InlineTagCell.swift; path = /Users/kyle/Desktop/InlineTagController/Sources/InlineTagCell.swift; sourceTree = "<absolute>"; };
2828
27BD792E1F13F2060018832A /* InlineTagController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InlineTagController.swift; path = /Users/kyle/Desktop/InlineTagController/InlineTagController/../Sources/InlineTagController.swift; sourceTree = "<absolute>"; };
29-
27BD792F1F13F2060018832A /* InlineTagControllerConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InlineTagControllerConfiguration.swift; path = /Users/kyle/Desktop/InlineTagController/InlineTagController/../Sources/InlineTagControllerConfiguration.swift; sourceTree = "<absolute>"; };
29+
27BD792F1F13F2060018832A /* InlineTagConfigurable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InlineTagConfigurable.swift; path = /Users/kyle/Desktop/InlineTagController/Sources/InlineTagConfigurable.swift; sourceTree = "<absolute>"; };
3030
27BD79301F13F2060018832A /* InlineTagControllerFlowLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InlineTagControllerFlowLayout.swift; path = /Users/kyle/Desktop/InlineTagController/InlineTagController/../Sources/InlineTagControllerFlowLayout.swift; sourceTree = "<absolute>"; };
3131
27BD79311F13F2060018832A /* InlineTagControllerValidation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InlineTagControllerValidation.swift; path = /Users/kyle/Desktop/InlineTagController/InlineTagController/../Sources/InlineTagControllerValidation.swift; sourceTree = "<absolute>"; };
3232
27BD793B1F13F2680018832A /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -97,7 +97,7 @@
9797
children = (
9898
27BD792D1F13F2060018832A /* InlineTagCell.swift */,
9999
27BD792E1F13F2060018832A /* InlineTagController.swift */,
100-
27BD792F1F13F2060018832A /* InlineTagControllerConfiguration.swift */,
100+
27BD792F1F13F2060018832A /* InlineTagConfigurable.swift */,
101101
27BD79301F13F2060018832A /* InlineTagControllerFlowLayout.swift */,
102102
27BD79311F13F2060018832A /* InlineTagControllerValidation.swift */,
103103
);
@@ -234,7 +234,7 @@
234234
buildActionMask = 2147483647;
235235
files = (
236236
27BD79321F13F2060018832A /* InlineTagCell.swift in Sources */,
237-
27BD79341F13F2060018832A /* InlineTagControllerConfiguration.swift in Sources */,
237+
27BD79341F13F2060018832A /* InlineTagConfigurable.swift in Sources */,
238238
27BD79331F13F2060018832A /* InlineTagController.swift in Sources */,
239239
27BD79351F13F2060018832A /* InlineTagControllerFlowLayout.swift in Sources */,
240240
27BD79361F13F2060018832A /* InlineTagControllerValidation.swift in Sources */,
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Bucket
3+
type = "1"
4+
version = "2.0">
5+
<Breakpoints>
6+
<BreakpointProxy
7+
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
8+
<BreakpointContent
9+
shouldBeEnabled = "Yes"
10+
ignoreCount = "0"
11+
continueAfterRunningActions = "No"
12+
filePath = "Sources/InlineTagConfigurable.swift"
13+
timestampString = "521576595.271164"
14+
startingColumnNumber = "9223372036854775807"
15+
endingColumnNumber = "9223372036854775807"
16+
startingLineNumber = "80"
17+
endingLineNumber = "80"
18+
landmarkName = "set(config:)"
19+
landmarkType = "7">
20+
</BreakpointContent>
21+
</BreakpointProxy>
22+
<BreakpointProxy
23+
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
24+
<BreakpointContent
25+
shouldBeEnabled = "Yes"
26+
ignoreCount = "0"
27+
continueAfterRunningActions = "No"
28+
filePath = "Sources/InlineTagController.swift"
29+
timestampString = "521576607.517376"
30+
startingColumnNumber = "9223372036854775807"
31+
endingColumnNumber = "9223372036854775807"
32+
startingLineNumber = "104"
33+
endingLineNumber = "104"
34+
landmarkName = "updateForConfig()"
35+
landmarkType = "7">
36+
</BreakpointContent>
37+
</BreakpointProxy>
38+
</Breakpoints>
39+
</Bucket>

Sources/InlineTagCell.swift

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,10 @@ class InlineTagCell: UICollectionViewCell, UITextFieldDelegate {
8484
self.textField.textAlignment = .center
8585
self.textField.contentMode = .left
8686

87-
self.textField.keyboardType = InlineTagControllerConfiguration.keyboardType
88-
self.textField.returnKeyType = InlineTagControllerConfiguration.returnKey
89-
self.textField.autocapitalizationType = InlineTagControllerConfiguration.autoCapitalization
90-
self.textField.autocorrectionType = InlineTagControllerConfiguration.autoCorrection
87+
self.textField.keyboardType = TagConfig.keyboardType
88+
self.textField.returnKeyType = TagConfig.returnKey
89+
self.textField.autocapitalizationType = TagConfig.autoCapitalization
90+
self.textField.autocorrectionType = TagConfig.autoCorrection
9191

9292
set(mode: .view)
9393
}
@@ -121,28 +121,28 @@ class InlineTagCell: UICollectionViewCell, UITextFieldDelegate {
121121

122122
switch m {
123123
case .edit:
124-
textField.backgroundColor = InlineTagControllerConfiguration.editBackgroundColor
125-
textField.font = InlineTagControllerConfiguration.editFont
126-
textField.textColor = InlineTagControllerConfiguration.editFontColor
124+
textField.backgroundColor = TagConfig.backgroundColor.edit
125+
textField.font = TagConfig.font.edit
126+
textField.textColor = TagConfig.fontColor.edit
127127

128-
self.backgroundColor = InlineTagControllerConfiguration.editBackgroundColor
129-
self.layer.cornerRadius = CGFloat(InlineTagControllerConfiguration.editCornerRadius)
128+
self.backgroundColor = TagConfig.backgroundColor.edit
129+
self.layer.cornerRadius = TagConfig.radius.edit
130130

131131
case .view:
132-
textField.backgroundColor = InlineTagControllerConfiguration.viewBackgroundColor
133-
textField.font = InlineTagControllerConfiguration.viewFont
134-
textField.textColor = InlineTagControllerConfiguration.viewFontColor
132+
textField.backgroundColor = TagConfig.backgroundColor.view
133+
textField.font = TagConfig.font.view
134+
textField.textColor = TagConfig.fontColor.view
135135

136-
self.backgroundColor = InlineTagControllerConfiguration.viewBackgroundColor
137-
self.layer.cornerRadius = CGFloat(InlineTagControllerConfiguration.viewCornerRadius)
136+
self.backgroundColor = TagConfig.backgroundColor.view
137+
self.layer.cornerRadius = TagConfig.radius.view
138138

139139
case .invalid:
140-
textField.backgroundColor = InlineTagControllerConfiguration.invalidBackgroundColor
141-
textField.font = InlineTagControllerConfiguration.invalidFont
142-
textField.textColor = InlineTagControllerConfiguration.invalidFontColor
140+
textField.backgroundColor = TagConfig.backgroundColor.invalid
141+
textField.font = TagConfig.font.invalid
142+
textField.textColor = TagConfig.fontColor.invalid
143143

144-
self.backgroundColor = InlineTagControllerConfiguration.invalidBackgroundColor
145-
self.layer.cornerRadius = CGFloat(InlineTagControllerConfiguration.invalidCornerRadius)
144+
self.backgroundColor = TagConfig.backgroundColor.invalid
145+
self.layer.cornerRadius = TagConfig.radius.invalid
146146
}
147147

148148
self.mode = mode
@@ -159,7 +159,7 @@ class InlineTagCell: UICollectionViewCell, UITextFieldDelegate {
159159
extension InlineTagCell {
160160

161161
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
162-
if string == " " && InlineTagControllerConfiguration.skipOnWhitespace && InlineTagControllerValidation.isValid(text: self.textField.text) {
162+
if string == " " && TagConfig.skipOnWhitespace && InlineTagControllerValidation.isValid(text: self.textField.text) {
163163
self.delegate?.createAndSwitchToNewCell(cell: self)
164164
} else if string == "" && textField.text == "" {
165165
self.delegate?.shouldDeleteCellInFrontOfCell(cell: self)
@@ -171,7 +171,7 @@ extension InlineTagCell {
171171
}
172172

173173
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
174-
if InlineTagControllerConfiguration.skipOnReturnKey {
174+
if TagConfig.skipOnReturnKey {
175175
if !InlineTagControllerValidation.isValid(text: textField.text) {
176176
return false
177177
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//
2+
// InlineTagControllerConfiguration.swift
3+
// Testing
4+
//
5+
// Created by Kyle Begeman on 7/10/17.
6+
// Copyright © 2017 Kyle Begeman. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import UIKit
11+
12+
public typealias ColorCollection = (view: UIColor, edit: UIColor, invalid: UIColor, placeholder: UIColor?)
13+
public typealias FontCollection = (view: UIFont, edit: UIFont, invalid: UIFont, placeholder: UIFont)
14+
public typealias ValueCollection = (view: CGFloat, edit: CGFloat, invalid: CGFloat)
15+
16+
public enum NumberOfTags {
17+
case unlimited
18+
case quantity(Int)
19+
}
20+
21+
public protocol InlineTagConfigurable {
22+
var backgroundColor: ColorCollection { get }
23+
var fontColor: ColorCollection { get }
24+
var font: FontCollection { get }
25+
var radius: ValueCollection { get }
26+
27+
var cellHeight: Float { get }
28+
var inset: UIEdgeInsets { get }
29+
var interitemSpacing: CGFloat { get }
30+
var lineSpacing: CGFloat { get }
31+
var keyboardType: UIKeyboardType { get }
32+
var returnKey: UIReturnKeyType { get }
33+
var autoCapitalization: UITextAutocapitalizationType { get }
34+
var autoCorrection: UITextAutocorrectionType { get }
35+
var skipOnWhitespace: Bool { get }
36+
var skipOnReturnKey: Bool { get }
37+
var numberOfTags: NumberOfTags { get }
38+
var itemValidation: Validation? { get }
39+
}
40+
41+
extension InlineTagConfigurable {
42+
public var backgroundColor: ColorCollection {
43+
return (view: UIColor.blue, edit: UIColor.white, invalid: UIColor.red, placeholder: nil)
44+
}
45+
public var fontColor: ColorCollection {
46+
return (view: UIColor.white, edit: UIColor.darkText, invalid: UIColor.white, placeholder: UIColor.gray)
47+
}
48+
public var radius: ValueCollection {
49+
return (view: 8.0, edit: 8.0, invalid: 8.0)
50+
}
51+
public var font: FontCollection {
52+
let font = UIFont.systemFont(ofSize: 12.0, weight: UIFontWeightMedium)
53+
let phFont = UIFont.systemFont(ofSize: 12.0, weight: UIFontWeightLight)
54+
return (view: font, edit: font, invalid: font, placeholder: phFont)
55+
}
56+
57+
public var cellHeight: Float { return 20.0 }
58+
public var inset: UIEdgeInsets { return UIEdgeInsets(top: 2, left: 4, bottom: 2, right: 4) }
59+
public var interitemSpacing: CGFloat { return 5.0 }
60+
public var lineSpacing: CGFloat { return 5.0 }
61+
public var keyboardType: UIKeyboardType { return .default }
62+
public var returnKey: UIReturnKeyType { return .done }
63+
public var autoCapitalization: UITextAutocapitalizationType { return .none }
64+
public var autoCorrection: UITextAutocorrectionType { return .no }
65+
public var skipOnWhitespace: Bool { return true }
66+
public var skipOnReturnKey: Bool { return true }
67+
public var numberOfTags: NumberOfTags { return .unlimited }
68+
public var itemValidation: Validation? { return InlineTagControllerValidation.testEmptiness }
69+
}
70+
71+
internal class Config {
72+
static let instance = Config()
73+
private init() {
74+
configuration = DefaultConfiguration()
75+
}
76+
77+
var configuration: InlineTagConfigurable
78+
79+
func set(config: InlineTagConfigurable) {
80+
self.configuration = config
81+
}
82+
}
83+
84+
public class DefaultConfiguration: InlineTagConfigurable {}
85+
public let TagConfig = Config.instance.configuration

Sources/InlineTagController.swift

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,12 @@ public class InlineTagController: UICollectionView {
7474
return CGSize(width: self.bounds.width, height: max(self.minimumHeight(), size.height))
7575
}
7676

77-
private func customInit() {
78-
sizingCell = InlineTagCell(frame: CGRect(x: 0, y: 0, width: 100, height: CGFloat(InlineTagControllerConfiguration.cellHeight)))
77+
public func setConfiguration(_ config: InlineTagConfigurable) {
78+
Config.instance.set(config: config)
79+
updateForConfig()
80+
}
7981

82+
private func customInit() {
8083
self.backgroundColor = UIColor.white
8184
var frame = self.bounds
8285
frame.size.height = minimumHeight()
@@ -85,28 +88,34 @@ public class InlineTagController: UICollectionView {
8588
let view = UIView(frame: frame)
8689
view.addSubview(self.placeholderLabel)
8790

88-
self.placeholderLabel.font = InlineTagControllerConfiguration.placeholderFont
89-
self.placeholderLabel.textColor = InlineTagControllerConfiguration.placeholderFontColor
90-
9191
self.backgroundView = view
9292
self.register(InlineTagCell.self, forCellWithReuseIdentifier: InlineTagCell.identifier)
9393

9494
self.dataSource = self
9595
self.delegate = self
9696

97+
self.tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTapOnView(_:)))
98+
self.addGestureRecognizer(self.tapRecognizer)
99+
100+
updateForConfig()
101+
}
102+
103+
private func updateForConfig() {
104+
sizingCell = InlineTagCell(frame: CGRect(x: 0, y: 0, width: 100, height: CGFloat(TagConfig.cellHeight)))
105+
97106
if let layout = self.collectionViewLayout as? InlineTagControllerFlowLayout {
98-
layout.sectionInset = InlineTagControllerConfiguration.inset
99-
layout.minimumInteritemSpacing = InlineTagControllerConfiguration.interitemSpacing
100-
layout.minimumLineSpacing = InlineTagControllerConfiguration.lineSpacing
107+
layout.sectionInset = TagConfig.inset
108+
layout.minimumInteritemSpacing = TagConfig.interitemSpacing
109+
layout.minimumLineSpacing = TagConfig.lineSpacing
101110
}
102111

103-
self.tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTapOnView(_:)))
104-
self.addGestureRecognizer(self.tapRecognizer)
112+
self.placeholderLabel.font = TagConfig.font.placeholder
113+
self.placeholderLabel.textColor = TagConfig.fontColor.placeholder
105114
}
106115

107116
private func minimumHeight() -> CGFloat {
108-
let defaultHeight: CGFloat = CGFloat(InlineTagControllerConfiguration.cellHeight)
109-
let padding = InlineTagControllerConfiguration.inset.top + InlineTagControllerConfiguration.inset.bottom
117+
let defaultHeight: CGFloat = CGFloat(TagConfig.cellHeight)
118+
let padding = TagConfig.inset.top + TagConfig.inset.bottom
110119

111120
return defaultHeight + padding
112121
}
@@ -158,7 +167,7 @@ public class InlineTagController: UICollectionView {
158167
}
159168

160169
private func isTextValid(text: String) -> Bool {
161-
if let validation = InlineTagControllerConfiguration.itemValidation {
170+
if let validation = TagConfig.itemValidation {
162171
return validation(text)
163172
} else {
164173
return true
@@ -223,7 +232,7 @@ extension InlineTagController {
223232
}
224233

225234
private func replaceLastInvalidOrInsertItemText(text: String, switchToNext: Bool = true, completion: (() -> ())? = nil) {
226-
if let validator = InlineTagControllerConfiguration.itemValidation, let tag = self.tags.last, !validator(tag.text) {
235+
if let validator = TagConfig.itemValidation, let tag = self.tags.last, !validator(tag.text) {
227236
let position = self.tags.index(where: { (i) -> Bool in
228237
i.text == tag.text
229238
})
@@ -335,7 +344,7 @@ extension InlineTagController: UICollectionViewDelegate, UICollectionViewDataSou
335344
let layoutInset = (self.collectionViewLayout as! UICollectionViewFlowLayout).sectionInset
336345
let maximumWidth = self.bounds.width - layoutInset.left - layoutInset.right
337346

338-
return CGSize(width: min(size.width, maximumWidth), height: CGFloat(InlineTagControllerConfiguration.cellHeight))
347+
return CGSize(width: min(size.width, maximumWidth), height: CGFloat(TagConfig.cellHeight))
339348
}
340349

341350
}
@@ -401,7 +410,7 @@ extension InlineTagController: InlineTagCellDelegate {
401410
}
402411

403412
internal func needPreciseNumberOfItems() -> Int? {
404-
switch InlineTagControllerConfiguration.numberOfTags {
413+
switch TagConfig.numberOfTags {
405414
case .unlimited:
406415
return nil
407416
case let .quantity(value):

0 commit comments

Comments
 (0)