Skip to content

Commit 8765c5d

Browse files
authored
Merge pull request #22 from polydice/feature/option-picker-control
Option Picker Control
2 parents c267726 + f4f2900 commit 8765c5d

File tree

8 files changed

+405
-10
lines changed

8 files changed

+405
-10
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## `develop`
2+
3+
* Drop Class Name Prefixes
4+
* Add an easy to use `OptionPickerControl` that displays a `UIPickerView` with given options
5+
16
## v1.5.0
27

38
* Swift 4.0

Example/ExampleViewController.swift

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,20 @@ import ICInputAccessory
2929

3030
class ExampleViewController: UITableViewController {
3131

32-
private let types: [UIView.Type] = [
32+
private let showcases: [UIView.Type] = [
3333
KeyboardDismissTextField.self,
3434
TokenField.self,
35-
CustomizedTokenField.self
35+
CustomizedTokenField.self,
36+
OptionPickerControl<Language>.self
3637
]
3738

39+
private lazy var languagePicker: OptionPickerControl<Language> = {
40+
let picker = OptionPickerControl<Language>()
41+
picker.options += Language.availableLanguages.map(Option.init(_:))
42+
picker.addTarget(self, action: .updateLanguage, for: .valueChanged)
43+
return picker
44+
}()
45+
3846
private lazy var flipButton: UIButton = {
3947
let _button = UIButton(type: .system)
4048
_button.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 88)
@@ -52,41 +60,45 @@ class ExampleViewController: UITableViewController {
5260

5361
// MARK: - UIViewController
5462

55-
override func loadView() {
56-
super.loadView()
63+
override func viewDidLoad() {
64+
super.viewDidLoad()
5765
tableView.rowHeight = 44
5866
tableView.register(ExampleCell.self, forCellReuseIdentifier: String(describing: ExampleCell.self))
5967
tableView.tableFooterView = flipButton
6068
tableView.tableFooterView?.isUserInteractionEnabled = true
69+
view.addSubview(languagePicker)
6170
}
6271

6372
// MARK: - UITableViewDataSource
6473

6574
override func numberOfSections(in tableView: UITableView) -> Int {
66-
return types.count
75+
return showcases.count
6776
}
6877

6978
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
7079
return 1
7180
}
7281

7382
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
74-
switch types[section] {
83+
switch showcases[section] {
7584
case is KeyboardDismissTextField.Type:
7685
return "Dismiss Keyboard"
7786
case is TokenField.Type:
7887
return "Text Field with Tokens"
7988
case is CustomizedTokenField.Type:
8089
return "Customize Token Field"
90+
case is OptionPickerControl<Language>.Type:
91+
return "Option Picker Control"
8192
default:
8293
return ""
8394
}
8495
}
8596

8697
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
8798
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ExampleCell.self), for: indexPath)
99+
cell.accessoryType = .none
88100

89-
switch types[indexPath.section] {
101+
switch showcases[indexPath.section] {
90102
case let type as KeyboardDismissTextField.Type:
91103
let textField = type.init()
92104
textField.leftViewMode = .always
@@ -107,6 +119,11 @@ class ExampleViewController: UITableViewController {
107119
container.addSubview(tokenField)
108120
(cell as? ExampleCell)?.showcase = container
109121

122+
case is OptionPickerControl<Language>.Type:
123+
(cell as? ExampleCell)?.showcase = nil
124+
cell.textLabel?.text = languagePicker.selectedOption.title
125+
cell.accessoryType = .disclosureIndicator
126+
110127
default:
111128
break
112129
}
@@ -116,12 +133,25 @@ class ExampleViewController: UITableViewController {
116133
// MARK: - UITableViewDelegate
117134

118135
override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
119-
return types[indexPath.section] == CustomizedTokenField.self
136+
switch showcases[indexPath.section] {
137+
case is CustomizedTokenField.Type:
138+
return true
139+
case is OptionPickerControl<Language>.Type:
140+
return true
141+
default:
142+
return false
143+
}
120144
}
121145

122146
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
123-
if types[indexPath.section] == CustomizedTokenField.self {
147+
switch showcases[indexPath.section] {
148+
case is CustomizedTokenField.Type:
124149
present(UINavigationController(rootViewController: CustomizedTokenViewController()), animated: true, completion: nil)
150+
case is OptionPickerControl<Language>.Type:
151+
tableView.deselectRow(at: indexPath, animated: true)
152+
languagePicker.becomeFirstResponder()
153+
default:
154+
break
125155
}
126156
}
127157

@@ -134,6 +164,10 @@ class ExampleViewController: UITableViewController {
134164
}
135165
}
136166

167+
@objc fileprivate func updateLanguage(_ sender: UIControl) {
168+
tableView.reloadData()
169+
}
170+
137171
}
138172

139173

@@ -142,4 +176,5 @@ class ExampleViewController: UITableViewController {
142176

143177
private extension Selector {
144178
static let showStoryboard = #selector(ExampleViewController.showStoryboard(_:))
179+
static let updateLanguage = #selector(ExampleViewController.updateLanguage(_:))
145180
}

Example/Language.swift

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//
2+
// Language.swift
3+
// Example
4+
//
5+
// Created by Ben on 20/01/2018.
6+
// Copyright © 2018 bcylin.
7+
//
8+
// Permission is hereby granted, free of charge, to any person obtaining a copy
9+
// of this software and associated documentation files (the "Software"), to deal
10+
// in the Software without restriction, including without limitation the rights
11+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
// copies of the Software, and to permit persons to whom the Software is
13+
// furnished to do so, subject to the following conditions:
14+
//
15+
// The above copyright notice and this permission notice shall be included in all
16+
// copies or substantial portions of the Software.
17+
//
18+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
// SOFTWARE.
25+
//
26+
27+
import Foundation
28+
import ICInputAccessory
29+
30+
enum Language: String, OptionDescriptive {
31+
32+
case english
33+
case french
34+
case german
35+
case japanese
36+
case mandarin
37+
case spanish
38+
39+
static var availableLanguages: [Language] = [
40+
.english,
41+
.french,
42+
.german,
43+
.japanese,
44+
.mandarin,
45+
.spanish
46+
]
47+
48+
// MARK: - OptionDescriptive
49+
50+
var title: String {
51+
return rawValue.capitalized
52+
}
53+
54+
static var titleForOptionalValue: String {
55+
return "(Optional)"
56+
}
57+
58+
}

ICInputAccessory.podspec

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,17 @@ Pod::Spec.new do |s|
2323
s.source = { git: "https://github.com/polydice/ICInputAccessory.git", tag: "v#{s.version}" }
2424
s.requires_arc = true
2525

26-
s.default_subspecs = "KeyboardDismissTextField", "TokenField"
26+
s.default_subspecs = "KeyboardDismissTextField", "OptionPickerControl", "TokenField"
2727

2828
s.subspec "KeyboardDismissTextField" do |sp|
2929
sp.source_files = "Source/KeyboardDismissTextField/*.swift"
3030
sp.resources = "Source/KeyboardDismissTextField/*.xcassets"
3131
end
3232

33+
s.subspec "OptionPickerControl" do |sp|
34+
sp.source_files = "Source/OptionPickerControl/*.swift"
35+
end
36+
3337
s.subspec "TokenField" do |sp|
3438
sp.source_files = "Source/TokenField/*.swift"
3539
end

ICInputAccessory.xcodeproj/project.pbxproj

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
B528196D1C9035BE007D01D5 /* InsetLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52819691C9035BE007D01D5 /* InsetLabel.swift */; };
1313
B528196E1C9035BE007D01D5 /* Token.swift in Sources */ = {isa = PBXBuildFile; fileRef = B528196A1C9035BE007D01D5 /* Token.swift */; };
1414
B528196F1C9035BE007D01D5 /* TokenField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B528196B1C9035BE007D01D5 /* TokenField.swift */; };
15+
B52ADB1920132F0C00D96B87 /* Option.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52ADB1720132F0C00D96B87 /* Option.swift */; };
16+
B52ADB1A20132F0C00D96B87 /* OptionPickerControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52ADB1820132F0C00D96B87 /* OptionPickerControl.swift */; };
17+
B52ADB1C201332E400D96B87 /* Language.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52ADB1B201332E400D96B87 /* Language.swift */; };
18+
B52ADB1F201485B800D96B87 /* OptionPickerControlUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52ADB1D201485A700D96B87 /* OptionPickerControlUITests.swift */; };
1519
B533768B1F4436D000230739 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B533768A1F4436D000230739 /* AppDelegate.swift */; };
1620
B53376921F4436D000230739 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B53376911F4436D000230739 /* Assets.xcassets */; };
1721
B53376951F4436D000230739 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B53376931F4436D000230739 /* LaunchScreen.storyboard */; };
@@ -70,6 +74,10 @@
7074
B52819691C9035BE007D01D5 /* InsetLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InsetLabel.swift; path = Source/TokenField/InsetLabel.swift; sourceTree = SOURCE_ROOT; };
7175
B528196A1C9035BE007D01D5 /* Token.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Token.swift; path = Source/TokenField/Token.swift; sourceTree = SOURCE_ROOT; };
7276
B528196B1C9035BE007D01D5 /* TokenField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TokenField.swift; path = Source/TokenField/TokenField.swift; sourceTree = SOURCE_ROOT; };
77+
B52ADB1720132F0C00D96B87 /* Option.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Option.swift; path = Source/OptionPickerControl/Option.swift; sourceTree = SOURCE_ROOT; };
78+
B52ADB1820132F0C00D96B87 /* OptionPickerControl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OptionPickerControl.swift; path = Source/OptionPickerControl/OptionPickerControl.swift; sourceTree = SOURCE_ROOT; };
79+
B52ADB1B201332E400D96B87 /* Language.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Language.swift; sourceTree = "<group>"; };
80+
B52ADB1D201485A700D96B87 /* OptionPickerControlUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = OptionPickerControlUITests.swift; path = ICInputAccessoryUITests/OptionPickerControlUITests.swift; sourceTree = SOURCE_ROOT; };
7381
B53376881F4436D000230739 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
7482
B533768A1F4436D000230739 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7583
B53376911F4436D000230739 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -148,6 +156,15 @@
148156
name = TokenField;
149157
sourceTree = "<group>";
150158
};
159+
B52ADB1220132EEF00D96B87 /* OptionPickerControl */ = {
160+
isa = PBXGroup;
161+
children = (
162+
B52ADB1720132F0C00D96B87 /* Option.swift */,
163+
B52ADB1820132F0C00D96B87 /* OptionPickerControl.swift */,
164+
);
165+
name = OptionPickerControl;
166+
sourceTree = "<group>";
167+
};
151168
B53376891F4436D000230739 /* Example */ = {
152169
isa = PBXGroup;
153170
children = (
@@ -158,6 +175,7 @@
158175
B53376AF1F44387000230739 /* ExampleCell.swift */,
159176
B53376B01F44387000230739 /* ExampleViewController.swift */,
160177
B53376961F4436D000230739 /* Info.plist */,
178+
B52ADB1B201332E400D96B87 /* Language.swift */,
161179
B53376931F4436D000230739 /* LaunchScreen.storyboard */,
162180
B53376B11F44387000230739 /* Main.storyboard */,
163181
B53376B21F44387000230739 /* StoryboardViewController.swift */,
@@ -170,6 +188,7 @@
170188
children = (
171189
B53376A11F4436D000230739 /* Info.plist */,
172190
B53376A91F4437D900230739 /* KeyboardDismissTextFieldUITests.swift */,
191+
B52ADB1D201485A700D96B87 /* OptionPickerControlUITests.swift */,
173192
B53376AA1F4437D900230739 /* TokenFieldUITests.swift */,
174193
);
175194
name = ICInputAccessoryUITests;
@@ -202,6 +221,7 @@
202221
isa = PBXGroup;
203222
children = (
204223
B52819671C90358C007D01D5 /* KeyboardDismissAccessory */,
224+
B52ADB1220132EEF00D96B87 /* OptionPickerControl */,
205225
B52819701C9035C3007D01D5 /* TokenField */,
206226
B56BC42D1C89A7EA00C20AD6 /* ICInputAccessory.h */,
207227
B548C5AC1C8D69A5009D5AEE /* Images.xcassets */,
@@ -410,6 +430,7 @@
410430
B53376B41F44387000230739 /* CustomizedTokenViewController.swift in Sources */,
411431
B53376B51F44387000230739 /* ExampleCell.swift in Sources */,
412432
B53376B61F44387000230739 /* ExampleViewController.swift in Sources */,
433+
B52ADB1C201332E400D96B87 /* Language.swift in Sources */,
413434
B53376B81F44387000230739 /* StoryboardViewController.swift in Sources */,
414435
);
415436
runOnlyForDeploymentPostprocessing = 0;
@@ -419,6 +440,7 @@
419440
buildActionMask = 2147483647;
420441
files = (
421442
B53376AB1F4437D900230739 /* KeyboardDismissTextFieldUITests.swift in Sources */,
443+
B52ADB1F201485B800D96B87 /* OptionPickerControlUITests.swift in Sources */,
422444
B53376AC1F4437D900230739 /* TokenFieldUITests.swift in Sources */,
423445
);
424446
runOnlyForDeploymentPostprocessing = 0;
@@ -431,6 +453,8 @@
431453
B528196D1C9035BE007D01D5 /* InsetLabel.swift in Sources */,
432454
B56BC4361C89A8D800C20AD6 /* KeyboardDismissAccessoryView.swift in Sources */,
433455
B548C5EE1C8EB9E2009D5AEE /* KeyboardDismissTextField.swift in Sources */,
456+
B52ADB1920132F0C00D96B87 /* Option.swift in Sources */,
457+
B52ADB1A20132F0C00D96B87 /* OptionPickerControl.swift in Sources */,
434458
B528196E1C9035BE007D01D5 /* Token.swift in Sources */,
435459
B528196F1C9035BE007D01D5 /* TokenField.swift in Sources */,
436460
);
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//
2+
// OptionPickerControlUITests.swift
3+
// ICInputAccessoryUITests
4+
//
5+
// Created by Ben on 21/01/2018.
6+
// Copyright © 2018 bcylin.
7+
//
8+
// Permission is hereby granted, free of charge, to any person obtaining a copy
9+
// of this software and associated documentation files (the "Software"), to deal
10+
// in the Software without restriction, including without limitation the rights
11+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
// copies of the Software, and to permit persons to whom the Software is
13+
// furnished to do so, subject to the following conditions:
14+
//
15+
// The above copyright notice and this permission notice shall be included in all
16+
// copies or substantial portions of the Software.
17+
//
18+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
// SOFTWARE.
25+
//
26+
27+
import XCTest
28+
29+
final class OptionPickerControlUITests: XCTestCase {
30+
31+
private lazy var app = XCUIApplication()
32+
33+
override func setUp() {
34+
super.setUp()
35+
continueAfterFailure = false
36+
XCUIApplication().launch()
37+
}
38+
39+
func testOptionSelection() {
40+
app.tables.staticTexts["(Optional)"].tap()
41+
let picker = app.pickerWheels.element
42+
43+
picker.adjust(toPickerWheelValue: "English")
44+
XCTAssert(app.tables.staticTexts["English"].exists)
45+
46+
picker.adjust(toPickerWheelValue: "French")
47+
XCTAssert(app.tables.staticTexts["French"].exists)
48+
49+
picker.adjust(toPickerWheelValue: "German")
50+
XCTAssert(app.tables.staticTexts["German"].exists)
51+
52+
picker.adjust(toPickerWheelValue: "Japanese")
53+
XCTAssert(app.tables.staticTexts["Japanese"].exists)
54+
55+
picker.adjust(toPickerWheelValue: "Mandarin")
56+
XCTAssert(app.tables.staticTexts["Mandarin"].exists)
57+
58+
picker.adjust(toPickerWheelValue: "Spanish")
59+
XCTAssert(app.tables.staticTexts["Spanish"].exists)
60+
61+
app.toolbars.buttons["Done"].tap()
62+
}
63+
64+
}

0 commit comments

Comments
 (0)