├── docs ├── img │ ├── dash.png │ ├── gh.png │ └── carat.png ├── docsets │ ├── NumericPicker.tgz │ └── NumericPicker.docset │ │ └── Contents │ │ ├── Resources │ │ ├── docSet.dsidx │ │ └── Documents │ │ │ ├── img │ │ │ ├── gh.png │ │ │ ├── carat.png │ │ │ └── dash.png │ │ │ ├── js │ │ │ └── jazzy.js │ │ │ ├── Classes.html │ │ │ ├── search.json │ │ │ ├── css │ │ │ ├── highlight.css │ │ │ └── jazzy.css │ │ │ └── index.html │ │ └── Info.plist ├── undocumented.json ├── badge.svg ├── js │ └── jazzy.js ├── Classes.html ├── search.json ├── css │ ├── highlight.css │ └── jazzy.css └── index.html ├── NumericPicker.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcshareddata │ └── xcschemes │ │ ├── NumericPicker-Example.xcscheme │ │ └── NumericPicker.xcscheme └── project.pbxproj ├── Package.swift ├── .travis.yml ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── .gitignore ├── Tests ├── Info.plist └── NumericPickerTests │ ├── NumericPickerUnitTests.swift │ ├── ComponentsStringTests.swift │ └── DisplayStringTests.swift ├── Info.plist ├── LICENSE.md ├── NumericPicker.podspec ├── NumericPicker-Example ├── Info.plist ├── AppDelegate.swift ├── Base.lproj │ ├── LaunchScreen.storyboard │ ├── LaunchScreen.xib │ └── Main.storyboard ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json └── ViewController.swift ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── README.md └── Sources └── NumericPicker.swift /docs/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattLewin/NumericPicker/HEAD/docs/img/dash.png -------------------------------------------------------------------------------- /docs/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattLewin/NumericPicker/HEAD/docs/img/gh.png -------------------------------------------------------------------------------- /docs/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattLewin/NumericPicker/HEAD/docs/img/carat.png -------------------------------------------------------------------------------- /docs/docsets/NumericPicker.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattLewin/NumericPicker/HEAD/docs/docsets/NumericPicker.tgz -------------------------------------------------------------------------------- /docs/docsets/NumericPicker.docset/Contents/Resources/docSet.dsidx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattLewin/NumericPicker/HEAD/docs/docsets/NumericPicker.docset/Contents/Resources/docSet.dsidx -------------------------------------------------------------------------------- /docs/docsets/NumericPicker.docset/Contents/Resources/Documents/img/gh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattLewin/NumericPicker/HEAD/docs/docsets/NumericPicker.docset/Contents/Resources/Documents/img/gh.png -------------------------------------------------------------------------------- /docs/docsets/NumericPicker.docset/Contents/Resources/Documents/img/carat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattLewin/NumericPicker/HEAD/docs/docsets/NumericPicker.docset/Contents/Resources/Documents/img/carat.png -------------------------------------------------------------------------------- /docs/docsets/NumericPicker.docset/Contents/Resources/Documents/img/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MattLewin/NumericPicker/HEAD/docs/docsets/NumericPicker.docset/Contents/Resources/Documents/img/dash.png -------------------------------------------------------------------------------- /NumericPicker.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // NOTE: The Swift Package Manager does not currently support UIKit or iOS. Thus this file is of no use. It is here for 2 | // future use. 3 | /* 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "NumericPicker" 8 | ) 9 | */ 10 | -------------------------------------------------------------------------------- /NumericPicker.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/undocumented.json: -------------------------------------------------------------------------------- 1 | { 2 | "warnings": [ 3 | { 4 | "file": "/Users/Matt/src/Cocoapods-dev/NumericPicker/Sources/NumericPicker.swift", 5 | "line": 351, 6 | "symbol": "NumericPicker.pickerView(_:accessibilityLabelForComponent:)", 7 | "symbol_kind": "source.lang.swift.decl.function.method.instance", 8 | "warning": "undocumented" 9 | } 10 | ], 11 | "source_directory": "/Users/Matt/src/Cocoapods-dev/NumericPicker" 12 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * http://www.objc.io/issue-6/travis-ci.html 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | osx_image: xcode10 6 | language: objective-c 7 | xcode_project: NumericPicker.xcodeproj 8 | xcode_scheme: NumericPicker 9 | cache: 10 | - bundler 11 | - xcpretty 12 | before_install: 13 | - gem install xcpretty --no-document 14 | script: 15 | - set -o pipefail && travis_retry xcodebuild test -project NumericPicker.xcodeproj -scheme NumericPicker -destination 'platform=iOS Simulator,name=iPhone X,OS=11.4' ONLY_ACTIVE_ARCH=NO | xcpretty 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /docs/docsets/NumericPicker.docset/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIdentifier 6 | com.jazzy.numericpicker 7 | CFBundleName 8 | NumericPicker 9 | DocSetPlatformFamily 10 | numericpicker 11 | isDashDocset 12 | 13 | dashIndexFilePath 14 | index.html 15 | isJavaScriptEnabled 16 | 17 | DashDocSetFamily 18 | dashtoc 19 | 20 | 21 | -------------------------------------------------------------------------------- /docs/badge.svg: -------------------------------------------------------------------------------- 1 | documentationdocumentation95%95% -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Identify a problem 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Configuration (please complete the following information):** 24 | - iOS version: [e.g. 11.4.1] 25 | - NumericPicker version: [e.g. 0.5] 26 | - Device: [e.g. iPhone 8+] 27 | 28 | **Additional context** 29 | Add any other context about the problem here. 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Swift Package Manager 23 | .build/ 24 | 25 | # Bundler 26 | .bundle 27 | 28 | Carthage 29 | # We recommend against adding the Pods directory to your .gitignore. However 30 | # you should judge for yourself, the pros and cons are mentioned at: 31 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 32 | # 33 | # Note: if you ignore the Pods directory, make sure to uncomment 34 | # `pod install` in .travis.yml 35 | # 36 | # Pods/ 37 | -------------------------------------------------------------------------------- /Tests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /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 | FMWK 17 | CFBundleShortVersionString 18 | 1 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017-2018 MoGroups 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 |
15 |
16 |

