4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NumericPicker.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod lib lint NumericPicker.podspec' to ensure this is a
3 | # valid spec before submitting.
4 | #
5 | # Any lines starting with a # are optional, but their use is encouraged
6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
7 | #
8 |
9 | Pod::Spec.new do |s|
10 | s.name = 'NumericPicker'
11 | s.version = '1.1.1'
12 | s.summary = 'iOS picker for easily selecting numbers by digit.'
13 | s.swift_version = '4.2'
14 |
15 | s.description = <<-DESC
16 | NumericPicker is a drop-in iOS picker control written in Swift. It makes simplifies the creation of pickers that allow
17 | your users to specify numbers by digit. It automatically uses the proper grouping and decimal separator for the
18 | current (or specified) locale. You can easily dictate the number of integer and decimal places in the controller.
19 | DESC
20 |
21 | s.homepage = 'https://github.com/MattLewin/NumericPicker'
22 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
23 | s.license = { :type => 'MIT', :file => 'LICENSE.md' }
24 | s.author = { 'Matt Lewin' => 'matt@mogroups.com' }
25 | s.source = { :git => 'https://github.com/MattLewin/NumericPicker.git', :tag => s.version.to_s }
26 | s.social_media_url = 'https://twitter.com/mlewin72'
27 |
28 | s.ios.deployment_target = '10.3'
29 |
30 | s.source_files = 'Sources'
31 | s.frameworks = 'UIKit'
32 | end
33 |
--------------------------------------------------------------------------------
/NumericPicker-Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/docs/js/jazzy.js:
--------------------------------------------------------------------------------
1 | window.jazzy = {'docset': false}
2 | if (typeof window.dash != 'undefined') {
3 | document.documentElement.className += ' dash'
4 | window.jazzy.docset = true
5 | }
6 | if (navigator.userAgent.match(/xcode/i)) {
7 | document.documentElement.className += ' xcode'
8 | window.jazzy.docset = true
9 | }
10 |
11 | // On doc load, toggle the URL hash discussion if present
12 | $(document).ready(function() {
13 | if (!window.jazzy.docset) {
14 | var linkToHash = $('a[href="' + window.location.hash +'"]');
15 | linkToHash.trigger("click");
16 | }
17 | });
18 |
19 | // On token click, toggle its discussion and animate token.marginLeft
20 | $(".token").click(function(event) {
21 | if (window.jazzy.docset) {
22 | return;
23 | }
24 | var link = $(this);
25 | var animationDuration = 300;
26 | var tokenOffset = "15px";
27 | var original = link.css('marginLeft') == tokenOffset;
28 | link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration);
29 | $content = link.parent().parent().next();
30 | $content.slideToggle(animationDuration);
31 |
32 | // Keeps the document from jumping to the hash.
33 | var href = $(this).attr('href');
34 | if (history.pushState) {
35 | history.pushState({}, '', href);
36 | } else {
37 | location.hash = href;
38 | }
39 | event.preventDefault();
40 | });
41 |
42 | // Dumb down quotes within code blocks that delimit strings instead of quotations
43 | // https://github.com/realm/jazzy/issues/714
44 | $("code q").replaceWith(function () {
45 | return ["\"", $(this).contents(), "\""];
46 | });
47 |
--------------------------------------------------------------------------------
/docs/docsets/NumericPicker.docset/Contents/Resources/Documents/js/jazzy.js:
--------------------------------------------------------------------------------
1 | window.jazzy = {'docset': false}
2 | if (typeof window.dash != 'undefined') {
3 | document.documentElement.className += ' dash'
4 | window.jazzy.docset = true
5 | }
6 | if (navigator.userAgent.match(/xcode/i)) {
7 | document.documentElement.className += ' xcode'
8 | window.jazzy.docset = true
9 | }
10 |
11 | // On doc load, toggle the URL hash discussion if present
12 | $(document).ready(function() {
13 | if (!window.jazzy.docset) {
14 | var linkToHash = $('a[href="' + window.location.hash +'"]');
15 | linkToHash.trigger("click");
16 | }
17 | });
18 |
19 | // On token click, toggle its discussion and animate token.marginLeft
20 | $(".token").click(function(event) {
21 | if (window.jazzy.docset) {
22 | return;
23 | }
24 | var link = $(this);
25 | var animationDuration = 300;
26 | var tokenOffset = "15px";
27 | var original = link.css('marginLeft') == tokenOffset;
28 | link.animate({'margin-left':original ? "0px" : tokenOffset}, animationDuration);
29 | $content = link.parent().parent().next();
30 | $content.slideToggle(animationDuration);
31 |
32 | // Keeps the document from jumping to the hash.
33 | var href = $(this).attr('href');
34 | if (history.pushState) {
35 | history.pushState({}, '', href);
36 | } else {
37 | location.hash = href;
38 | }
39 | event.preventDefault();
40 | });
41 |
42 | // Dumb down quotes within code blocks that delimit strings instead of quotations
43 | // https://github.com/realm/jazzy/issues/714
44 | $("code q").replaceWith(function () {
45 | return ["\"", $(this).contents(), "\""];
46 | });
47 |
--------------------------------------------------------------------------------
/NumericPicker-Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // NumericPicker
4 | //
5 | // Created by Matt Lewin on 02/02/2017.
6 | // Copyright © 2017 MoGroups
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
16 | // all 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
24 | // THE SOFTWARE.
25 | //
26 |
27 | import UIKit
28 |
29 | @UIApplicationMain
30 | class AppDelegate: UIResponder, UIApplicationDelegate {
31 |
32 | var window: UIWindow?
33 |
34 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
35 | return true
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/NumericPicker-Example/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/NumericPicker-Example/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 1.1.1
2 | * Reduce minimum required iOS version to 10.3. (Xcode 10 and Swift 4.2 still required)
3 |
4 | # 1.1.0
5 | * Update minimum requirements to be Xcode 10, iOS 12, and Swift 4.2
6 | * Remove the obsolete (and build-breaking) versioning artifact forcing this cocoapod to build as Swift 4.0
7 |
8 | # 1.0.1 - Long-Term Xcode 9 & Swift 4.0 support
9 | * Fix [issue #4](https://github.com/MattLewin/NumericPicker/issues/4): work around an iOS 12 SDK bug with picker view heights
10 | * Make NumericPicker example respond to changes in dynamic fonts
11 |
12 | # 1.0.0
13 | * The picker labels now adjust to changes in dynamic font sizes -- fixes a long-standing issue
14 | * Restore default picker font size to Body -- it was accidentally changed to Title 1
15 | * Remove hardcoded 54-point font from IB picker example
16 |
17 | # 0.6.0
18 | * Handle picker font size adjustment, fix layout issues - [Rotem Rubnov](https://github.com/rubnov) of [100 Grams Software](https://100grams.io)
19 | * Update project to Xcode 9.4.1 recommended settings
20 | * Access String characters directly, per String changes in Swift 4 ([SE-0163](https://github.com/apple/swift-evolution/blob/master/proposals/0163-string-revision-1.md))
21 |
22 | # 0.5.0
23 | * Completely reorganize the file layout to better support SPM, Carthage and Cocoapods, as well as make it easier for users to incorporate
24 | into their projects
25 | * Centralize the integer and fractional place descriptors, making the code easier to read and maintain
26 | * Prepare for using the Swift Package Manager, even though it does not yet support `UIKit` or `iOS`
27 |
28 | # 0.4.0
29 | * Update for Swift 4
30 | * Add accessibility labels to NumericPicker, thus facilitating voice over and UI testing
31 | * Simplify the code by replacing individual NumberFormatter local variables with an instance-level NumberFormatter
32 | * Rename NumericPickerTests to NumericPickerUnitTests
33 |
34 | # 0.3.1
35 | * Send '.valueChanged' message only when the numeric value of the picker changes, rather than when other factors (i.e., minimum
36 | fraction or maximum integer digits changes). This means the 'displayString' will need to be obtained after setting one of these
37 | properties.
38 |
39 | # 0.3.0
40 | * Resolves #1: allow for setting a minimum value for the picker to display
41 | * Update podspec for version 0.3.0
42 |
43 | # 0.2.2
44 | * Re-layout the control when `font` is updated
45 |
46 | # 0.2.1
47 | * Alphabetize all properties and functions in NumericPicker.swift, and modify the "MARK" comments to be sexier in Xcode
48 |
49 | # 0.2.0
50 | * Automatically increase `minIntegerDigits` if `value` is set to something with more than `minIntegerDigits`.
51 | This prevents picker components from vanishing if the user sets the leftmost component to zero.
52 | * Regardless of where the control is instantiated (code or IB) and how its properties are configured (defaults, code,
53 | IB), ensure it sized properly.
54 | * Clean up some whitespace
55 | * Fix a stupid typo on the README
56 |
57 | # 0.1.3
58 | Document code so Cocoadocs likes it more
59 |
60 | # 0.1.2
61 | More Carthage support changes
62 |
63 | # 0.1.1
64 | Changes to properly support Carthage
65 |
66 | # 0.1.0
67 | Initial public repo
68 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at matt@mogroups.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/NumericPicker-Example/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // NumericPicker
4 | //
5 | // Created by Matt Lewin on 02/02/2017.
6 | // Copyright © 2017 MoGroups
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
16 | // all 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
24 | // THE SOFTWARE.
25 | //
26 |
27 | import UIKit
28 | import NumericPicker
29 |
30 | class ViewController: UIViewController {
31 |
32 | // MARK: - Properties
33 | var codeNumericPicker = NumericPicker()
34 |
35 | // MARK: IB Outlets
36 | @IBOutlet weak var codePickerStack: UIStackView!
37 | @IBOutlet weak var codePickerValue: UILabel!
38 |
39 | @IBOutlet weak var ibPickerValue: UILabel!
40 | @IBOutlet weak var ibNumericPicker: NumericPicker!
41 |
42 | // MARK: - View life cycle
43 | override func viewDidLoad() {
44 | super.viewDidLoad()
45 | ibNumericPicker.value = 12345.6
46 |
47 | // Configure a NumericPicker in code
48 | codeNumericPicker.minIntegerDigits = 6
49 | codeNumericPicker.fractionDigits = 3
50 | codeNumericPicker.value = 76543.21
51 | codeNumericPicker.locale = Locale(identifier: "de-DE")
52 | codeNumericPicker.addTarget(self, action: #selector(codeValueChanged), for: .valueChanged)
53 | codePickerStack.addArrangedSubview(codeNumericPicker)
54 |
55 | NotificationCenter.default.addObserver(self,
56 | selector: #selector(contentSizeCategoryChanged(_:)),
57 | name: UIContentSizeCategory.didChangeNotification,
58 | object: nil)
59 |
60 | }
61 |
62 | override func viewWillAppear(_ animated: Bool) {
63 | super.viewWillAppear(animated)
64 | ibPickerValue.text = ibNumericPicker.displayString
65 | codePickerValue.text = codeNumericPicker.displayString
66 | }
67 |
68 | // MARK: - Actions
69 | @objc func codeValueChanged() {
70 | codePickerValue.text = codeNumericPicker.displayString
71 | }
72 |
73 | @IBAction func ibValueChanged(_ sender: NumericPicker) {
74 | ibPickerValue.text = sender.displayString
75 | }
76 |
77 | @objc func contentSizeCategoryChanged(_ notification: Notification) {
78 | ibNumericPicker.font = UIFont.preferredFont(forTextStyle: .body)
79 | codeNumericPicker.font = UIFont.preferredFont(forTextStyle: .body)
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/NumericPicker.xcodeproj/xcshareddata/xcschemes/NumericPicker-Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/NumericPicker.xcodeproj/xcshareddata/xcschemes/NumericPicker.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
65 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
84 |
90 |
91 |
92 |
93 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/docs/Classes.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Classes Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 | NumericPicker Reference
22 |
23 | Classes Reference
24 |
25 |
26 |
27 |
39 |
40 |
41 |
42 | Classes
43 | The following classes are available globally.
44 |
45 |
46 |
47 |
48 |
49 |
50 |
57 |
58 |
59 |
60 |
61 |
62 |
NumericPicker is a drop-in iOS picker control written in Swift 3. It makes simplifies the creation of pickers that allow
63 | your users to specify numbers by digit. It automatically uses the proper grouping and decimal separator for the
64 | current (or specified) locale. You can easily dictate the number of integer and decimal places in the controller.
65 |
66 |
67 |
68 |
See more
69 |
70 |
71 |
Declaration
72 |
73 |
Swift
74 |
@IBDesignable public class NumericPicker : UIControl
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/docs/docsets/NumericPicker.docset/Contents/Resources/Documents/Classes.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Classes Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 | NumericPicker Reference
22 |
23 | Classes Reference
24 |
25 |
26 |
27 |
39 |
40 |
41 |
42 | Classes
43 | The following classes are available globally.
44 |
45 |
46 |
47 |
48 |
49 |
50 |
57 |
58 |
59 |
60 |
61 |
62 |
NumericPicker is a drop-in iOS picker control written in Swift 3. It makes simplifies the creation of pickers that allow
63 | your users to specify numbers by digit. It automatically uses the proper grouping and decimal separator for the
64 | current (or specified) locale. You can easily dictate the number of integer and decimal places in the controller.
65 |
66 |
67 |
68 |
See more
69 |
70 |
71 |
Declaration
72 |
73 |
Swift
74 |
@IBDesignable public class NumericPicker : UIControl
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/Tests/NumericPickerTests/NumericPickerUnitTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NumericPickerTests.swift
3 | // NumericPicker
4 | //
5 | // Created by Matthew Lewin on 2/1/17.
6 | // Copyright © 2017 MoGroups
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
16 | // all 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
24 | // THE SOFTWARE.
25 | //
26 |
27 | import XCTest
28 | @testable import NumericPicker
29 |
30 | /// Tests the `NumericPicker` control itself, rather than any discrete functionality.
31 | class NumericPickerTests: XCTestCase {
32 |
33 | class TestingViewController: UIViewController {
34 |
35 | @objc func valueChanged(_ sender: NumericPicker) {
36 | print("[\(#function)]")
37 | }
38 | }
39 |
40 | var vc: TestingViewController!
41 | var picker: NumericPicker!
42 |
43 | override func setUp() {
44 | super.setUp()
45 | vc = TestingViewController()
46 | vc.view.frame = CGRect(origin: CGPoint.zero, size: CGSize.init(width: 64, height: 64))
47 |
48 | picker = NumericPicker()
49 | picker.addTarget(vc, action: #selector(TestingViewController.valueChanged(_:)), for: .valueChanged)
50 | picker.locale = Locale(identifier: "en-US")
51 | picker.font = UIFont.monospacedDigitSystemFont(ofSize: 12, weight: UIFont.Weight.regular)
52 |
53 | vc.view.addSubview(picker)
54 | }
55 |
56 | override func tearDown() {
57 | picker.removeTarget(vc, action: #selector(TestingViewController.valueChanged(_:)), for: .valueChanged)
58 | picker.removeFromSuperview()
59 | picker = nil
60 | vc = nil
61 |
62 | super.tearDown()
63 | }
64 |
65 | func testSetValue() {
66 | picker.value = 1234
67 | XCTAssertEqual(picker.displayString, "1,234")
68 | XCTAssertEqual(picker.componentsString, "1,234")
69 | }
70 |
71 | func testSetMinIntegerDigits() {
72 | picker.value = 1234.1
73 | picker.minIntegerDigits = 6
74 | XCTAssertEqual(picker.displayString, "1,234")
75 | XCTAssertEqual(picker.componentsString, "001,234")
76 | }
77 |
78 | func testFractionDigits() {
79 | picker.value = 1234.567
80 | picker.fractionDigits = 4
81 | XCTAssertEqual(picker.displayString, "1,234.5670")
82 | XCTAssertEqual(picker.componentsString, "1,234.5670")
83 | }
84 |
85 | func testWidthOfPickerSingleComponent() {
86 | picker.value = 1
87 | picker.minIntegerDigits = 1
88 | picker.fractionDigits = 0
89 | XCTAssertEqual(picker.widthOfPickerView(), 16.0)
90 | }
91 |
92 | func testWidthOfPickerTwoIntegerComponents() {
93 | picker.value = 1
94 | picker.minIntegerDigits = 2
95 | picker.fractionDigits = 0
96 | XCTAssertEqual(picker.widthOfPickerView(), 40.0)
97 | }
98 |
99 | func testWidthOfPickerSingleIntSingleDecimal() {
100 | picker.value = 1
101 | picker.minIntegerDigits = 1
102 | picker.fractionDigits = 1
103 | XCTAssertEqual(picker.widthOfPickerView(), 64.0)
104 | }
105 |
106 | func testRowSelection() {
107 | picker.value = 9
108 | picker.minIntegerDigits = 1
109 | picker.fractionDigits = 0
110 | picker.picker.selectRow(2, inComponent: 0, animated: false)
111 | picker.picker.reloadAllComponents()
112 | picker.pickerView(picker.picker, didSelectRow: 2, inComponent: 0)
113 | XCTAssertEqual(picker.displayString, "2")
114 | }
115 | }
116 |
117 |
--------------------------------------------------------------------------------
/docs/search.json:
--------------------------------------------------------------------------------
1 | {"Classes/NumericPicker.html#/s:13NumericPickerAAC4fontSo6UIFontCv":{"name":"font","abstract":"The font for the components of the picker. (defaults to Body)
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/s:13NumericPickerAAC13displayStringSSv":{"name":"displayString","abstract":"displayString is the numeric value selected in the picker without integer zero-padding. It’s read-only and","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(py)intrinsicContentSize":{"name":"intrinsicContentSize","abstract":"
The natural size for the receiving view, considering only properties of the view itself.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/s:13NumericPickerAAC6locale10Foundation6LocaleVv":{"name":"locale","abstract":"The locale used for numeric presentation. (defaults to current locale)
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(py)fractionDigits":{"name":"fractionDigits","abstract":"Number of digits to display to the right of the decimal separator (defaults to 0)
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(py)minIntegerDigits":{"name":"minIntegerDigits","abstract":"Minimum number of digits to display to the left of the decimal separator (defaults to 1)
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(py)minValue":{"name":"minValue","abstract":"Minimum value the picker may be set to (defaults to 0.0)
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(py)value":{"name":"value","abstract":"The numeric value shown in the picker (defaults to 0.0)
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(im)init":{"name":"init()","abstract":"Initializes and returns a newly allocated NumericPicker object with a zero-sized frame rectangle.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(im)initWithCoder:":{"name":"init(coder:)","abstract":"Returns an object initialized from data in a given unarchiver.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(im)initWithFrame:":{"name":"init(frame:)","abstract":"Initializes and returns a newly allocated NumericPicker object with the specified frame rectangle.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@CM@NumericPicker@objc(cs)NumericPicker(im)pickerView:accessibilityLabelForComponent:":{"name":"pickerView(_:accessibilityLabelForComponent:)","abstract":"Undocumented
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@CM@NumericPicker@objc(cs)NumericPicker(im)numberOfComponentsInPickerView:":{"name":"numberOfComponents(in:)","abstract":"Called by the picker view when it needs the number of components.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@CM@NumericPicker@objc(cs)NumericPicker(im)pickerView:numberOfRowsInComponent:":{"name":"pickerView(_:numberOfRowsInComponent:)","abstract":"Called by the picker view when it needs the number of rows for a specified component.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@CM@NumericPicker@objc(cs)NumericPicker(im)pickerView:didSelectRow:inComponent:":{"name":"pickerView(_:didSelectRow:inComponent:)","abstract":"Called by the picker view when the user selects a row in a component.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@CM@NumericPicker@objc(cs)NumericPicker(im)pickerView:titleForRow:forComponent:":{"name":"pickerView(_:titleForRow:forComponent:)","abstract":"Called by the picker view when it needs the title to use for a given row in a given component.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@CM@NumericPicker@objc(cs)NumericPicker(im)pickerView:viewForRow:forComponent:reusingView:":{"name":"pickerView(_:viewForRow:forComponent:reusing:)","abstract":"Called by the picker view when it needs the view to use for a given row in a given component.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@CM@NumericPicker@objc(cs)NumericPicker(im)pickerView:widthForComponent:":{"name":"pickerView(_:widthForComponent:)","abstract":"Called by the picker view when it needs the row width to use for drawing row content.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html":{"name":"NumericPicker","abstract":"NumericPicker is a drop-in iOS picker control written in Swift 3. It makes simplifies the creation of pickers that allow"},"Classes.html":{"name":"Classes","abstract":"
The following classes are available globally.
"}}
--------------------------------------------------------------------------------
/docs/docsets/NumericPicker.docset/Contents/Resources/Documents/search.json:
--------------------------------------------------------------------------------
1 | {"Classes/NumericPicker.html#/s:13NumericPickerAAC4fontSo6UIFontCv":{"name":"font","abstract":"The font for the components of the picker. (defaults to Body)
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/s:13NumericPickerAAC13displayStringSSv":{"name":"displayString","abstract":"displayString is the numeric value selected in the picker without integer zero-padding. It’s read-only and","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(py)intrinsicContentSize":{"name":"intrinsicContentSize","abstract":"
The natural size for the receiving view, considering only properties of the view itself.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/s:13NumericPickerAAC6locale10Foundation6LocaleVv":{"name":"locale","abstract":"The locale used for numeric presentation. (defaults to current locale)
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(py)fractionDigits":{"name":"fractionDigits","abstract":"Number of digits to display to the right of the decimal separator (defaults to 0)
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(py)minIntegerDigits":{"name":"minIntegerDigits","abstract":"Minimum number of digits to display to the left of the decimal separator (defaults to 1)
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(py)minValue":{"name":"minValue","abstract":"Minimum value the picker may be set to (defaults to 0.0)
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(py)value":{"name":"value","abstract":"The numeric value shown in the picker (defaults to 0.0)
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(im)init":{"name":"init()","abstract":"Initializes and returns a newly allocated NumericPicker object with a zero-sized frame rectangle.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(im)initWithCoder:":{"name":"init(coder:)","abstract":"Returns an object initialized from data in a given unarchiver.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@M@NumericPicker@objc(cs)NumericPicker(im)initWithFrame:":{"name":"init(frame:)","abstract":"Initializes and returns a newly allocated NumericPicker object with the specified frame rectangle.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@CM@NumericPicker@objc(cs)NumericPicker(im)pickerView:accessibilityLabelForComponent:":{"name":"pickerView(_:accessibilityLabelForComponent:)","abstract":"Undocumented
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@CM@NumericPicker@objc(cs)NumericPicker(im)numberOfComponentsInPickerView:":{"name":"numberOfComponents(in:)","abstract":"Called by the picker view when it needs the number of components.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@CM@NumericPicker@objc(cs)NumericPicker(im)pickerView:numberOfRowsInComponent:":{"name":"pickerView(_:numberOfRowsInComponent:)","abstract":"Called by the picker view when it needs the number of rows for a specified component.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@CM@NumericPicker@objc(cs)NumericPicker(im)pickerView:didSelectRow:inComponent:":{"name":"pickerView(_:didSelectRow:inComponent:)","abstract":"Called by the picker view when the user selects a row in a component.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@CM@NumericPicker@objc(cs)NumericPicker(im)pickerView:titleForRow:forComponent:":{"name":"pickerView(_:titleForRow:forComponent:)","abstract":"Called by the picker view when it needs the title to use for a given row in a given component.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@CM@NumericPicker@objc(cs)NumericPicker(im)pickerView:viewForRow:forComponent:reusingView:":{"name":"pickerView(_:viewForRow:forComponent:reusing:)","abstract":"Called by the picker view when it needs the view to use for a given row in a given component.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html#/c:@CM@NumericPicker@objc(cs)NumericPicker(im)pickerView:widthForComponent:":{"name":"pickerView(_:widthForComponent:)","abstract":"Called by the picker view when it needs the row width to use for drawing row content.
","parent_name":"NumericPicker"},"Classes/NumericPicker.html":{"name":"NumericPicker","abstract":"NumericPicker is a drop-in iOS picker control written in Swift 3. It makes simplifies the creation of pickers that allow"},"Classes.html":{"name":"Classes","abstract":"
The following classes are available globally.
"}}
--------------------------------------------------------------------------------
/Tests/NumericPickerTests/ComponentsStringTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ComponentsStringTests.swift
3 | // NumericPicker
4 | //
5 | // Created by Matthew Lewin on 1/31/17.
6 | // Copyright © 2017 MoGroups
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
16 | // all 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
24 | // THE SOFTWARE.
25 | //
26 |
27 | import XCTest
28 |
29 | @testable import NumericPicker
30 |
31 | class ComponentsStringTests: XCTestCase {
32 |
33 | static var numericPicker: NumericPicker!
34 | let componentsString: (Double, Int, Int) -> String = {
35 | (value, intDigits, fractionDigits) in
36 | return numericPicker.updatedComponentString(value: value, intDigits: intDigits, fractionDigits: fractionDigits)
37 | }
38 |
39 | override func setUp() {
40 | super.setUp()
41 | ComponentsStringTests.numericPicker = NumericPicker(frame: CGRect.zero)
42 | ComponentsStringTests.numericPicker.locale = Locale(identifier: "en-US")
43 | }
44 |
45 | func testWith0FractionalDigits() {
46 | let fractionDigits = 0
47 |
48 | XCTContext.runActivity(named: "with a single-digit integer value") { _ in
49 | let value = 1.0
50 | let intDigits = 1
51 | XCTAssertEqual(componentsString(value, intDigits, fractionDigits), "1")
52 | }
53 |
54 | XCTContext.runActivity(named: "with three-integer value and single-integer place") { _ in
55 | let value = 123.0
56 | let intDigits = 1
57 | XCTAssertEqual(componentsString(value, intDigits, fractionDigits), "123")
58 | }
59 |
60 | XCTContext.runActivity(named: "with two-integer value padded to three places") { _ in
61 | let value = 12.3
62 | let intDigits = 3
63 | XCTAssertEqual(componentsString(value, intDigits, fractionDigits), "012")
64 | }
65 |
66 | XCTContext.runActivity(named: "with three-integer value padded to six places") { _ in
67 | let value = 123.0
68 | let intDigits = 6
69 | XCTAssertEqual(componentsString(value, intDigits, fractionDigits), "000,123")
70 | }
71 |
72 | XCTContext.runActivity(named: "with nine-integer value padded to ten places") { _ in
73 | let value = 234567890.0
74 | let intDigits = 10
75 | XCTAssertEqual(componentsString(value, intDigits, fractionDigits), "0,234,567,890")
76 | }
77 | }
78 |
79 | func testWith1FractionalDigit() {
80 | let fractionDigits = 1
81 |
82 | XCTContext.runActivity(named: "with a zero integer value and one integer place") { _ in
83 | let value = 0.9
84 | let intDigits = 1
85 | XCTAssertEqual(componentsString(value, intDigits, fractionDigits), "0.9")
86 | }
87 | }
88 |
89 | func testWith3FractionalDigits() {
90 | let fractionDigits = 3
91 |
92 | XCTContext.runActivity(named: "with a three-integer value padded to four places and hundredths padded to thousandths") { _ in
93 | let value = 123.45
94 | let intDigits = 4
95 | XCTAssertEqual(componentsString(value, intDigits, fractionDigits), "0,123.450")
96 | }
97 | }
98 |
99 | func testInFrenchLocale() {
100 | ComponentsStringTests.numericPicker.locale = Locale(identifier: "fr-FR")
101 |
102 | XCTContext.runActivity(named: "with 6 fractional digits") { _ in
103 | let fractionDigits = 6
104 |
105 | XCTContext.runActivity(named: "with a four-integer value padded to six places and six decimal places") { _ in
106 | let value = 1234.5678
107 | let intDigits = 6
108 | XCTAssertEqual(componentsString(value, intDigits, fractionDigits), "001 234,567800")
109 | }
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/NumericPicker-Example/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/docs/css/highlight.css:
--------------------------------------------------------------------------------
1 | /* Credit to https://gist.github.com/wataru420/2048287 */
2 | .highlight {
3 | /* Comment */
4 | /* Error */
5 | /* Keyword */
6 | /* Operator */
7 | /* Comment.Multiline */
8 | /* Comment.Preproc */
9 | /* Comment.Single */
10 | /* Comment.Special */
11 | /* Generic.Deleted */
12 | /* Generic.Deleted.Specific */
13 | /* Generic.Emph */
14 | /* Generic.Error */
15 | /* Generic.Heading */
16 | /* Generic.Inserted */
17 | /* Generic.Inserted.Specific */
18 | /* Generic.Output */
19 | /* Generic.Prompt */
20 | /* Generic.Strong */
21 | /* Generic.Subheading */
22 | /* Generic.Traceback */
23 | /* Keyword.Constant */
24 | /* Keyword.Declaration */
25 | /* Keyword.Pseudo */
26 | /* Keyword.Reserved */
27 | /* Keyword.Type */
28 | /* Literal.Number */
29 | /* Literal.String */
30 | /* Name.Attribute */
31 | /* Name.Builtin */
32 | /* Name.Class */
33 | /* Name.Constant */
34 | /* Name.Entity */
35 | /* Name.Exception */
36 | /* Name.Function */
37 | /* Name.Namespace */
38 | /* Name.Tag */
39 | /* Name.Variable */
40 | /* Operator.Word */
41 | /* Text.Whitespace */
42 | /* Literal.Number.Float */
43 | /* Literal.Number.Hex */
44 | /* Literal.Number.Integer */
45 | /* Literal.Number.Oct */
46 | /* Literal.String.Backtick */
47 | /* Literal.String.Char */
48 | /* Literal.String.Doc */
49 | /* Literal.String.Double */
50 | /* Literal.String.Escape */
51 | /* Literal.String.Heredoc */
52 | /* Literal.String.Interpol */
53 | /* Literal.String.Other */
54 | /* Literal.String.Regex */
55 | /* Literal.String.Single */
56 | /* Literal.String.Symbol */
57 | /* Name.Builtin.Pseudo */
58 | /* Name.Variable.Class */
59 | /* Name.Variable.Global */
60 | /* Name.Variable.Instance */
61 | /* Literal.Number.Integer.Long */ }
62 | .highlight .c {
63 | color: #999988;
64 | font-style: italic; }
65 | .highlight .err {
66 | color: #a61717;
67 | background-color: #e3d2d2; }
68 | .highlight .k {
69 | color: #000000;
70 | font-weight: bold; }
71 | .highlight .o {
72 | color: #000000;
73 | font-weight: bold; }
74 | .highlight .cm {
75 | color: #999988;
76 | font-style: italic; }
77 | .highlight .cp {
78 | color: #999999;
79 | font-weight: bold; }
80 | .highlight .c1 {
81 | color: #999988;
82 | font-style: italic; }
83 | .highlight .cs {
84 | color: #999999;
85 | font-weight: bold;
86 | font-style: italic; }
87 | .highlight .gd {
88 | color: #000000;
89 | background-color: #ffdddd; }
90 | .highlight .gd .x {
91 | color: #000000;
92 | background-color: #ffaaaa; }
93 | .highlight .ge {
94 | color: #000000;
95 | font-style: italic; }
96 | .highlight .gr {
97 | color: #aa0000; }
98 | .highlight .gh {
99 | color: #999999; }
100 | .highlight .gi {
101 | color: #000000;
102 | background-color: #ddffdd; }
103 | .highlight .gi .x {
104 | color: #000000;
105 | background-color: #aaffaa; }
106 | .highlight .go {
107 | color: #888888; }
108 | .highlight .gp {
109 | color: #555555; }
110 | .highlight .gs {
111 | font-weight: bold; }
112 | .highlight .gu {
113 | color: #aaaaaa; }
114 | .highlight .gt {
115 | color: #aa0000; }
116 | .highlight .kc {
117 | color: #000000;
118 | font-weight: bold; }
119 | .highlight .kd {
120 | color: #000000;
121 | font-weight: bold; }
122 | .highlight .kp {
123 | color: #000000;
124 | font-weight: bold; }
125 | .highlight .kr {
126 | color: #000000;
127 | font-weight: bold; }
128 | .highlight .kt {
129 | color: #445588; }
130 | .highlight .m {
131 | color: #009999; }
132 | .highlight .s {
133 | color: #d14; }
134 | .highlight .na {
135 | color: #008080; }
136 | .highlight .nb {
137 | color: #0086B3; }
138 | .highlight .nc {
139 | color: #445588;
140 | font-weight: bold; }
141 | .highlight .no {
142 | color: #008080; }
143 | .highlight .ni {
144 | color: #800080; }
145 | .highlight .ne {
146 | color: #990000;
147 | font-weight: bold; }
148 | .highlight .nf {
149 | color: #990000; }
150 | .highlight .nn {
151 | color: #555555; }
152 | .highlight .nt {
153 | color: #000080; }
154 | .highlight .nv {
155 | color: #008080; }
156 | .highlight .ow {
157 | color: #000000;
158 | font-weight: bold; }
159 | .highlight .w {
160 | color: #bbbbbb; }
161 | .highlight .mf {
162 | color: #009999; }
163 | .highlight .mh {
164 | color: #009999; }
165 | .highlight .mi {
166 | color: #009999; }
167 | .highlight .mo {
168 | color: #009999; }
169 | .highlight .sb {
170 | color: #d14; }
171 | .highlight .sc {
172 | color: #d14; }
173 | .highlight .sd {
174 | color: #d14; }
175 | .highlight .s2 {
176 | color: #d14; }
177 | .highlight .se {
178 | color: #d14; }
179 | .highlight .sh {
180 | color: #d14; }
181 | .highlight .si {
182 | color: #d14; }
183 | .highlight .sx {
184 | color: #d14; }
185 | .highlight .sr {
186 | color: #009926; }
187 | .highlight .s1 {
188 | color: #d14; }
189 | .highlight .ss {
190 | color: #990073; }
191 | .highlight .bp {
192 | color: #999999; }
193 | .highlight .vc {
194 | color: #008080; }
195 | .highlight .vg {
196 | color: #008080; }
197 | .highlight .vi {
198 | color: #008080; }
199 | .highlight .il {
200 | color: #009999; }
201 |
--------------------------------------------------------------------------------
/docs/docsets/NumericPicker.docset/Contents/Resources/Documents/css/highlight.css:
--------------------------------------------------------------------------------
1 | /* Credit to https://gist.github.com/wataru420/2048287 */
2 | .highlight {
3 | /* Comment */
4 | /* Error */
5 | /* Keyword */
6 | /* Operator */
7 | /* Comment.Multiline */
8 | /* Comment.Preproc */
9 | /* Comment.Single */
10 | /* Comment.Special */
11 | /* Generic.Deleted */
12 | /* Generic.Deleted.Specific */
13 | /* Generic.Emph */
14 | /* Generic.Error */
15 | /* Generic.Heading */
16 | /* Generic.Inserted */
17 | /* Generic.Inserted.Specific */
18 | /* Generic.Output */
19 | /* Generic.Prompt */
20 | /* Generic.Strong */
21 | /* Generic.Subheading */
22 | /* Generic.Traceback */
23 | /* Keyword.Constant */
24 | /* Keyword.Declaration */
25 | /* Keyword.Pseudo */
26 | /* Keyword.Reserved */
27 | /* Keyword.Type */
28 | /* Literal.Number */
29 | /* Literal.String */
30 | /* Name.Attribute */
31 | /* Name.Builtin */
32 | /* Name.Class */
33 | /* Name.Constant */
34 | /* Name.Entity */
35 | /* Name.Exception */
36 | /* Name.Function */
37 | /* Name.Namespace */
38 | /* Name.Tag */
39 | /* Name.Variable */
40 | /* Operator.Word */
41 | /* Text.Whitespace */
42 | /* Literal.Number.Float */
43 | /* Literal.Number.Hex */
44 | /* Literal.Number.Integer */
45 | /* Literal.Number.Oct */
46 | /* Literal.String.Backtick */
47 | /* Literal.String.Char */
48 | /* Literal.String.Doc */
49 | /* Literal.String.Double */
50 | /* Literal.String.Escape */
51 | /* Literal.String.Heredoc */
52 | /* Literal.String.Interpol */
53 | /* Literal.String.Other */
54 | /* Literal.String.Regex */
55 | /* Literal.String.Single */
56 | /* Literal.String.Symbol */
57 | /* Name.Builtin.Pseudo */
58 | /* Name.Variable.Class */
59 | /* Name.Variable.Global */
60 | /* Name.Variable.Instance */
61 | /* Literal.Number.Integer.Long */ }
62 | .highlight .c {
63 | color: #999988;
64 | font-style: italic; }
65 | .highlight .err {
66 | color: #a61717;
67 | background-color: #e3d2d2; }
68 | .highlight .k {
69 | color: #000000;
70 | font-weight: bold; }
71 | .highlight .o {
72 | color: #000000;
73 | font-weight: bold; }
74 | .highlight .cm {
75 | color: #999988;
76 | font-style: italic; }
77 | .highlight .cp {
78 | color: #999999;
79 | font-weight: bold; }
80 | .highlight .c1 {
81 | color: #999988;
82 | font-style: italic; }
83 | .highlight .cs {
84 | color: #999999;
85 | font-weight: bold;
86 | font-style: italic; }
87 | .highlight .gd {
88 | color: #000000;
89 | background-color: #ffdddd; }
90 | .highlight .gd .x {
91 | color: #000000;
92 | background-color: #ffaaaa; }
93 | .highlight .ge {
94 | color: #000000;
95 | font-style: italic; }
96 | .highlight .gr {
97 | color: #aa0000; }
98 | .highlight .gh {
99 | color: #999999; }
100 | .highlight .gi {
101 | color: #000000;
102 | background-color: #ddffdd; }
103 | .highlight .gi .x {
104 | color: #000000;
105 | background-color: #aaffaa; }
106 | .highlight .go {
107 | color: #888888; }
108 | .highlight .gp {
109 | color: #555555; }
110 | .highlight .gs {
111 | font-weight: bold; }
112 | .highlight .gu {
113 | color: #aaaaaa; }
114 | .highlight .gt {
115 | color: #aa0000; }
116 | .highlight .kc {
117 | color: #000000;
118 | font-weight: bold; }
119 | .highlight .kd {
120 | color: #000000;
121 | font-weight: bold; }
122 | .highlight .kp {
123 | color: #000000;
124 | font-weight: bold; }
125 | .highlight .kr {
126 | color: #000000;
127 | font-weight: bold; }
128 | .highlight .kt {
129 | color: #445588; }
130 | .highlight .m {
131 | color: #009999; }
132 | .highlight .s {
133 | color: #d14; }
134 | .highlight .na {
135 | color: #008080; }
136 | .highlight .nb {
137 | color: #0086B3; }
138 | .highlight .nc {
139 | color: #445588;
140 | font-weight: bold; }
141 | .highlight .no {
142 | color: #008080; }
143 | .highlight .ni {
144 | color: #800080; }
145 | .highlight .ne {
146 | color: #990000;
147 | font-weight: bold; }
148 | .highlight .nf {
149 | color: #990000; }
150 | .highlight .nn {
151 | color: #555555; }
152 | .highlight .nt {
153 | color: #000080; }
154 | .highlight .nv {
155 | color: #008080; }
156 | .highlight .ow {
157 | color: #000000;
158 | font-weight: bold; }
159 | .highlight .w {
160 | color: #bbbbbb; }
161 | .highlight .mf {
162 | color: #009999; }
163 | .highlight .mh {
164 | color: #009999; }
165 | .highlight .mi {
166 | color: #009999; }
167 | .highlight .mo {
168 | color: #009999; }
169 | .highlight .sb {
170 | color: #d14; }
171 | .highlight .sc {
172 | color: #d14; }
173 | .highlight .sd {
174 | color: #d14; }
175 | .highlight .s2 {
176 | color: #d14; }
177 | .highlight .se {
178 | color: #d14; }
179 | .highlight .sh {
180 | color: #d14; }
181 | .highlight .si {
182 | color: #d14; }
183 | .highlight .sx {
184 | color: #d14; }
185 | .highlight .sr {
186 | color: #009926; }
187 | .highlight .s1 {
188 | color: #d14; }
189 | .highlight .ss {
190 | color: #990073; }
191 | .highlight .bp {
192 | color: #999999; }
193 | .highlight .vc {
194 | color: #008080; }
195 | .highlight .vg {
196 | color: #008080; }
197 | .highlight .vi {
198 | color: #008080; }
199 | .highlight .il {
200 | color: #009999; }
201 |
--------------------------------------------------------------------------------
/Tests/NumericPickerTests/DisplayStringTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DisplayStringTests.swift
3 | // NumericPicker
4 | //
5 | // Created by Matthew Lewin on 1/31/17.
6 | // Copyright © 2017 MoGroups
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
16 | // all 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
24 | // THE SOFTWARE.
25 | //
26 |
27 | import XCTest
28 |
29 | @testable import NumericPicker
30 |
31 | class DisplayStringTests: XCTestCase {
32 |
33 | static var numericPicker: NumericPicker!
34 | let displayString: (Double, Int) -> String = {
35 | (value, fractionDigits) in
36 | return numericPicker.updatedDisplayString(value: value, fractionDigits: fractionDigits)
37 | }
38 |
39 | override func setUp() {
40 | super.setUp()
41 | DisplayStringTests.numericPicker = NumericPicker(frame: CGRect.zero)
42 | DisplayStringTests.numericPicker.locale = Locale(identifier: "en-US")
43 | }
44 |
45 | func testWith0FractionalDigits() {
46 |
47 | let fractionDigits = 0
48 |
49 | XCTContext.runActivity(named: "with a single-digit integer value") { _ in
50 | let value = 1.0
51 | XCTAssertEqual(displayString(value, fractionDigits), "1")
52 | }
53 |
54 | XCTContext.runActivity(named: "with three integers") { _ in
55 | let value = 123.0
56 | XCTAssertEqual(displayString(value, fractionDigits), "123")
57 | }
58 |
59 | XCTContext.runActivity(named: "with the value in tenths place rounded down") { _ in
60 | let value = 123.4
61 | XCTAssertEqual(displayString(value, fractionDigits), "123")
62 | }
63 |
64 | XCTContext.runActivity(named: "with the value in tenths place rounded up") { _ in
65 | let value = 123.6
66 | XCTAssertEqual(displayString(value, fractionDigits), "124")
67 | }
68 |
69 | XCTContext.runActivity(named: "with seven integers") { _ in
70 | let value = 1234567.0
71 | XCTAssertEqual(displayString(value, fractionDigits), "1,234,567")
72 | }
73 |
74 | XCTContext.runActivity(named: "with nine integers") { _ in
75 | let value = 123456789.0
76 | XCTAssertEqual(displayString(value, fractionDigits), "123,456,789")
77 | }
78 |
79 | XCTContext.runActivity(named: "with ten integers") { _ in
80 | let value = 1234567890.0
81 | XCTAssertEqual(displayString(value, fractionDigits), "1,234,567,890")
82 | }
83 |
84 | }
85 |
86 |
87 | func testWith1FractionalDigit() {
88 | let fractionDigits = 1
89 |
90 | XCTContext.runActivity(named: "with zero integer value") { _ in
91 | let value = 0.9
92 | XCTAssertEqual(displayString(value, fractionDigits), "0.9")
93 | }
94 |
95 | XCTContext.runActivity(named: "with four integer digits") { _ in
96 | let value = 1234.5
97 | XCTAssertEqual(displayString(value, fractionDigits), "1,234.5")
98 | }
99 | }
100 |
101 | func testWith3FractionalDigits() {
102 | let fractionDigits = 3
103 |
104 | XCTContext.runActivity(named: "with only tenths in value") { _ in
105 | let value = 123.4
106 | XCTAssertEqual(displayString(value, fractionDigits), "123.400")
107 | }
108 |
109 | XCTContext.runActivity(named: "with only hundredths in value") { _ in
110 | let value = 123.45
111 | XCTAssertEqual(displayString(value, fractionDigits), "123.450")
112 | }
113 |
114 | XCTContext.runActivity(named: "with thousandths in value") { _ in
115 | let value = 123.456
116 | XCTAssertEqual(displayString(value, fractionDigits), "123.456")
117 | }
118 | }
119 |
120 | func testWith4FractionalDigits() {
121 | let fractionDigits = 4
122 |
123 | XCTContext.runActivity(named: "with four integer value") { _ in
124 | let value = 1234.5678
125 | XCTAssertEqual(displayString(value, fractionDigits), "1,234.5678")
126 | }
127 | }
128 |
129 |
130 | func testInFrenchLocale() {
131 | DisplayStringTests.numericPicker.locale = Locale(identifier: "fr-FR")
132 |
133 | XCTContext.runActivity(named: "with 0 fractional digits") { _ in
134 | let fractionDigits = 0
135 |
136 | XCTContext.runActivity(named: "with nine integers") { _ in
137 | let value = 123456789.0
138 | XCTAssertEqual(displayString(value, fractionDigits), "123 456 789")
139 | }
140 |
141 | XCTContext.runActivity(named: "with ten integers") { _ in
142 | let value = 1234567890.0
143 | XCTAssertEqual(displayString(value, fractionDigits), "1 234 567 890")
144 | }
145 |
146 | }
147 |
148 | XCTContext.runActivity(named: "with 4 fractional digits") { _ in
149 | let fractionDigits = 4
150 |
151 | XCTContext.runActivity(named: "with four integers") { _ in
152 | let value = 1234.5678
153 | XCTAssertEqual(displayString(value, fractionDigits), "1 234,5678")
154 | }
155 | }
156 | }
157 | }
158 |
159 | /*
160 | TBD:
161 | - Currency in dollars
162 | - Currency in non-US currency
163 | */
164 |
165 |
--------------------------------------------------------------------------------
/docs/css/jazzy.css:
--------------------------------------------------------------------------------
1 | html, body, div, span, h1, h3, h4, p, a, code, em, img, ul, li, table, tbody, tr, td {
2 | background: transparent;
3 | border: 0;
4 | margin: 0;
5 | outline: 0;
6 | padding: 0;
7 | vertical-align: baseline; }
8 |
9 | body {
10 | background-color: #f2f2f2;
11 | font-family: Helvetica, freesans, Arial, sans-serif;
12 | font-size: 14px;
13 | -webkit-font-smoothing: subpixel-antialiased;
14 | word-wrap: break-word; }
15 |
16 | h1, h2, h3 {
17 | margin-top: 0.8em;
18 | margin-bottom: 0.3em;
19 | font-weight: 100;
20 | color: black; }
21 |
22 | h1 {
23 | font-size: 2.5em; }
24 |
25 | h2 {
26 | font-size: 2em;
27 | border-bottom: 1px solid #e2e2e2; }
28 |
29 | h4 {
30 | font-size: 13px;
31 | line-height: 1.5;
32 | margin-top: 21px; }
33 |
34 | h5 {
35 | font-size: 1.1em; }
36 |
37 | h6 {
38 | font-size: 1.1em;
39 | color: #777; }
40 |
41 | .section-name {
42 | color: gray;
43 | display: block;
44 | font-family: Helvetica;
45 | font-size: 22px;
46 | font-weight: 100;
47 | margin-bottom: 15px; }
48 |
49 | pre, code {
50 | font: 0.95em Menlo, monospace;
51 | color: #777;
52 | word-wrap: normal; }
53 |
54 | p code, li code {
55 | background-color: #eee;
56 | padding: 2px 4px;
57 | border-radius: 4px; }
58 |
59 | a {
60 | color: #0088cc;
61 | text-decoration: none; }
62 |
63 | ul {
64 | padding-left: 15px; }
65 |
66 | li {
67 | line-height: 1.8em; }
68 |
69 | img {
70 | max-width: 100%; }
71 |
72 | blockquote {
73 | margin-left: 0;
74 | padding: 0 10px;
75 | border-left: 4px solid #ccc; }
76 |
77 | .content-wrapper {
78 | margin: 0 auto;
79 | width: 980px; }
80 |
81 | header {
82 | font-size: 0.85em;
83 | line-height: 26px;
84 | background-color: #414141;
85 | position: fixed;
86 | width: 100%;
87 | z-index: 1; }
88 | header img {
89 | padding-right: 6px;
90 | vertical-align: -4px;
91 | height: 16px; }
92 | header a {
93 | color: #fff; }
94 | header p {
95 | float: left;
96 | color: #999; }
97 | header .header-right {
98 | float: right;
99 | margin-left: 16px; }
100 |
101 | #breadcrumbs {
102 | background-color: #f2f2f2;
103 | height: 27px;
104 | padding-top: 17px;
105 | position: fixed;
106 | width: 100%;
107 | z-index: 1;
108 | margin-top: 26px; }
109 | #breadcrumbs #carat {
110 | height: 10px;
111 | margin: 0 5px; }
112 |
113 | .sidebar {
114 | background-color: #f9f9f9;
115 | border: 1px solid #e2e2e2;
116 | overflow-y: auto;
117 | overflow-x: hidden;
118 | position: fixed;
119 | top: 70px;
120 | bottom: 0;
121 | width: 230px;
122 | word-wrap: normal; }
123 |
124 | .nav-groups {
125 | list-style-type: none;
126 | background: #fff;
127 | padding-left: 0; }
128 |
129 | .nav-group-name {
130 | border-bottom: 1px solid #e2e2e2;
131 | font-size: 1.1em;
132 | font-weight: 100;
133 | padding: 15px 0 15px 20px; }
134 | .nav-group-name > a {
135 | color: #333; }
136 |
137 | .nav-group-tasks {
138 | margin-top: 5px; }
139 |
140 | .nav-group-task {
141 | font-size: 0.9em;
142 | list-style-type: none;
143 | white-space: nowrap; }
144 | .nav-group-task a {
145 | color: #888; }
146 |
147 | .main-content {
148 | background-color: #fff;
149 | border: 1px solid #e2e2e2;
150 | margin-left: 246px;
151 | position: absolute;
152 | overflow: hidden;
153 | padding-bottom: 60px;
154 | top: 70px;
155 | width: 734px; }
156 | .main-content p, .main-content a, .main-content code, .main-content em, .main-content ul, .main-content table, .main-content blockquote {
157 | margin-bottom: 1em; }
158 | .main-content p {
159 | line-height: 1.8em; }
160 | .main-content section .section:first-child {
161 | margin-top: 0;
162 | padding-top: 0; }
163 | .main-content section .task-group-section .task-group:first-of-type {
164 | padding-top: 10px; }
165 | .main-content section .task-group-section .task-group:first-of-type .section-name {
166 | padding-top: 15px; }
167 | .main-content section .heading:before {
168 | content: "";
169 | display: block;
170 | padding-top: 70px;
171 | margin: -70px 0 0; }
172 |
173 | .section {
174 | padding: 0 25px; }
175 |
176 | .highlight {
177 | background-color: #eee;
178 | padding: 10px 12px;
179 | border: 1px solid #e2e2e2;
180 | border-radius: 4px;
181 | overflow-x: auto; }
182 |
183 | .declaration .highlight {
184 | overflow-x: initial;
185 | padding: 0 40px 40px 0;
186 | margin-bottom: -25px;
187 | background-color: transparent;
188 | border: none; }
189 |
190 | .section-name {
191 | margin: 0;
192 | margin-left: 18px; }
193 |
194 | .task-group-section {
195 | padding-left: 6px;
196 | border-top: 1px solid #e2e2e2; }
197 |
198 | .task-group {
199 | padding-top: 0px; }
200 |
201 | .task-name-container a[name]:before {
202 | content: "";
203 | display: block;
204 | padding-top: 70px;
205 | margin: -70px 0 0; }
206 |
207 | .item {
208 | padding-top: 8px;
209 | width: 100%;
210 | list-style-type: none; }
211 | .item a[name]:before {
212 | content: "";
213 | display: block;
214 | padding-top: 70px;
215 | margin: -70px 0 0; }
216 | .item code {
217 | background-color: transparent;
218 | padding: 0; }
219 | .item .token {
220 | padding-left: 3px;
221 | margin-left: 15px;
222 | font-size: 11.9px; }
223 | .item .declaration-note {
224 | font-size: .85em;
225 | color: gray;
226 | font-style: italic; }
227 |
228 | .pointer-container {
229 | border-bottom: 1px solid #e2e2e2;
230 | left: -23px;
231 | padding-bottom: 13px;
232 | position: relative;
233 | width: 110%; }
234 |
235 | .pointer {
236 | background: #f9f9f9;
237 | border-left: 1px solid #e2e2e2;
238 | border-top: 1px solid #e2e2e2;
239 | height: 12px;
240 | left: 21px;
241 | top: -7px;
242 | -webkit-transform: rotate(45deg);
243 | -moz-transform: rotate(45deg);
244 | -o-transform: rotate(45deg);
245 | transform: rotate(45deg);
246 | position: absolute;
247 | width: 12px; }
248 |
249 | .height-container {
250 | display: none;
251 | left: -25px;
252 | padding: 0 25px;
253 | position: relative;
254 | width: 100%;
255 | overflow: hidden; }
256 | .height-container .section {
257 | background: #f9f9f9;
258 | border-bottom: 1px solid #e2e2e2;
259 | left: -25px;
260 | position: relative;
261 | width: 100%;
262 | padding-top: 10px;
263 | padding-bottom: 5px; }
264 |
265 | .aside, .language {
266 | padding: 6px 12px;
267 | margin: 12px 0;
268 | border-left: 5px solid #dddddd;
269 | overflow-y: hidden; }
270 | .aside .aside-title, .language .aside-title {
271 | font-size: 9px;
272 | letter-spacing: 2px;
273 | text-transform: uppercase;
274 | padding-bottom: 0;
275 | margin: 0;
276 | color: #aaa;
277 | -webkit-user-select: none; }
278 | .aside p:last-child, .language p:last-child {
279 | margin-bottom: 0; }
280 |
281 | .language {
282 | border-left: 5px solid #cde9f4; }
283 | .language .aside-title {
284 | color: #4b8afb; }
285 |
286 | .aside-warning {
287 | border-left: 5px solid #ff6666; }
288 | .aside-warning .aside-title {
289 | color: #ff0000; }
290 |
291 | .graybox {
292 | border-collapse: collapse;
293 | width: 100%; }
294 | .graybox p {
295 | margin: 0;
296 | word-break: break-word;
297 | min-width: 50px; }
298 | .graybox td {
299 | border: 1px solid #e2e2e2;
300 | padding: 5px 25px 5px 10px;
301 | vertical-align: middle; }
302 | .graybox tr td:first-of-type {
303 | text-align: right;
304 | padding: 7px;
305 | vertical-align: top;
306 | word-break: normal;
307 | width: 40px; }
308 |
309 | .slightly-smaller {
310 | font-size: 0.9em; }
311 |
312 | #footer {
313 | position: absolute;
314 | bottom: 10px;
315 | margin-left: 25px; }
316 | #footer p {
317 | margin: 0;
318 | color: #aaa;
319 | font-size: 0.8em; }
320 |
321 | html.dash header, html.dash #breadcrumbs, html.dash .sidebar {
322 | display: none; }
323 | html.dash .main-content {
324 | width: 980px;
325 | margin-left: 0;
326 | border: none;
327 | width: 100%;
328 | top: 0;
329 | padding-bottom: 0; }
330 | html.dash .height-container {
331 | display: block; }
332 | html.dash .item .token {
333 | margin-left: 0; }
334 | html.dash .content-wrapper {
335 | width: auto; }
336 | html.dash #footer {
337 | position: static; }
338 |
--------------------------------------------------------------------------------
/docs/docsets/NumericPicker.docset/Contents/Resources/Documents/css/jazzy.css:
--------------------------------------------------------------------------------
1 | html, body, div, span, h1, h3, h4, p, a, code, em, img, ul, li, table, tbody, tr, td {
2 | background: transparent;
3 | border: 0;
4 | margin: 0;
5 | outline: 0;
6 | padding: 0;
7 | vertical-align: baseline; }
8 |
9 | body {
10 | background-color: #f2f2f2;
11 | font-family: Helvetica, freesans, Arial, sans-serif;
12 | font-size: 14px;
13 | -webkit-font-smoothing: subpixel-antialiased;
14 | word-wrap: break-word; }
15 |
16 | h1, h2, h3 {
17 | margin-top: 0.8em;
18 | margin-bottom: 0.3em;
19 | font-weight: 100;
20 | color: black; }
21 |
22 | h1 {
23 | font-size: 2.5em; }
24 |
25 | h2 {
26 | font-size: 2em;
27 | border-bottom: 1px solid #e2e2e2; }
28 |
29 | h4 {
30 | font-size: 13px;
31 | line-height: 1.5;
32 | margin-top: 21px; }
33 |
34 | h5 {
35 | font-size: 1.1em; }
36 |
37 | h6 {
38 | font-size: 1.1em;
39 | color: #777; }
40 |
41 | .section-name {
42 | color: gray;
43 | display: block;
44 | font-family: Helvetica;
45 | font-size: 22px;
46 | font-weight: 100;
47 | margin-bottom: 15px; }
48 |
49 | pre, code {
50 | font: 0.95em Menlo, monospace;
51 | color: #777;
52 | word-wrap: normal; }
53 |
54 | p code, li code {
55 | background-color: #eee;
56 | padding: 2px 4px;
57 | border-radius: 4px; }
58 |
59 | a {
60 | color: #0088cc;
61 | text-decoration: none; }
62 |
63 | ul {
64 | padding-left: 15px; }
65 |
66 | li {
67 | line-height: 1.8em; }
68 |
69 | img {
70 | max-width: 100%; }
71 |
72 | blockquote {
73 | margin-left: 0;
74 | padding: 0 10px;
75 | border-left: 4px solid #ccc; }
76 |
77 | .content-wrapper {
78 | margin: 0 auto;
79 | width: 980px; }
80 |
81 | header {
82 | font-size: 0.85em;
83 | line-height: 26px;
84 | background-color: #414141;
85 | position: fixed;
86 | width: 100%;
87 | z-index: 1; }
88 | header img {
89 | padding-right: 6px;
90 | vertical-align: -4px;
91 | height: 16px; }
92 | header a {
93 | color: #fff; }
94 | header p {
95 | float: left;
96 | color: #999; }
97 | header .header-right {
98 | float: right;
99 | margin-left: 16px; }
100 |
101 | #breadcrumbs {
102 | background-color: #f2f2f2;
103 | height: 27px;
104 | padding-top: 17px;
105 | position: fixed;
106 | width: 100%;
107 | z-index: 1;
108 | margin-top: 26px; }
109 | #breadcrumbs #carat {
110 | height: 10px;
111 | margin: 0 5px; }
112 |
113 | .sidebar {
114 | background-color: #f9f9f9;
115 | border: 1px solid #e2e2e2;
116 | overflow-y: auto;
117 | overflow-x: hidden;
118 | position: fixed;
119 | top: 70px;
120 | bottom: 0;
121 | width: 230px;
122 | word-wrap: normal; }
123 |
124 | .nav-groups {
125 | list-style-type: none;
126 | background: #fff;
127 | padding-left: 0; }
128 |
129 | .nav-group-name {
130 | border-bottom: 1px solid #e2e2e2;
131 | font-size: 1.1em;
132 | font-weight: 100;
133 | padding: 15px 0 15px 20px; }
134 | .nav-group-name > a {
135 | color: #333; }
136 |
137 | .nav-group-tasks {
138 | margin-top: 5px; }
139 |
140 | .nav-group-task {
141 | font-size: 0.9em;
142 | list-style-type: none;
143 | white-space: nowrap; }
144 | .nav-group-task a {
145 | color: #888; }
146 |
147 | .main-content {
148 | background-color: #fff;
149 | border: 1px solid #e2e2e2;
150 | margin-left: 246px;
151 | position: absolute;
152 | overflow: hidden;
153 | padding-bottom: 60px;
154 | top: 70px;
155 | width: 734px; }
156 | .main-content p, .main-content a, .main-content code, .main-content em, .main-content ul, .main-content table, .main-content blockquote {
157 | margin-bottom: 1em; }
158 | .main-content p {
159 | line-height: 1.8em; }
160 | .main-content section .section:first-child {
161 | margin-top: 0;
162 | padding-top: 0; }
163 | .main-content section .task-group-section .task-group:first-of-type {
164 | padding-top: 10px; }
165 | .main-content section .task-group-section .task-group:first-of-type .section-name {
166 | padding-top: 15px; }
167 | .main-content section .heading:before {
168 | content: "";
169 | display: block;
170 | padding-top: 70px;
171 | margin: -70px 0 0; }
172 |
173 | .section {
174 | padding: 0 25px; }
175 |
176 | .highlight {
177 | background-color: #eee;
178 | padding: 10px 12px;
179 | border: 1px solid #e2e2e2;
180 | border-radius: 4px;
181 | overflow-x: auto; }
182 |
183 | .declaration .highlight {
184 | overflow-x: initial;
185 | padding: 0 40px 40px 0;
186 | margin-bottom: -25px;
187 | background-color: transparent;
188 | border: none; }
189 |
190 | .section-name {
191 | margin: 0;
192 | margin-left: 18px; }
193 |
194 | .task-group-section {
195 | padding-left: 6px;
196 | border-top: 1px solid #e2e2e2; }
197 |
198 | .task-group {
199 | padding-top: 0px; }
200 |
201 | .task-name-container a[name]:before {
202 | content: "";
203 | display: block;
204 | padding-top: 70px;
205 | margin: -70px 0 0; }
206 |
207 | .item {
208 | padding-top: 8px;
209 | width: 100%;
210 | list-style-type: none; }
211 | .item a[name]:before {
212 | content: "";
213 | display: block;
214 | padding-top: 70px;
215 | margin: -70px 0 0; }
216 | .item code {
217 | background-color: transparent;
218 | padding: 0; }
219 | .item .token {
220 | padding-left: 3px;
221 | margin-left: 15px;
222 | font-size: 11.9px; }
223 | .item .declaration-note {
224 | font-size: .85em;
225 | color: gray;
226 | font-style: italic; }
227 |
228 | .pointer-container {
229 | border-bottom: 1px solid #e2e2e2;
230 | left: -23px;
231 | padding-bottom: 13px;
232 | position: relative;
233 | width: 110%; }
234 |
235 | .pointer {
236 | background: #f9f9f9;
237 | border-left: 1px solid #e2e2e2;
238 | border-top: 1px solid #e2e2e2;
239 | height: 12px;
240 | left: 21px;
241 | top: -7px;
242 | -webkit-transform: rotate(45deg);
243 | -moz-transform: rotate(45deg);
244 | -o-transform: rotate(45deg);
245 | transform: rotate(45deg);
246 | position: absolute;
247 | width: 12px; }
248 |
249 | .height-container {
250 | display: none;
251 | left: -25px;
252 | padding: 0 25px;
253 | position: relative;
254 | width: 100%;
255 | overflow: hidden; }
256 | .height-container .section {
257 | background: #f9f9f9;
258 | border-bottom: 1px solid #e2e2e2;
259 | left: -25px;
260 | position: relative;
261 | width: 100%;
262 | padding-top: 10px;
263 | padding-bottom: 5px; }
264 |
265 | .aside, .language {
266 | padding: 6px 12px;
267 | margin: 12px 0;
268 | border-left: 5px solid #dddddd;
269 | overflow-y: hidden; }
270 | .aside .aside-title, .language .aside-title {
271 | font-size: 9px;
272 | letter-spacing: 2px;
273 | text-transform: uppercase;
274 | padding-bottom: 0;
275 | margin: 0;
276 | color: #aaa;
277 | -webkit-user-select: none; }
278 | .aside p:last-child, .language p:last-child {
279 | margin-bottom: 0; }
280 |
281 | .language {
282 | border-left: 5px solid #cde9f4; }
283 | .language .aside-title {
284 | color: #4b8afb; }
285 |
286 | .aside-warning {
287 | border-left: 5px solid #ff6666; }
288 | .aside-warning .aside-title {
289 | color: #ff0000; }
290 |
291 | .graybox {
292 | border-collapse: collapse;
293 | width: 100%; }
294 | .graybox p {
295 | margin: 0;
296 | word-break: break-word;
297 | min-width: 50px; }
298 | .graybox td {
299 | border: 1px solid #e2e2e2;
300 | padding: 5px 25px 5px 10px;
301 | vertical-align: middle; }
302 | .graybox tr td:first-of-type {
303 | text-align: right;
304 | padding: 7px;
305 | vertical-align: top;
306 | word-break: normal;
307 | width: 40px; }
308 |
309 | .slightly-smaller {
310 | font-size: 0.9em; }
311 |
312 | #footer {
313 | position: absolute;
314 | bottom: 10px;
315 | margin-left: 25px; }
316 | #footer p {
317 | margin: 0;
318 | color: #aaa;
319 | font-size: 0.8em; }
320 |
321 | html.dash header, html.dash #breadcrumbs, html.dash .sidebar {
322 | display: none; }
323 | html.dash .main-content {
324 | width: 980px;
325 | margin-left: 0;
326 | border: none;
327 | width: 100%;
328 | top: 0;
329 | padding-bottom: 0; }
330 | html.dash .height-container {
331 | display: block; }
332 | html.dash .item .token {
333 | margin-left: 0; }
334 | html.dash .content-wrapper {
335 | width: auto; }
336 | html.dash #footer {
337 | position: static; }
338 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NumericPicker
2 |
3 | [](http://cocoapods.org/pods/NumericPicker)
4 | [](http://cocoapods.org/pods/NumericPicker)
5 | [](http://cocoapods.org/pods/NumericPicker)
6 | [](https://swift.org)
7 | [](https://travis-ci.org/MattLewin/NumericPicker)
8 |
9 | [](https://cocoapods.org/pods/NumericPicker)
10 | [](https://github.com/Carthage/Carthage)
11 | [](https://swift.org/package-manager/)
12 |
13 | [](https://github.com/MattLewin/NumericPicker/releases)
14 |
15 | ## Description
16 |
17 | NumericPicker is a drop-in iOS picker control written in Swift. It simplifies the creation of pickers that allow
18 | your users to specify numbers by digit. It automatically uses the proper grouping and decimal separator for the
19 | current (or specified) locale. You can easily dictate the number of integer and decimal places in the controller.
20 |
21 | 
22 |
23 | *Note that the "Picker Value" field is there for demonstration purposes only. It is not included in the
24 | `NumericPicker` control.*
25 |
26 | ---
27 |
28 | ## Table of Contents
29 |
30 | * [Example](#example)
31 | * [Minimum Requirements](#minimum-requirements)
32 | * [Installation](#installation)
33 | * [Usage](#usage)
34 | * [Author](#author)
35 | * [License](#license)
36 |
37 | ---
38 |
39 | ## Minimum Requirements
40 | ### Version 1.1.x
41 | * Xcode 10
42 | * iOS 10.3
43 | * Swift 4.2
44 |
45 | ### Version 1.0.x
46 | * Xcode 9
47 | * iOS 10.3
48 |
49 | ## Example
50 |
51 | This repo contains an example project demonstrating how to use the `NumericPicker` control from Interface Builder and
52 | from code.
53 |
54 | To run the example project, clone the repo, open `NumericPicker.xcodeproj` and run the `NumericPicker-Example` scheme
55 |
56 | ## Installation
57 |
58 | ### CocoaPods
59 |
60 | NumericPicker is available through [CocoaPods](http://cocoapods.org).
61 |
62 | [CocoaPods](http://cocoapods.org) is a dependency manager for Swift and Objective-C that simplifies the use of 3rd-party
63 | libraries like `NumericPicker` in your projects.
64 |
65 | First, add the following line to your [Podfile](http://guides.cocoapods.org/using/using-cocoapods.html):
66 |
67 | ```ruby
68 | pod "NumericPicker"
69 | ```
70 |
71 | or, for Xcode 9 and Swift 4.0
72 |
73 | ```ruby
74 | pod "NumericPicker", '~> 1.0.0'
75 | ```
76 |
77 | Second, install `NumericPicker` into your project:
78 |
79 | ```bash
80 | pod install
81 | ```
82 |
83 | ### Carthage
84 |
85 | [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and
86 | provides you with binary frameworks.
87 |
88 | To integrate `NumericPicker` into your Xcode project using Carthage, specify it in your `Cartfile`:
89 |
90 | ```ruby
91 | github "MattLewin/NumericPicker"
92 | ```
93 |
94 | or, for Xcode 9 and Swift 4.0
95 |
96 | ```ruby
97 | github "MattLewin/NumericPicker" ~> 1.0.0
98 | ```
99 |
100 | Run `carthage update` to build the framework and drag the built `NumericPicker.framework` (in Carthage/Build/iOS folder)
101 | into your Xcode project (Linked Frameworks and Libraries in `Targets`).
102 |
103 | ### Swift Package Manager (SPM)
104 |
105 | The [Swift Package Manager](https://github.com/apple/swift-package-manager) does not yet support importing `UIKit` or compilation for
106 | `iOS`. Thus, `NumericPicker` can not yet be used with the SPM.
107 |
108 | ### Manually
109 |
110 | 1. Copy `NumericPicker.swift` into your project
111 | 2. Have a nice day
112 |
113 | ## Usage
114 |
115 | `NumericPicker` is a subclass of [`UIControl`](https://developer.apple.com/reference/uikit/uicontrol). In this way it
116 | is more like [`UIDatePicker`](https://developer.apple.com/reference/uikit/uidatepicker) than it is like
117 | [`UIPickerView`](https://developer.apple.com/reference/uikit/uipickerview). What this means for you is that you don't
118 | need to implement [`UIPickerViewDataSource`](https://developer.apple.com/reference/uikit/uipickerviewdatasource) or
119 | [`UIPickerViewDelegate`](https://developer.apple.com/reference/uikit/uipickerviewdelegate).
120 |
121 | *Note that the provided [Example](#example) demonstrates everything detailed below.*
122 |
123 | ### Configurable Properties
124 |
125 | * `value: Double` - The value displayed in the picker. Set this value to update the picker programatically.
126 | *(Default: 0)*
127 | * `minIntegerDigits: Int` - The minimum number of integer digits (digits to the left of the decimal separator) to
128 | include in the picker. Think of this as zero-padding the picker. If `value` requires more than this minimum, the picker
129 | will automatically meet this requirement. (This is probably not what you want, though.) *(Default: 1)*
130 | * `fractionDigits: Int` - The number of digits to the right of the decimal separator. `NumericPicker` guarantees
131 | exactly this many fractional digits will be displayed. You can use this to achieve rounding or zero-padding of values
132 | to the right of the decimal separator. *(Default: 0)*
133 | * `locale: Locale` - The locale used to format the numeric values. Use this if you want numbers formatted with
134 | separators other than those used by the device locale. *(Default: current device locale)*
135 | * `font: UIFont` - The font used to format the picker components. *(Default: `Body` text style)*
136 | * `displayString: String` - **READ ONLY** - The text representation of `value`. This string will contain locale-specific
137 | grouping and decimal separators. It will have exactly `fractionDigits` digits to the right of the decimal separator and
138 | the minimum number of integer places necessary to represent `value`.
139 |
140 |
141 | ### Interface Builder
142 |
143 | To use `NumericPicker` with Interface Builder, add a [`UIControl`](https://developer.apple.com/reference/uikit/uicontrol)
144 | to your storyboard or XIB, and then set the "Custom Class" to `NumericPicker`. Connect the "`Value Changed`" event to
145 | a function in your view controller. (Be certain to set the "Type" to `NumericPicker` as shown below.)
146 |
147 | 
148 |
149 | Within that function, you can access `sender.displayString` or `sender.value` as needed.
150 |
151 |
152 | #### *Cocoapods or Manually*
153 |
154 | If you are using Cocoapods or have dropped `NumericPicker.swift` into your code, you can configure `value`,
155 | `minIntegerDigits`, and `fractionDigits` from the "Attributes" inspector.
156 |
157 | 
158 |
159 | #### *Carthage*
160 |
161 | Xcode does not currently (as of 9.0) support `@IBInspectable` properties from external frameworks. The means
162 | you cannot configure the above properties in IB. You can, however, trick IB into rendering `NumericPicker` with its
163 | default values by adding the following code to one of your view controllers:
164 |
165 | ```swift
166 | @IBDesignable extension NumericPicker { }
167 | ```
168 |
169 | ### Code
170 |
171 | Add a `NumericPicker` control from code as you would any other subview. Here is the code from
172 | `NumericPicker-Example/ViewController.swift` to produce the bottom sample `NumericPicker`. Note that it is typically unnecessary
173 | to set `locale`, as `NumericPicker` will use the current device locale by default.
174 |
175 | ```swift
176 | var codeNumericPicker = NumericPicker()
177 | codeNumericPicker.minIntegerDigits = 6
178 | codeNumericPicker.fractionDigits = 3
179 | codeNumericPicker.value = 76543.21
180 | codeNumericPicker.locale = Locale(identifier: "de-DE")
181 | codeNumericPicker.addTarget(self, action: #selector(codeValueChanged), for: .valueChanged)
182 | codePickerStack.addArrangedSubview(codeNumericPicker)
183 |
184 | ```
185 |
186 | ## Author
187 |
188 | Matt Lewin, matt@mogroups.com
189 |
190 | ## License
191 |
192 | NumericPicker is available under the MIT license. See [LICENSE.md](https://raw.githubusercontent.com/MattLewin/NumericPicker/master/LICENSE.md)
193 | for more info.
194 |
195 |
196 |
197 |
198 |
--------------------------------------------------------------------------------
/NumericPicker-Example/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | NumericPicker Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 | NumericPicker Reference
22 |
23 | NumericPicker Reference
24 |
25 |
26 |
27 |
39 |
40 |
41 |
42 |
43 | NumericPicker
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | Description
57 |
58 | NumericPicker is a drop-in iOS picker control written in Swift 4. It simplifies the creation of pickers that allow
59 | your users to specify numbers by digit. It automatically uses the proper grouping and decimal separator for the
60 | current (or specified) locale. You can easily dictate the number of integer and decimal places in the controller.
61 |
62 |
63 |
64 | Note that the Picker Value field is there for demonstration purposes only. It is not included in the
65 | NumericPicker control.
66 |
67 |
68 | Table of Contents
69 |
70 |
78 |
79 |
80 | Minimum Requirements
81 |
82 |
83 | Xcode 9.0+
84 | iOS 10.3+
85 |
86 | Example
87 |
88 | This repo contains an example project demonstrating how to use the NumericPicker control from Interface Builder and
89 | from code.
90 |
91 | To run the example project, clone the repo, open NumericPicker.xcodeproj and run the NumericPicker-Example scheme
92 | Installation
93 | CocoaPods
94 |
95 | NumericPicker is available through CocoaPods .
96 |
97 | CocoaPods is a dependency manager for Swift and Objective-C that simplifies the use of 3rd-party
98 | libraries like NumericPicker in your projects.
99 |
100 | First, add the following line to your Podfile :
101 | pod "NumericPicker"
102 |
103 |
104 | Second, install NumericPicker into your project:
105 | pod install
106 |
107 | Carthage
108 |
109 | Carthage is a decentralized dependency manager that builds your dependencies and
110 | provides you with binary frameworks.
111 |
112 | To integrate NumericPicker into your Xcode project using Carthage, specify it in your Cartfile:
113 | github "MattLewin/NumericPicker"
114 |
115 |
116 | Run carthage update to build the framework and drag the built NumericPicker.framework (in Carthage/Build/iOS folder)
117 | into your Xcode project (Linked Frameworks and Libraries in Targets).
118 | Swift Package Manager (SPM)
119 |
120 | The Swift Package Manager does not yet support importing UIKit or compilation for
121 | iOS. Thus, NumericPicker can not yet be used with the SPM.
122 | Manually
123 |
124 |
125 | Copy NumericPicker.swift into your project
126 | Have a nice day
127 |
128 | Usage
129 |
130 | NumericPicker is a subclass of UIControl . In this way it
131 | is more like UIDatePicker than it is like
132 | UIPickerView . What this means for you is that you don’t
133 | need to implement UIPickerViewDataSource or
134 | UIPickerViewDelegate .
135 |
136 | Note that the provided Example demonstrates everything detailed below.
137 | Configurable Properties
138 |
139 |
140 | value: Double - The value displayed in the picker. Set this value to update the picker programatically.
141 | (Default: 0)
142 | minIntegerDigits: Int - The minimum number of integer digits (digits to the left of the decimal separator) to
143 | include in the picker. Think of this as zero-padding the picker. If value requires more than this minimum, the picker
144 | will automatically meet this requirement. (This is probably not what you want, though.) (Default: 1)
145 | fractionDigits: Int - The number of digits to the right of the decimal separator. NumericPicker guarantees
146 | exactly this many fractional digits will be displayed. You can use this to achieve rounding or zero-padding of values
147 | to the right of the decimal separator. (Default: 0)
148 | locale: Locale - The locale used to format the numeric values. Use this if you want numbers formatted with
149 | separators other than those used by the device locale. (Default: current device locale)
150 | font: UIFont - The font used to format the picker components. (Default: Body text style)
151 | displayString: String - READ ONLY - The text representation of value. This string will contain locale-specific
152 | grouping and decimal separators. It will have exactly fractionDigits digits to the right of the decimal separator and
153 | the minimum number of integer places necessary to represent value.
154 |
155 | Interface Builder
156 |
157 | To use NumericPicker with Interface Builder, add a UIControl
158 | to your storyboard or XIB, and then set the Custom Class to NumericPicker . Connect the `Value Changed` event to
159 | a function in your view controller. (Be certain to set the Type to NumericPicker as shown below.)
160 |
161 |
162 |
163 | Within that function, you can access sender.displayString or sender.value as needed.
164 | Cocoapods or Manually
165 |
166 | If you are using Cocoapods or have dropped NumericPicker.swift into your code, you can configure value,
167 | minIntegerDigits, and fractionDigits from the Attributes inspector.
168 |
169 |
170 | Carthage
171 |
172 | Xcode does not currently (as of 9.0) support @IBInspectable properties from external frameworks. The means
173 | you cannot configure the above properties in IB. You can, however, trick IB into rendering NumericPicker with its
174 | default values by adding the following code to one of your view controllers:
175 | @IBDesignable extension NumericPicker { }
176 |
177 | Code
178 |
179 | Add a NumericPicker control from code as you would any other subview. Here is the code from
180 | NumericPicker-Example/ViewController.swift to produce the bottom sample NumericPicker . Note that it is typically unnecessary
181 | to set locale, as NumericPicker will use the current device locale by default.
182 | var codeNumericPicker = NumericPicker ()
183 | codeNumericPicker . minIntegerDigits = 6
184 | codeNumericPicker . fractionDigits = 3
185 | codeNumericPicker . value = 76543.21
186 | codeNumericPicker . locale = Locale ( identifier : "de-DE" )
187 | codeNumericPicker . addTarget ( self , action : #selector( codeValueChanged ) , for : . valueChanged )
188 | codePickerStack . addArrangedSubview ( codeNumericPicker )
189 |
190 |
191 | Author
192 |
193 | Matt Lewin, matt@mogroups.com
194 | License
195 |
196 | NumericPicker is available under the MIT license. See LICENSE.md
197 | for more info.
198 |
199 |
200 |
201 |
205 |
206 |
207 |
208 |
209 |
210 |
--------------------------------------------------------------------------------
/docs/docsets/NumericPicker.docset/Contents/Resources/Documents/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | NumericPicker Reference
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 | NumericPicker Reference
22 |
23 | NumericPicker Reference
24 |
25 |
26 |
27 |
39 |
40 |
41 |
42 |
43 | NumericPicker
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | Description
57 |
58 | NumericPicker is a drop-in iOS picker control written in Swift 4. It simplifies the creation of pickers that allow
59 | your users to specify numbers by digit. It automatically uses the proper grouping and decimal separator for the
60 | current (or specified) locale. You can easily dictate the number of integer and decimal places in the controller.
61 |
62 |
63 |
64 | Note that the Picker Value field is there for demonstration purposes only. It is not included in the
65 | NumericPicker control.
66 |
67 |
68 | Table of Contents
69 |
70 |
78 |
79 |
80 | Minimum Requirements
81 |
82 |
83 | Xcode 9.0+
84 | iOS 10.3+
85 |
86 | Example
87 |
88 | This repo contains an example project demonstrating how to use the NumericPicker control from Interface Builder and
89 | from code.
90 |
91 | To run the example project, clone the repo, open NumericPicker.xcodeproj and run the NumericPicker-Example scheme
92 | Installation
93 | CocoaPods
94 |
95 | NumericPicker is available through CocoaPods .
96 |
97 | CocoaPods is a dependency manager for Swift and Objective-C that simplifies the use of 3rd-party
98 | libraries like NumericPicker in your projects.
99 |
100 | First, add the following line to your Podfile :
101 | pod "NumericPicker"
102 |
103 |
104 | Second, install NumericPicker into your project:
105 | pod install
106 |
107 | Carthage
108 |
109 | Carthage is a decentralized dependency manager that builds your dependencies and
110 | provides you with binary frameworks.
111 |
112 | To integrate NumericPicker into your Xcode project using Carthage, specify it in your Cartfile:
113 | github "MattLewin/NumericPicker"
114 |
115 |
116 | Run carthage update to build the framework and drag the built NumericPicker.framework (in Carthage/Build/iOS folder)
117 | into your Xcode project (Linked Frameworks and Libraries in Targets).
118 | Swift Package Manager (SPM)
119 |
120 | The Swift Package Manager does not yet support importing UIKit or compilation for
121 | iOS. Thus, NumericPicker can not yet be used with the SPM.
122 | Manually
123 |
124 |
125 | Copy NumericPicker.swift into your project
126 | Have a nice day
127 |
128 | Usage
129 |
130 | NumericPicker is a subclass of UIControl . In this way it
131 | is more like UIDatePicker than it is like
132 | UIPickerView . What this means for you is that you don’t
133 | need to implement UIPickerViewDataSource or
134 | UIPickerViewDelegate .
135 |
136 | Note that the provided Example demonstrates everything detailed below.
137 | Configurable Properties
138 |
139 |
140 | value: Double - The value displayed in the picker. Set this value to update the picker programatically.
141 | (Default: 0)
142 | minIntegerDigits: Int - The minimum number of integer digits (digits to the left of the decimal separator) to
143 | include in the picker. Think of this as zero-padding the picker. If value requires more than this minimum, the picker
144 | will automatically meet this requirement. (This is probably not what you want, though.) (Default: 1)
145 | fractionDigits: Int - The number of digits to the right of the decimal separator. NumericPicker guarantees
146 | exactly this many fractional digits will be displayed. You can use this to achieve rounding or zero-padding of values
147 | to the right of the decimal separator. (Default: 0)
148 | locale: Locale - The locale used to format the numeric values. Use this if you want numbers formatted with
149 | separators other than those used by the device locale. (Default: current device locale)
150 | font: UIFont - The font used to format the picker components. (Default: Body text style)
151 | displayString: String - READ ONLY - The text representation of value. This string will contain locale-specific
152 | grouping and decimal separators. It will have exactly fractionDigits digits to the right of the decimal separator and
153 | the minimum number of integer places necessary to represent value.
154 |
155 | Interface Builder
156 |
157 | To use NumericPicker with Interface Builder, add a UIControl
158 | to your storyboard or XIB, and then set the Custom Class to NumericPicker . Connect the `Value Changed` event to
159 | a function in your view controller. (Be certain to set the Type to NumericPicker as shown below.)
160 |
161 |
162 |
163 | Within that function, you can access sender.displayString or sender.value as needed.
164 | Cocoapods or Manually
165 |
166 | If you are using Cocoapods or have dropped NumericPicker.swift into your code, you can configure value,
167 | minIntegerDigits, and fractionDigits from the Attributes inspector.
168 |
169 |
170 | Carthage
171 |
172 | Xcode does not currently (as of 9.0) support @IBInspectable properties from external frameworks. The means
173 | you cannot configure the above properties in IB. You can, however, trick IB into rendering NumericPicker with its
174 | default values by adding the following code to one of your view controllers:
175 | @IBDesignable extension NumericPicker { }
176 |
177 | Code
178 |
179 | Add a NumericPicker control from code as you would any other subview. Here is the code from
180 | NumericPicker-Example/ViewController.swift to produce the bottom sample NumericPicker . Note that it is typically unnecessary
181 | to set locale, as NumericPicker will use the current device locale by default.
182 | var codeNumericPicker = NumericPicker ()
183 | codeNumericPicker . minIntegerDigits = 6
184 | codeNumericPicker . fractionDigits = 3
185 | codeNumericPicker . value = 76543.21
186 | codeNumericPicker . locale = Locale ( identifier : "de-DE" )
187 | codeNumericPicker . addTarget ( self , action : #selector( codeValueChanged ) , for : . valueChanged )
188 | codePickerStack . addArrangedSubview ( codeNumericPicker )
189 |
190 |
191 | Author
192 |
193 | Matt Lewin, matt@mogroups.com
194 | License
195 |
196 | NumericPicker is available under the MIT license. See LICENSE.md
197 | for more info.
198 |
199 |
200 |
201 |
205 |
206 |
207 |
208 |
209 |
210 |
--------------------------------------------------------------------------------
/Sources/NumericPicker.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NumericPicker.swift
3 | // NumericPicker
4 | //
5 | // Created by Matthew Lewin on 2/1/17.
6 | // Copyright © 2017 MoGroups
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
16 | // all 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
24 | // THE SOFTWARE.
25 | //
26 |
27 | import UIKit
28 |
29 | /**
30 | NumericPicker is a drop-in iOS picker control written in Swift. It makes simplifies the creation of pickers that allow
31 | your users to specify numbers by digit. It automatically uses the proper grouping and decimal separator for the
32 | current (or specified) locale. You can easily dictate the number of integer and decimal places in the controller.
33 |
34 | 
35 | */
36 | @IBDesignable public class NumericPicker: UIControl {
37 | // *** Please alphabetize everything under its respective group ***
38 |
39 | // MARK: - Properties
40 |
41 | /// The font for the components of the picker. (defaults to `Body`)
42 | @IBInspectable public var font = UIFont.preferredFont(forTextStyle: .body) {
43 | didSet {
44 | picker.reloadAllComponents()
45 | generateAccessibilityLabels()
46 | }
47 | }
48 |
49 | /// `displayString` is the numeric value selected in the picker without integer zero-padding. It's read-only and
50 | /// updated by changes to `value`, `minIntegerDigits`, and `fractionDigits`.
51 | fileprivate(set) public var displayString: String = "0"
52 |
53 | /// The natural size for the receiving view, considering only properties of the view itself.
54 | override public var intrinsicContentSize: CGSize {
55 | return picker.bounds.size
56 | }
57 |
58 | /// The locale used for numeric presentation. (defaults to current locale)
59 | public var locale = Locale.current {
60 | didSet {
61 | numberFormatter.locale = locale
62 | updateAppearance(animated: false)
63 | generateAccessibilityLabels()
64 | }
65 | }
66 |
67 | // MARK: IB inspectable properties
68 |
69 | /// Number of digits to display to the right of the decimal separator (defaults to `0`)
70 | @IBInspectable public var fractionDigits: Int = 0 {
71 | didSet {
72 | updateAppearance(animated: false)
73 | generateAccessibilityLabels()
74 | }
75 | }
76 |
77 | /// Minimum number of digits to display to the left of the decimal separator (defaults to `1`)
78 | @IBInspectable public var minIntegerDigits: Int = 1 {
79 | didSet {
80 | updateAppearance(animated: false)
81 | generateAccessibilityLabels()
82 | }
83 | }
84 |
85 | /// Minimum value the picker may be set to (defaults to `0.0`)
86 | /// - Warning: Must be zero or greater.
87 | @IBInspectable public var minValue: Double = 0.0 {
88 | didSet {
89 | if minValue < 0.0 {
90 | minValue = 0.0
91 | }
92 | }
93 | }
94 |
95 | /// The numeric value shown in the picker (defaults to `0.0`)
96 | @IBInspectable public var value: Double = 0.0 {
97 | didSet {
98 | // If value exceeds the maximum integer value representable by minIntegerDigits, increase minIntegerDigits
99 | // to avoid picker components disappearing if the user sets the leftmost component to zero.
100 | if Decimal(value) >= pow(10, minIntegerDigits) {
101 | minIntegerDigits = intDigits(in: value)
102 | }
103 |
104 | updateAppearance(animated: true)
105 | sendActions(for: .valueChanged)
106 |
107 | guard justInstantiated else { return }
108 | justInstantiated = false
109 | }
110 | }
111 |
112 | // MARK: Private properties
113 |
114 | /// `componentsString` is the numeric value selected in the picker zero-padded to at least `minIntegerDigits`
115 | /// places. It's updated by changes to `value`, `minIntegerDigits`, and `fractionDigits`.
116 | fileprivate(set) var componentsString: String = "0"
117 |
118 | /// When the `NumericPicker` is first instantiated, we want to size it properly according to `value`. After that,
119 | /// changing `value` shouldn't resize the view.
120 | private var justInstantiated = true
121 |
122 | /// The `UIPickerView` embedded within this control
123 | fileprivate(set) var picker: UIPickerView = UIPickerView()
124 |
125 | /// The accessibility labels for each component of the picker
126 | fileprivate var accessibilityLabels: [String]?
127 |
128 | /// We rely so heavily on `NumberFormatter`, that we keep one instantiated as a property
129 | fileprivate let numberFormatter = NumberFormatter()
130 |
131 | // MARK: - Object life cycle
132 |
133 | /// Initializes and returns a newly allocated `NumericPicker` object with a zero-sized frame rectangle.
134 | convenience public init() {
135 | self.init(frame: CGRect.zero)
136 | }
137 |
138 | /**
139 | Returns an object initialized from data in a given unarchiver.
140 |
141 | - parameter aDecoder: An unarchiver object.
142 | */
143 | required public init?(coder aDecoder: NSCoder) {
144 | super.init(coder: aDecoder)
145 | commonInit()
146 | }
147 |
148 | /**
149 | Initializes and returns a newly allocated `NumericPicker` object with the specified frame rectangle.
150 |
151 | - parameter frame: The frame rectangle for the view, measured in points. The origin of the frame is relative to
152 | the superview in which you plan to add it.
153 | */
154 | override public init(frame: CGRect) {
155 | super.init(frame: frame)
156 | commonInit()
157 | }
158 |
159 | /**
160 | Encapsulates the functionality common to all `init` methods of `NumericPicker`
161 | */
162 | private func commonInit() {
163 | numberFormatter.usesGroupingSeparator = true
164 | picker.delegate = self
165 | picker.dataSource = self
166 | picker.isAccessibilityElement = false
167 | addSubview(picker)
168 | picker.translatesAutoresizingMaskIntoConstraints = false
169 | addConstraint(NSLayoutConstraint(item: picker, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0))
170 | addConstraint(NSLayoutConstraint(item: picker, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0))
171 | addConstraint(NSLayoutConstraint(item: picker, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1, constant: 0))
172 | addConstraint(NSLayoutConstraint(item: picker, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1, constant: 0))
173 | }
174 |
175 | // MARK: - Picker Maintenance
176 |
177 | /**
178 | Recalculates `displayString` and `componentsString` and refreshes the picker view. Called whenever a property
179 | of the `NumericPicker` changes.
180 |
181 | - parameter animated: whether to animate the changes to the picker's components (default: `true`)
182 | */
183 | func updateAppearance(animated: Bool = true) {
184 | displayString = updatedDisplayString(value: value, fractionDigits: fractionDigits)
185 | componentsString = updatedComponentString(value: value,
186 | intDigits: minIntegerDigits,
187 | fractionDigits: fractionDigits)
188 |
189 | picker.reloadAllComponents()
190 | var index = 0
191 |
192 | for char in componentsString {
193 | // Row is the numeric value of the digit string, or zero for separators
194 | let row = Int(String(char)) ?? 0
195 | picker.selectRow(row, inComponent: index, animated: animated)
196 | index += 1
197 | }
198 | }
199 |
200 | /**
201 | - parameter value: the new value displayed in the picker
202 | - parameter intDigits: the number of digits displayed to the **left** of the decimal separator
203 | - parameter fractionDigits: the number of digits displayed to the **right** of the decimal separator
204 |
205 | - returns: a string used by `NumericPicker`'s `UIPickerViewDataSource` and `UIPickerViewDelegate` to create and
206 | configure the components of the picker view
207 | */
208 | func updatedComponentString(value: Double, intDigits: Int, fractionDigits: Int) -> String {
209 | numberFormatter.minimumIntegerDigits = intDigits
210 | numberFormatter.minimumFractionDigits = fractionDigits
211 | numberFormatter.maximumFractionDigits = fractionDigits
212 | numberFormatter.numberStyle = .decimal
213 |
214 | let stringValue = numberFormatter.string(from: NSNumber(value: value))
215 | return stringValue ?? numberFormatter.string(from: 0)!
216 | }
217 |
218 | /**
219 | - parameter value: the new value displayed in the picker
220 | - parameter fractionDigits: the number of digits displayed to the right of the decimal separator
221 |
222 | - returns: a string formatted for display to the user
223 | */
224 | func updatedDisplayString(value: Double, fractionDigits: Int) -> String {
225 | numberFormatter.minimumIntegerDigits = 1
226 | numberFormatter.minimumFractionDigits = fractionDigits
227 | numberFormatter.maximumFractionDigits = fractionDigits
228 | numberFormatter.numberStyle = .decimal
229 |
230 | let stringValue = numberFormatter.string(from: NSNumber(value: value))
231 | return stringValue ?? numberFormatter.string(from: 0)!
232 | }
233 |
234 | /**
235 | Calculates the width of the picker based on the number of components.
236 |
237 | - returns: the new width of the picker
238 | */
239 | func widthOfPickerView() -> CGFloat {
240 | let componentWidth: CGFloat! = picker.delegate?.pickerView!(picker, widthForComponent: 0)
241 | let componentCount = CGFloat((picker.dataSource?.numberOfComponents(in: picker))!)
242 | return componentCount * componentWidth + (componentCount - 1) * (componentWidth / 2) // Account for spacing between components
243 | }
244 |
245 | // MARK: - Utility functions
246 |
247 | static let integerPlaceDescriptors = [
248 | NSLocalizedString("ones", comment: "the ones or units column"),
249 | NSLocalizedString("tens", comment: "the tens column"),
250 | NSLocalizedString("hundreds", comment: "the hundreds column"),
251 | NSLocalizedString("thousands", comment: "the thousands column"),
252 | NSLocalizedString("ten thousands", comment: "the ten thousands column"),
253 | NSLocalizedString("hundred thousands", comment: "the hundred thousands column"),
254 | NSLocalizedString("millions", comment: "the millions column"),
255 | ]
256 |
257 | static let fractionPlaceDescriptors = [
258 | NSLocalizedString("tenths", comment: "the tenths (0.1) column"),
259 | NSLocalizedString("hundredths", comment: "the hundredths (0.01) column"),
260 | NSLocalizedString("thousandths", comment: "the thousandths (0.001) column"),
261 | ]
262 |
263 | fileprivate func exponentString(for: FloatingPointSign, magnitude: Int) -> String {
264 | numberFormatter.maximumIntegerDigits = 1
265 | numberFormatter.maximumFractionDigits = 0
266 | numberFormatter.numberStyle = .scientific
267 | let magnitudeNumber = Decimal(sign: .plus, exponent: magnitude, significand: 1)
268 | return numberFormatter.string(from: magnitudeNumber as NSDecimalNumber)!
269 | }
270 |
271 | /**
272 | Produce the set of accessibility labels based on the number of integer and fraction digits and store them in the
273 | `accessibilityLabels` property.
274 |
275 | For integer components greater than seven and fraction components greater than three, the label will be represented
276 | as exponents. (i.e., *1E10* for one trillion and *1E-4* for ten-thousandths.) For everything in between, the label
277 | will be the descriptor for that digit place. (i.e., "millions" or "tenths")
278 | */
279 | fileprivate func generateAccessibilityLabels() {
280 | let componentParts = componentsString.components(separatedBy: numberFormatter.decimalSeparator)
281 | let integerPortion = componentParts[0]
282 | var digitIndex = 1
283 |
284 | accessibilityLabels = integerPortion.map { character -> String in
285 | guard character != numberFormatter.groupingSeparator.first! else {
286 | return NSLocalizedString("thousands separator", comment: "the separator between digit groupings")
287 | }
288 |
289 | let place = minIntegerDigits - digitIndex
290 | digitIndex += 1
291 | if place < NumericPicker.integerPlaceDescriptors.count {
292 | return NumericPicker.integerPlaceDescriptors[place]
293 | }
294 | else {
295 | return exponentString(for: .plus, magnitude: place)
296 | }
297 | }
298 |
299 | guard componentParts.count == 2 else { return }
300 |
301 | let fractionPortion = componentParts[1]
302 |
303 | accessibilityLabels?.append(NSLocalizedString("decimal point",
304 | comment: "the separator between integer and fractional portions"))
305 |
306 | for index in 0.. Int {
323 | var intValue = Int(value)
324 | var digits = 0
325 |
326 | repeat {
327 | intValue /= 10
328 | digits += 1
329 | } while (intValue != 0)
330 |
331 | return digits
332 | }
333 | }
334 |
335 | // MARK: - UIPickerViewAccessibilityDelegate
336 |
337 | extension NumericPicker: UIPickerViewAccessibilityDelegate {
338 |
339 | public func pickerView(_ pickerView: UIPickerView, accessibilityLabelForComponent component: Int) -> String? {
340 | return accessibilityLabels?[component] ??
341 | NSLocalizedString("unknown picker wheel #\(component)", comment: "voice over label for unknown picker component")
342 | }
343 | }
344 |
345 | // MARK: - UIPickerViewDataSource
346 | extension NumericPicker: UIPickerViewDataSource {
347 |
348 | /**
349 | Called by the picker view when it needs the number of components.
350 |
351 | - parameter pickerView: The picker view requesting the data.
352 |
353 | - returns: The number of components (or “columns”) that the picker view should display.
354 | */
355 | public func numberOfComponents(in pickerView: UIPickerView) -> Int {
356 | return componentsString.count
357 | }
358 |
359 | /**
360 | Called by the picker view when it needs the number of rows for a specified component.
361 |
362 | - parameter pickerView: The picker view requesting the data.
363 | - parameter component: A zero-indexed number identifying a component of `pickerView`. Components are numbered left-to-right.
364 |
365 | - returns: The number of rows for the component.
366 | */
367 | public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
368 | let unicodeScalers = componentsString.unicodeScalars
369 | let index = unicodeScalers.index(unicodeScalers.startIndex, offsetBy: component)
370 | let char = componentsString.unicodeScalars[index]
371 |
372 | guard CharacterSet.decimalDigits.contains(char) else {
373 | return 1
374 | }
375 |
376 | return 10
377 | }
378 | }
379 |
380 | // MARK: - UIPickerViewDelegate
381 |
382 | extension NumericPicker: UIPickerViewDelegate {
383 |
384 | /**
385 | Called by the picker view when the user selects a row in a component.
386 |
387 | - parameter pickerView: The picker view requesting the data.
388 | - parameter row: A zero-indexed number identifying a row of `component`. Rows are numbered top-to-bottom.
389 | - parameter component: A zero-indexed number identifying a component of `pickerView`. Components are numbered left-to-right.
390 | */
391 | public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
392 | var stringValue = ""
393 | for index in 0..= minValue) ? value : minValue
405 | }
406 |
407 | /**
408 | Called by the picker view when it needs the title to use for a given row in a given component.
409 |
410 | - parameter pickerView: The picker view requesting the data.
411 | - parameter row: A zero-indexed number identifying a row of `component`. Rows are numbered top-to-bottom.
412 | - parameter component: A zero-indexed number identifying a component of `pickerView`. Components are numbered left-to-right.
413 |
414 | - returns: The string to use as the title of the indicated component row.
415 | */
416 | public func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
417 | let unicodeScalers = componentsString.unicodeScalars
418 |
419 | // Work around a bug in iOS 12 SDK
420 | if component >= unicodeScalers.count {
421 | return String(row)
422 | }
423 |
424 | let index = unicodeScalers.index(unicodeScalers.startIndex, offsetBy: component)
425 | let char = componentsString.unicodeScalars[index]
426 |
427 | guard CharacterSet.decimalDigits.contains(char) else {
428 | return String(char)
429 | }
430 |
431 | return String(row)
432 | }
433 |
434 | /**
435 | Called by the picker view when it needs the view to use for a given row in a given component.
436 |
437 | - parameter pickerView: The picker view requesting the data.
438 | - parameter row: A zero-indexed number identifying a row of `component`. Rows are numbered top-to-bottom.
439 | - parameter component: A zero-indexed number identifying a component of `pickerView`. Components are numbered left-to-right.
440 | - parameter view: A view object that was previously used for this row, but is now hidden and cached by the picker view.
441 |
442 | - returns: A view object to use as the content of `row`. The object can be any subclass of UIView, such as UILabel,
443 | UIImageView, or even a custom view.
444 | */
445 | public func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
446 | let pickerLabel = view as? UILabel ?? UILabel()
447 | let title = self.pickerView(pickerView, titleForRow: row, forComponent: component)
448 | pickerLabel.text = title
449 | pickerLabel.font = font
450 | pickerLabel.adjustsFontForContentSizeCategory = true
451 | pickerLabel.accessibilityTraits = UIAccessibilityTraits.adjustable
452 | pickerLabel.accessibilityValue = title
453 | pickerLabel.sizeToFit()
454 | return pickerLabel
455 | }
456 |
457 | /**
458 | Called by the picker view when it needs the row width to use for drawing row content.
459 |
460 | - parameter pickerView: The picker view requesting the data.
461 | - parameter component: A zero-indexed number identifying a component of `pickerView`. Components are numbered left-to-right.
462 |
463 | - returns: A `CGFloat` indicating the width of the row in points.
464 | */
465 | public func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
466 | let pickerLabel = self.pickerView(pickerView, viewForRow: 0, forComponent: component, reusing: nil)
467 | let width = pickerLabel.bounds.width + 8
468 | return width
469 | }
470 |
471 | public func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
472 | let pickerLabel = self.pickerView(pickerView, viewForRow: 0, forComponent: component, reusing: nil)
473 | let height = pickerLabel.bounds.height + 8
474 | return height
475 | }
476 | }
477 |
--------------------------------------------------------------------------------
/NumericPicker.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 51;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | C98B8D411F91361700552D46 /* NumericPicker.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C98B8D371F91361700552D46 /* NumericPicker.framework */; };
11 | C98B8D581F9136F600552D46 /* NumericPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = C98B8D571F9136F600552D46 /* NumericPicker.swift */; };
12 | C98B8D601F9137BB00552D46 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C98B8D5F1F9137BB00552D46 /* AppDelegate.swift */; };
13 | C98B8D621F9137BB00552D46 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C98B8D611F9137BB00552D46 /* ViewController.swift */; };
14 | C98B8D651F9137BB00552D46 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C98B8D631F9137BB00552D46 /* Main.storyboard */; };
15 | C98B8D671F9137BB00552D46 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C98B8D661F9137BB00552D46 /* Assets.xcassets */; };
16 | C98B8D6A1F9137BB00552D46 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C98B8D681F9137BB00552D46 /* LaunchScreen.storyboard */; };
17 | C98B8D701F91495E00552D46 /* NumericPicker.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C98B8D371F91361700552D46 /* NumericPicker.framework */; };
18 | C98C13C81F914BA700450415 /* ComponentsStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C98C13C71F914BA700450415 /* ComponentsStringTests.swift */; };
19 | C98C13CA1F91575F00450415 /* DisplayStringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C98C13C91F91575F00450415 /* DisplayStringTests.swift */; };
20 | C98C13CC1F915B0300450415 /* NumericPickerUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C98C13CB1F915B0300450415 /* NumericPickerUnitTests.swift */; };
21 | /* End PBXBuildFile section */
22 |
23 | /* Begin PBXContainerItemProxy section */
24 | C98B8D421F91361700552D46 /* PBXContainerItemProxy */ = {
25 | isa = PBXContainerItemProxy;
26 | containerPortal = C98B8D2E1F91361700552D46 /* Project object */;
27 | proxyType = 1;
28 | remoteGlobalIDString = C98B8D361F91361700552D46;
29 | remoteInfo = NumericPicker;
30 | };
31 | /* End PBXContainerItemProxy section */
32 |
33 | /* Begin PBXFileReference section */
34 | C98B8D371F91361700552D46 /* NumericPicker.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NumericPicker.framework; sourceTree = BUILT_PRODUCTS_DIR; };
35 | C98B8D3B1F91361700552D46 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
36 | C98B8D401F91361700552D46 /* NumericPickerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NumericPickerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
37 | C98B8D471F91361700552D46 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
38 | C98B8D511F9136A500552D46 /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = ""; };
39 | C98B8D521F9136A500552D46 /* NumericPicker.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = NumericPicker.podspec; sourceTree = ""; };
40 | C98B8D531F9136A500552D46 /* .travis.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .travis.yml; sourceTree = ""; };
41 | C98B8D541F9136A600552D46 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = ""; };
42 | C98B8D551F9136A600552D46 /* LICENSE.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = ""; };
43 | C98B8D561F9136A600552D46 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
44 | C98B8D571F9136F600552D46 /* NumericPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumericPicker.swift; sourceTree = ""; };
45 | C98B8D5D1F9137BB00552D46 /* NumericPicker-Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "NumericPicker-Example.app"; sourceTree = BUILT_PRODUCTS_DIR; };
46 | C98B8D5F1F9137BB00552D46 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
47 | C98B8D611F9137BB00552D46 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
48 | C98B8D641F9137BB00552D46 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
49 | C98B8D661F9137BB00552D46 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
50 | C98B8D691F9137BB00552D46 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
51 | C98B8D6B1F9137BB00552D46 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
52 | C98C13C71F914BA700450415 /* ComponentsStringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComponentsStringTests.swift; sourceTree = ""; };
53 | C98C13C91F91575F00450415 /* DisplayStringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayStringTests.swift; sourceTree = ""; };
54 | C98C13CB1F915B0300450415 /* NumericPickerUnitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumericPickerUnitTests.swift; sourceTree = ""; };
55 | C98C13CF1F92CCE000450415 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; };
56 | /* End PBXFileReference section */
57 |
58 | /* Begin PBXFrameworksBuildPhase section */
59 | C98B8D331F91361700552D46 /* Frameworks */ = {
60 | isa = PBXFrameworksBuildPhase;
61 | buildActionMask = 2147483647;
62 | files = (
63 | );
64 | runOnlyForDeploymentPostprocessing = 0;
65 | };
66 | C98B8D3D1F91361700552D46 /* Frameworks */ = {
67 | isa = PBXFrameworksBuildPhase;
68 | buildActionMask = 2147483647;
69 | files = (
70 | C98B8D411F91361700552D46 /* NumericPicker.framework in Frameworks */,
71 | );
72 | runOnlyForDeploymentPostprocessing = 0;
73 | };
74 | C98B8D5A1F9137BB00552D46 /* Frameworks */ = {
75 | isa = PBXFrameworksBuildPhase;
76 | buildActionMask = 2147483647;
77 | files = (
78 | C98B8D701F91495E00552D46 /* NumericPicker.framework in Frameworks */,
79 | );
80 | runOnlyForDeploymentPostprocessing = 0;
81 | };
82 | /* End PBXFrameworksBuildPhase section */
83 |
84 | /* Begin PBXGroup section */
85 | C98B8D2D1F91361700552D46 = {
86 | isa = PBXGroup;
87 | children = (
88 | C98B8D511F9136A500552D46 /* .gitignore */,
89 | C98B8D531F9136A500552D46 /* .travis.yml */,
90 | C98B8D541F9136A600552D46 /* CHANGELOG.md */,
91 | C98B8D3B1F91361700552D46 /* Info.plist */,
92 | C98B8D551F9136A600552D46 /* LICENSE.md */,
93 | C98B8D521F9136A500552D46 /* NumericPicker.podspec */,
94 | C98C13CF1F92CCE000450415 /* Package.swift */,
95 | C98B8D561F9136A600552D46 /* README.md */,
96 | C98B8D391F91361700552D46 /* Sources */,
97 | C98B8D441F91361700552D46 /* Tests */,
98 | C98B8D5E1F9137BB00552D46 /* NumericPicker-Example */,
99 | C98B8D381F91361700552D46 /* Products */,
100 | C98B8D6F1F91495E00552D46 /* Frameworks */,
101 | );
102 | sourceTree = "";
103 | };
104 | C98B8D381F91361700552D46 /* Products */ = {
105 | isa = PBXGroup;
106 | children = (
107 | C98B8D371F91361700552D46 /* NumericPicker.framework */,
108 | C98B8D401F91361700552D46 /* NumericPickerTests.xctest */,
109 | C98B8D5D1F9137BB00552D46 /* NumericPicker-Example.app */,
110 | );
111 | name = Products;
112 | sourceTree = "";
113 | };
114 | C98B8D391F91361700552D46 /* Sources */ = {
115 | isa = PBXGroup;
116 | children = (
117 | C98B8D571F9136F600552D46 /* NumericPicker.swift */,
118 | );
119 | path = Sources;
120 | sourceTree = "";
121 | };
122 | C98B8D441F91361700552D46 /* Tests */ = {
123 | isa = PBXGroup;
124 | children = (
125 | C98C13CE1F92CCA200450415 /* NumericPickerTests */,
126 | C98B8D471F91361700552D46 /* Info.plist */,
127 | );
128 | path = Tests;
129 | sourceTree = "";
130 | };
131 | C98B8D5E1F9137BB00552D46 /* NumericPicker-Example */ = {
132 | isa = PBXGroup;
133 | children = (
134 | C98B8D5F1F9137BB00552D46 /* AppDelegate.swift */,
135 | C98B8D611F9137BB00552D46 /* ViewController.swift */,
136 | C98B8D631F9137BB00552D46 /* Main.storyboard */,
137 | C98B8D661F9137BB00552D46 /* Assets.xcassets */,
138 | C98B8D681F9137BB00552D46 /* LaunchScreen.storyboard */,
139 | C98B8D6B1F9137BB00552D46 /* Info.plist */,
140 | );
141 | path = "NumericPicker-Example";
142 | sourceTree = "";
143 | };
144 | C98B8D6F1F91495E00552D46 /* Frameworks */ = {
145 | isa = PBXGroup;
146 | children = (
147 | );
148 | name = Frameworks;
149 | sourceTree = "";
150 | };
151 | C98C13CE1F92CCA200450415 /* NumericPickerTests */ = {
152 | isa = PBXGroup;
153 | children = (
154 | C98C13C71F914BA700450415 /* ComponentsStringTests.swift */,
155 | C98C13C91F91575F00450415 /* DisplayStringTests.swift */,
156 | C98C13CB1F915B0300450415 /* NumericPickerUnitTests.swift */,
157 | );
158 | path = NumericPickerTests;
159 | sourceTree = "";
160 | };
161 | /* End PBXGroup section */
162 |
163 | /* Begin PBXHeadersBuildPhase section */
164 | C98B8D341F91361700552D46 /* Headers */ = {
165 | isa = PBXHeadersBuildPhase;
166 | buildActionMask = 2147483647;
167 | files = (
168 | );
169 | runOnlyForDeploymentPostprocessing = 0;
170 | };
171 | /* End PBXHeadersBuildPhase section */
172 |
173 | /* Begin PBXNativeTarget section */
174 | C98B8D361F91361700552D46 /* NumericPicker */ = {
175 | isa = PBXNativeTarget;
176 | buildConfigurationList = C98B8D4B1F91361700552D46 /* Build configuration list for PBXNativeTarget "NumericPicker" */;
177 | buildPhases = (
178 | C98B8D321F91361700552D46 /* Sources */,
179 | C98B8D331F91361700552D46 /* Frameworks */,
180 | C98B8D341F91361700552D46 /* Headers */,
181 | C98B8D351F91361700552D46 /* Resources */,
182 | );
183 | buildRules = (
184 | );
185 | dependencies = (
186 | );
187 | name = NumericPicker;
188 | productName = NumericPicker;
189 | productReference = C98B8D371F91361700552D46 /* NumericPicker.framework */;
190 | productType = "com.apple.product-type.framework";
191 | };
192 | C98B8D3F1F91361700552D46 /* NumericPickerTests */ = {
193 | isa = PBXNativeTarget;
194 | buildConfigurationList = C98B8D4E1F91361700552D46 /* Build configuration list for PBXNativeTarget "NumericPickerTests" */;
195 | buildPhases = (
196 | C98B8D3C1F91361700552D46 /* Sources */,
197 | C98B8D3D1F91361700552D46 /* Frameworks */,
198 | C98B8D3E1F91361700552D46 /* Resources */,
199 | );
200 | buildRules = (
201 | );
202 | dependencies = (
203 | C98B8D431F91361700552D46 /* PBXTargetDependency */,
204 | );
205 | name = NumericPickerTests;
206 | productName = NumericPickerTests;
207 | productReference = C98B8D401F91361700552D46 /* NumericPickerTests.xctest */;
208 | productType = "com.apple.product-type.bundle.unit-test";
209 | };
210 | C98B8D5C1F9137BB00552D46 /* NumericPicker-Example */ = {
211 | isa = PBXNativeTarget;
212 | buildConfigurationList = C98B8D6C1F9137BB00552D46 /* Build configuration list for PBXNativeTarget "NumericPicker-Example" */;
213 | buildPhases = (
214 | C98B8D591F9137BB00552D46 /* Sources */,
215 | C98B8D5A1F9137BB00552D46 /* Frameworks */,
216 | C98B8D5B1F9137BB00552D46 /* Resources */,
217 | );
218 | buildRules = (
219 | );
220 | dependencies = (
221 | );
222 | name = "NumericPicker-Example";
223 | productName = "NumericPicker-Example";
224 | productReference = C98B8D5D1F9137BB00552D46 /* NumericPicker-Example.app */;
225 | productType = "com.apple.product-type.application";
226 | };
227 | /* End PBXNativeTarget section */
228 |
229 | /* Begin PBXProject section */
230 | C98B8D2E1F91361700552D46 /* Project object */ = {
231 | isa = PBXProject;
232 | attributes = {
233 | LastSwiftUpdateCheck = 0900;
234 | LastUpgradeCheck = 0940;
235 | ORGANIZATIONNAME = MoGroups;
236 | TargetAttributes = {
237 | C98B8D361F91361700552D46 = {
238 | CreatedOnToolsVersion = 9.0;
239 | LastSwiftMigration = 1000;
240 | ProvisioningStyle = Manual;
241 | };
242 | C98B8D3F1F91361700552D46 = {
243 | CreatedOnToolsVersion = 9.0;
244 | LastSwiftMigration = 1000;
245 | ProvisioningStyle = Manual;
246 | };
247 | C98B8D5C1F9137BB00552D46 = {
248 | CreatedOnToolsVersion = 9.0;
249 | LastSwiftMigration = 1000;
250 | ProvisioningStyle = Manual;
251 | };
252 | };
253 | };
254 | buildConfigurationList = C98B8D311F91361700552D46 /* Build configuration list for PBXProject "NumericPicker" */;
255 | compatibilityVersion = "Xcode 10.0";
256 | developmentRegion = en;
257 | hasScannedForEncodings = 0;
258 | knownRegions = (
259 | en,
260 | Base,
261 | );
262 | mainGroup = C98B8D2D1F91361700552D46;
263 | productRefGroup = C98B8D381F91361700552D46 /* Products */;
264 | projectDirPath = "";
265 | projectRoot = "";
266 | targets = (
267 | C98B8D361F91361700552D46 /* NumericPicker */,
268 | C98B8D3F1F91361700552D46 /* NumericPickerTests */,
269 | C98B8D5C1F9137BB00552D46 /* NumericPicker-Example */,
270 | );
271 | };
272 | /* End PBXProject section */
273 |
274 | /* Begin PBXResourcesBuildPhase section */
275 | C98B8D351F91361700552D46 /* Resources */ = {
276 | isa = PBXResourcesBuildPhase;
277 | buildActionMask = 2147483647;
278 | files = (
279 | );
280 | runOnlyForDeploymentPostprocessing = 0;
281 | };
282 | C98B8D3E1F91361700552D46 /* Resources */ = {
283 | isa = PBXResourcesBuildPhase;
284 | buildActionMask = 2147483647;
285 | files = (
286 | );
287 | runOnlyForDeploymentPostprocessing = 0;
288 | };
289 | C98B8D5B1F9137BB00552D46 /* Resources */ = {
290 | isa = PBXResourcesBuildPhase;
291 | buildActionMask = 2147483647;
292 | files = (
293 | C98B8D6A1F9137BB00552D46 /* LaunchScreen.storyboard in Resources */,
294 | C98B8D671F9137BB00552D46 /* Assets.xcassets in Resources */,
295 | C98B8D651F9137BB00552D46 /* Main.storyboard in Resources */,
296 | );
297 | runOnlyForDeploymentPostprocessing = 0;
298 | };
299 | /* End PBXResourcesBuildPhase section */
300 |
301 | /* Begin PBXSourcesBuildPhase section */
302 | C98B8D321F91361700552D46 /* Sources */ = {
303 | isa = PBXSourcesBuildPhase;
304 | buildActionMask = 2147483647;
305 | files = (
306 | C98B8D581F9136F600552D46 /* NumericPicker.swift in Sources */,
307 | );
308 | runOnlyForDeploymentPostprocessing = 0;
309 | };
310 | C98B8D3C1F91361700552D46 /* Sources */ = {
311 | isa = PBXSourcesBuildPhase;
312 | buildActionMask = 2147483647;
313 | files = (
314 | C98C13CC1F915B0300450415 /* NumericPickerUnitTests.swift in Sources */,
315 | C98C13C81F914BA700450415 /* ComponentsStringTests.swift in Sources */,
316 | C98C13CA1F91575F00450415 /* DisplayStringTests.swift in Sources */,
317 | );
318 | runOnlyForDeploymentPostprocessing = 0;
319 | };
320 | C98B8D591F9137BB00552D46 /* Sources */ = {
321 | isa = PBXSourcesBuildPhase;
322 | buildActionMask = 2147483647;
323 | files = (
324 | C98B8D621F9137BB00552D46 /* ViewController.swift in Sources */,
325 | C98B8D601F9137BB00552D46 /* AppDelegate.swift in Sources */,
326 | );
327 | runOnlyForDeploymentPostprocessing = 0;
328 | };
329 | /* End PBXSourcesBuildPhase section */
330 |
331 | /* Begin PBXTargetDependency section */
332 | C98B8D431F91361700552D46 /* PBXTargetDependency */ = {
333 | isa = PBXTargetDependency;
334 | target = C98B8D361F91361700552D46 /* NumericPicker */;
335 | targetProxy = C98B8D421F91361700552D46 /* PBXContainerItemProxy */;
336 | };
337 | /* End PBXTargetDependency section */
338 |
339 | /* Begin PBXVariantGroup section */
340 | C98B8D631F9137BB00552D46 /* Main.storyboard */ = {
341 | isa = PBXVariantGroup;
342 | children = (
343 | C98B8D641F9137BB00552D46 /* Base */,
344 | );
345 | name = Main.storyboard;
346 | sourceTree = "";
347 | };
348 | C98B8D681F9137BB00552D46 /* LaunchScreen.storyboard */ = {
349 | isa = PBXVariantGroup;
350 | children = (
351 | C98B8D691F9137BB00552D46 /* Base */,
352 | );
353 | name = LaunchScreen.storyboard;
354 | sourceTree = "";
355 | };
356 | /* End PBXVariantGroup section */
357 |
358 | /* Begin XCBuildConfiguration section */
359 | C98B8D491F91361700552D46 /* Debug */ = {
360 | isa = XCBuildConfiguration;
361 | buildSettings = {
362 | ALWAYS_SEARCH_USER_PATHS = NO;
363 | CLANG_ANALYZER_NONNULL = YES;
364 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
365 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
366 | CLANG_CXX_LIBRARY = "libc++";
367 | CLANG_ENABLE_MODULES = YES;
368 | CLANG_ENABLE_OBJC_ARC = YES;
369 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
370 | CLANG_WARN_BOOL_CONVERSION = YES;
371 | CLANG_WARN_COMMA = YES;
372 | CLANG_WARN_CONSTANT_CONVERSION = YES;
373 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
374 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
375 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
376 | CLANG_WARN_EMPTY_BODY = YES;
377 | CLANG_WARN_ENUM_CONVERSION = YES;
378 | CLANG_WARN_INFINITE_RECURSION = YES;
379 | CLANG_WARN_INT_CONVERSION = YES;
380 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
381 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
382 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
383 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
384 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
385 | CLANG_WARN_STRICT_PROTOTYPES = YES;
386 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
387 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
388 | CLANG_WARN_UNREACHABLE_CODE = YES;
389 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
390 | CODE_SIGN_IDENTITY = "iPhone Developer";
391 | COPY_PHASE_STRIP = NO;
392 | CURRENT_PROJECT_VERSION = 1.1.1;
393 | DEBUG_INFORMATION_FORMAT = dwarf;
394 | ENABLE_STRICT_OBJC_MSGSEND = YES;
395 | ENABLE_TESTABILITY = YES;
396 | GCC_C_LANGUAGE_STANDARD = gnu11;
397 | GCC_DYNAMIC_NO_PIC = NO;
398 | GCC_NO_COMMON_BLOCKS = YES;
399 | GCC_OPTIMIZATION_LEVEL = 0;
400 | GCC_PREPROCESSOR_DEFINITIONS = (
401 | "DEBUG=1",
402 | "$(inherited)",
403 | );
404 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
405 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
406 | GCC_WARN_UNDECLARED_SELECTOR = YES;
407 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
408 | GCC_WARN_UNUSED_FUNCTION = YES;
409 | GCC_WARN_UNUSED_VARIABLE = YES;
410 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
411 | MTL_ENABLE_DEBUG_INFO = YES;
412 | ONLY_ACTIVE_ARCH = YES;
413 | SDKROOT = iphoneos;
414 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
415 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
416 | SWIFT_VERSION = 4.2;
417 | VERSIONING_SYSTEM = "apple-generic";
418 | VERSION_INFO_PREFIX = "";
419 | };
420 | name = Debug;
421 | };
422 | C98B8D4A1F91361700552D46 /* Release */ = {
423 | isa = XCBuildConfiguration;
424 | buildSettings = {
425 | ALWAYS_SEARCH_USER_PATHS = NO;
426 | CLANG_ANALYZER_NONNULL = YES;
427 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
428 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
429 | CLANG_CXX_LIBRARY = "libc++";
430 | CLANG_ENABLE_MODULES = YES;
431 | CLANG_ENABLE_OBJC_ARC = YES;
432 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
433 | CLANG_WARN_BOOL_CONVERSION = YES;
434 | CLANG_WARN_COMMA = YES;
435 | CLANG_WARN_CONSTANT_CONVERSION = YES;
436 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
437 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
438 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
439 | CLANG_WARN_EMPTY_BODY = YES;
440 | CLANG_WARN_ENUM_CONVERSION = YES;
441 | CLANG_WARN_INFINITE_RECURSION = YES;
442 | CLANG_WARN_INT_CONVERSION = YES;
443 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
444 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
445 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
446 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
447 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
448 | CLANG_WARN_STRICT_PROTOTYPES = YES;
449 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
450 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
451 | CLANG_WARN_UNREACHABLE_CODE = YES;
452 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
453 | CODE_SIGN_IDENTITY = "iPhone Developer";
454 | COPY_PHASE_STRIP = NO;
455 | CURRENT_PROJECT_VERSION = 1.1.1;
456 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
457 | ENABLE_NS_ASSERTIONS = NO;
458 | ENABLE_STRICT_OBJC_MSGSEND = YES;
459 | GCC_C_LANGUAGE_STANDARD = gnu11;
460 | GCC_NO_COMMON_BLOCKS = YES;
461 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
462 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
463 | GCC_WARN_UNDECLARED_SELECTOR = YES;
464 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
465 | GCC_WARN_UNUSED_FUNCTION = YES;
466 | GCC_WARN_UNUSED_VARIABLE = YES;
467 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
468 | MTL_ENABLE_DEBUG_INFO = NO;
469 | SDKROOT = iphoneos;
470 | SWIFT_COMPILATION_MODE = wholemodule;
471 | SWIFT_OPTIMIZATION_LEVEL = "-O";
472 | SWIFT_VERSION = 4.2;
473 | VALIDATE_PRODUCT = YES;
474 | VERSIONING_SYSTEM = "apple-generic";
475 | VERSION_INFO_PREFIX = "";
476 | };
477 | name = Release;
478 | };
479 | C98B8D4C1F91361700552D46 /* Debug */ = {
480 | isa = XCBuildConfiguration;
481 | buildSettings = {
482 | CLANG_ENABLE_MODULES = YES;
483 | CODE_SIGN_IDENTITY = "";
484 | CODE_SIGN_STYLE = Manual;
485 | DEFINES_MODULE = YES;
486 | DEVELOPMENT_TEAM = "";
487 | DYLIB_COMPATIBILITY_VERSION = 1;
488 | DYLIB_CURRENT_VERSION = 1.1.1;
489 | DYLIB_INSTALL_NAME_BASE = "@rpath";
490 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
491 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
492 | LD_RUNPATH_SEARCH_PATHS = (
493 | "$(inherited)",
494 | "@executable_path/Frameworks",
495 | "@loader_path/Frameworks",
496 | );
497 | PRODUCT_BUNDLE_IDENTIFIER = com.mogroups.NumericPicker;
498 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
499 | PROVISIONING_PROFILE_SPECIFIER = "";
500 | SKIP_INSTALL = YES;
501 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
502 | TARGETED_DEVICE_FAMILY = "1,2";
503 | };
504 | name = Debug;
505 | };
506 | C98B8D4D1F91361700552D46 /* Release */ = {
507 | isa = XCBuildConfiguration;
508 | buildSettings = {
509 | CLANG_ENABLE_MODULES = YES;
510 | CODE_SIGN_IDENTITY = "";
511 | CODE_SIGN_STYLE = Manual;
512 | DEFINES_MODULE = YES;
513 | DEVELOPMENT_TEAM = "";
514 | DYLIB_COMPATIBILITY_VERSION = 1;
515 | DYLIB_CURRENT_VERSION = 1.1.1;
516 | DYLIB_INSTALL_NAME_BASE = "@rpath";
517 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist";
518 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
519 | LD_RUNPATH_SEARCH_PATHS = (
520 | "$(inherited)",
521 | "@executable_path/Frameworks",
522 | "@loader_path/Frameworks",
523 | );
524 | PRODUCT_BUNDLE_IDENTIFIER = com.mogroups.NumericPicker;
525 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
526 | PROVISIONING_PROFILE_SPECIFIER = "";
527 | SKIP_INSTALL = YES;
528 | TARGETED_DEVICE_FAMILY = "1,2";
529 | };
530 | name = Release;
531 | };
532 | C98B8D4F1F91361700552D46 /* Debug */ = {
533 | isa = XCBuildConfiguration;
534 | buildSettings = {
535 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
536 | CODE_SIGN_STYLE = Manual;
537 | DEVELOPMENT_TEAM = "";
538 | INFOPLIST_FILE = Tests/Info.plist;
539 | LD_RUNPATH_SEARCH_PATHS = (
540 | "$(inherited)",
541 | "@executable_path/Frameworks",
542 | "@loader_path/Frameworks",
543 | );
544 | PRODUCT_BUNDLE_IDENTIFIER = com.mogroups.NumericPickerTests;
545 | PRODUCT_NAME = "$(TARGET_NAME)";
546 | PROVISIONING_PROFILE_SPECIFIER = "";
547 | TARGETED_DEVICE_FAMILY = "1,2";
548 | };
549 | name = Debug;
550 | };
551 | C98B8D501F91361700552D46 /* Release */ = {
552 | isa = XCBuildConfiguration;
553 | buildSettings = {
554 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
555 | CODE_SIGN_STYLE = Manual;
556 | DEVELOPMENT_TEAM = "";
557 | INFOPLIST_FILE = Tests/Info.plist;
558 | LD_RUNPATH_SEARCH_PATHS = (
559 | "$(inherited)",
560 | "@executable_path/Frameworks",
561 | "@loader_path/Frameworks",
562 | );
563 | PRODUCT_BUNDLE_IDENTIFIER = com.mogroups.NumericPickerTests;
564 | PRODUCT_NAME = "$(TARGET_NAME)";
565 | PROVISIONING_PROFILE_SPECIFIER = "";
566 | TARGETED_DEVICE_FAMILY = "1,2";
567 | };
568 | name = Release;
569 | };
570 | C98B8D6D1F9137BB00552D46 /* Debug */ = {
571 | isa = XCBuildConfiguration;
572 | buildSettings = {
573 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
574 | CODE_SIGN_STYLE = Manual;
575 | DEVELOPMENT_TEAM = "";
576 | INFOPLIST_FILE = "NumericPicker-Example/Info.plist";
577 | LD_RUNPATH_SEARCH_PATHS = (
578 | "$(inherited)",
579 | "@executable_path/Frameworks",
580 | );
581 | PRODUCT_BUNDLE_IDENTIFIER = "com.mogroups.NumericPicker-Example";
582 | PRODUCT_NAME = "$(TARGET_NAME)";
583 | PROVISIONING_PROFILE_SPECIFIER = "";
584 | TARGETED_DEVICE_FAMILY = "1,2";
585 | };
586 | name = Debug;
587 | };
588 | C98B8D6E1F9137BB00552D46 /* Release */ = {
589 | isa = XCBuildConfiguration;
590 | buildSettings = {
591 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
592 | CODE_SIGN_STYLE = Manual;
593 | DEVELOPMENT_TEAM = "";
594 | INFOPLIST_FILE = "NumericPicker-Example/Info.plist";
595 | LD_RUNPATH_SEARCH_PATHS = (
596 | "$(inherited)",
597 | "@executable_path/Frameworks",
598 | );
599 | PRODUCT_BUNDLE_IDENTIFIER = "com.mogroups.NumericPicker-Example";
600 | PRODUCT_NAME = "$(TARGET_NAME)";
601 | PROVISIONING_PROFILE_SPECIFIER = "";
602 | TARGETED_DEVICE_FAMILY = "1,2";
603 | };
604 | name = Release;
605 | };
606 | /* End XCBuildConfiguration section */
607 |
608 | /* Begin XCConfigurationList section */
609 | C98B8D311F91361700552D46 /* Build configuration list for PBXProject "NumericPicker" */ = {
610 | isa = XCConfigurationList;
611 | buildConfigurations = (
612 | C98B8D491F91361700552D46 /* Debug */,
613 | C98B8D4A1F91361700552D46 /* Release */,
614 | );
615 | defaultConfigurationIsVisible = 0;
616 | defaultConfigurationName = Release;
617 | };
618 | C98B8D4B1F91361700552D46 /* Build configuration list for PBXNativeTarget "NumericPicker" */ = {
619 | isa = XCConfigurationList;
620 | buildConfigurations = (
621 | C98B8D4C1F91361700552D46 /* Debug */,
622 | C98B8D4D1F91361700552D46 /* Release */,
623 | );
624 | defaultConfigurationIsVisible = 0;
625 | defaultConfigurationName = Release;
626 | };
627 | C98B8D4E1F91361700552D46 /* Build configuration list for PBXNativeTarget "NumericPickerTests" */ = {
628 | isa = XCConfigurationList;
629 | buildConfigurations = (
630 | C98B8D4F1F91361700552D46 /* Debug */,
631 | C98B8D501F91361700552D46 /* Release */,
632 | );
633 | defaultConfigurationIsVisible = 0;
634 | defaultConfigurationName = Release;
635 | };
636 | C98B8D6C1F9137BB00552D46 /* Build configuration list for PBXNativeTarget "NumericPicker-Example" */ = {
637 | isa = XCConfigurationList;
638 | buildConfigurations = (
639 | C98B8D6D1F9137BB00552D46 /* Debug */,
640 | C98B8D6E1F9137BB00552D46 /* Release */,
641 | );
642 | defaultConfigurationIsVisible = 0;
643 | defaultConfigurationName = Release;
644 | };
645 | /* End XCConfigurationList section */
646 | };
647 | rootObject = C98B8D2E1F91361700552D46 /* Project object */;
648 | }
649 |
--------------------------------------------------------------------------------