NumericPicker Docs (95% documented)

17 |
18 |
19 |
20 | 25 |
26 |
27 | 39 |
40 |
41 |
42 |

Classes

43 |

The following classes are available globally.

44 | 45 |
46 |
47 |
48 |
    49 |
  • 50 |
    51 | 52 | 53 | 54 | NumericPicker 55 | 56 |
    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 |

    Sample Video

    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 |
15 |
16 |

NumericPicker Docs (95% documented)

17 |
18 |
19 |
20 | 25 |
26 |
27 | 39 |
40 |
41 |
42 |

Classes

43 |

The following classes are available globally.

44 | 45 |
46 |
47 |
48 |
    49 |
  • 50 |
    51 | 52 | 53 | 54 | NumericPicker 55 | 56 |
    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 |

    Sample Video

    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 | 25 | 31 | 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 | [![Version](https://img.shields.io/cocoapods/v/NumericPicker.svg?style=flat)](http://cocoapods.org/pods/NumericPicker) 4 | [![License](https://img.shields.io/cocoapods/l/NumericPicker.svg?style=flat)](http://cocoapods.org/pods/NumericPicker) 5 | [![Platform](https://img.shields.io/cocoapods/p/NumericPicker.svg?style=flat)](http://cocoapods.org/pods/NumericPicker) 6 | [![Swift Version](https://img.shields.io/badge/swift-4.2-blue.svg?style=flat)](https://swift.org) 7 | [![CI Status](http://img.shields.io/travis/MattLewin/NumericPicker.svg?style=flat)](https://travis-ci.org/MattLewin/NumericPicker) 8 | 9 | [![CocoaPods](https://img.shields.io/badge/CocoaPods-compatible-4BC51D.svg?style=flat)](https://cocoapods.org/pods/NumericPicker) 10 | [![Carthage](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 11 | [![Swift Package Manager](https://img.shields.io/badge/SPM-not%20yet-red.svg?style=flat)](https://swift.org/package-manager/) 12 | 13 | [![GitHub release](https://img.shields.io/github/release/MattLewin/NumericPicker.svg)](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 | ![Sample Video](https://cl.ly/j5XO/Screen%20Recording%202017-02-08%20at%2003.36%20PM.gif) 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 | ![IBAction](https://cl.ly/1s1Q1E3J3w1c/IBAction.png) 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 | ![IB NumericPicker](https://cl.ly/j5h1/NumericPicker-IB.png) 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 | 34 | 35 | 36 | 37 | 43 | 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 | 92 | 93 | 94 | 95 | 101 | 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 |
15 |
16 |

NumericPicker Docs (95% documented)

17 |
18 |
19 |
20 | 25 |
26 |
27 | 39 |
40 |
41 |
42 | 43 |

NumericPicker

44 | 45 |

Version 46 | License 47 | Platform 48 | Swift Version 49 | CI Status

50 | 51 |

CocoaPods 52 | Carthage 53 | Swift Package Manager

54 | 55 |

GitHub release

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 |

Sample Video

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 |
  1. Copy NumericPicker.swift into your project
  2. 126 |
  3. Have a nice day
  4. 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 |

IBAction

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 |

IB NumericPicker

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 |
15 |
16 |

NumericPicker Docs (95% documented)

17 |
18 |
19 |
20 | 25 |
26 |
27 | 39 |
40 |
41 |
42 | 43 |

NumericPicker

44 | 45 |

Version 46 | License 47 | Platform 48 | Swift Version 49 | CI Status

50 | 51 |

CocoaPods 52 | Carthage 53 | Swift Package Manager

54 | 55 |

GitHub release

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 |

Sample Video

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 |
  1. Copy NumericPicker.swift into your project
  2. 126 |
  3. Have a nice day
  4. 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 |

IBAction

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 |

IB NumericPicker

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 | ![Sample Video](https://cl.ly/j5XO/Screen%20Recording%202017-02-08%20at%2003.36%20PM.gif) 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 | --------------------------------------------------------------------------------