├── .gitignore ├── Example ├── Example.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── Example │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── logo-1024.png │ │ ├── logo-20.png │ │ ├── logo-20@2x.png │ │ ├── logo-20@3x.png │ │ ├── logo-29.png │ │ ├── logo-29@2x.png │ │ ├── logo-29@3x.png │ │ ├── logo-40.png │ │ ├── logo-40@2x.png │ │ ├── logo-40@3x.png │ │ ├── logo-60@2x.png │ │ ├── logo-60@3x.png │ │ ├── logo-76.png │ │ ├── logo-76@2x.png │ │ └── logo-83.5@2x.png │ └── Contents.json │ ├── Components │ ├── Handle │ │ ├── BlueSliderHandle.swift │ │ └── OrangeSliderHandle.swift │ ├── Tick │ │ └── BlueSliderTick.swift │ └── Track │ │ ├── BlueSliderTrack.swift │ │ └── OrangeSliderTrack.swift │ ├── ContentView.swift │ ├── ExampleApp.swift │ └── Info.plist ├── LICENSE ├── Package.swift ├── README.md ├── STDiscreteSlider.podspec └── Sources └── STDiscreteSlider ├── Components ├── Handle │ ├── AnySliderHandle.swift │ ├── DefaultSliderHandle.swift │ └── SliderHandle.swift ├── Tick │ ├── AnySliderTick.swift │ ├── DefaultSliderTick.swift │ └── SliderTick.swift └── Track │ ├── AnySliderTrack.swift │ ├── DefaultSliderTrack.swift │ └── SliderTrack.swift └── View └── STDiscreteSlider.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .swiftpm 3 | 4 | xcuserdata/ 5 | 6 | Package.resolved -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 085E752926CE6FE6006C25A1 /* ExampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 085E752826CE6FE6006C25A1 /* ExampleApp.swift */; }; 11 | 085E752B26CE6FE6006C25A1 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 085E752A26CE6FE6006C25A1 /* ContentView.swift */; }; 12 | 085E752D26CE6FE7006C25A1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 085E752C26CE6FE7006C25A1 /* Assets.xcassets */; }; 13 | 085E753A26CE7086006C25A1 /* STDiscreteSlider in Frameworks */ = {isa = PBXBuildFile; productRef = 085E753926CE7086006C25A1 /* STDiscreteSlider */; }; 14 | 085E753C26CE70A4006C25A1 /* OrangeSliderTrack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 085E753B26CE70A4006C25A1 /* OrangeSliderTrack.swift */; }; 15 | 085E754126CE7166006C25A1 /* OrangeSliderHandle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 085E754026CE7166006C25A1 /* OrangeSliderHandle.swift */; }; 16 | 088427BD26CE9A74001CFDDD /* BlueSliderTick.swift in Sources */ = {isa = PBXBuildFile; fileRef = 088427BC26CE9A74001CFDDD /* BlueSliderTick.swift */; }; 17 | 088427BF26CE9B69001CFDDD /* BlueSliderHandle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 088427BE26CE9B69001CFDDD /* BlueSliderHandle.swift */; }; 18 | 088427C126CE9BA9001CFDDD /* BlueSliderTrack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 088427C026CE9BA9001CFDDD /* BlueSliderTrack.swift */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 085E752526CE6FE6006C25A1 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | 085E752826CE6FE6006C25A1 /* ExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExampleApp.swift; sourceTree = ""; }; 24 | 085E752A26CE6FE6006C25A1 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 25 | 085E752C26CE6FE7006C25A1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 26 | 085E753126CE6FE7006C25A1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 27 | 085E753826CE7040006C25A1 /* STDiscreteSlider */ = {isa = PBXFileReference; lastKnownFileType = folder; name = STDiscreteSlider; path = ..; sourceTree = ""; }; 28 | 085E753B26CE70A4006C25A1 /* OrangeSliderTrack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrangeSliderTrack.swift; sourceTree = ""; }; 29 | 085E754026CE7166006C25A1 /* OrangeSliderHandle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrangeSliderHandle.swift; sourceTree = ""; }; 30 | 088427BC26CE9A74001CFDDD /* BlueSliderTick.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlueSliderTick.swift; sourceTree = ""; }; 31 | 088427BE26CE9B69001CFDDD /* BlueSliderHandle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlueSliderHandle.swift; sourceTree = ""; }; 32 | 088427C026CE9BA9001CFDDD /* BlueSliderTrack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlueSliderTrack.swift; sourceTree = ""; }; 33 | /* End PBXFileReference section */ 34 | 35 | /* Begin PBXFrameworksBuildPhase section */ 36 | 085E752226CE6FE6006C25A1 /* Frameworks */ = { 37 | isa = PBXFrameworksBuildPhase; 38 | buildActionMask = 2147483647; 39 | files = ( 40 | 085E753A26CE7086006C25A1 /* STDiscreteSlider in Frameworks */, 41 | ); 42 | runOnlyForDeploymentPostprocessing = 0; 43 | }; 44 | /* End PBXFrameworksBuildPhase section */ 45 | 46 | /* Begin PBXGroup section */ 47 | 085E751C26CE6FE6006C25A1 = { 48 | isa = PBXGroup; 49 | children = ( 50 | 085E752726CE6FE6006C25A1 /* Example */, 51 | 085E752626CE6FE6006C25A1 /* Products */, 52 | 085E753726CE7040006C25A1 /* Frameworks */, 53 | ); 54 | sourceTree = ""; 55 | }; 56 | 085E752626CE6FE6006C25A1 /* Products */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 085E752526CE6FE6006C25A1 /* Example.app */, 60 | ); 61 | name = Products; 62 | sourceTree = ""; 63 | }; 64 | 085E752726CE6FE6006C25A1 /* Example */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 085E753D26CE7156006C25A1 /* Components */, 68 | 085E752826CE6FE6006C25A1 /* ExampleApp.swift */, 69 | 085E752A26CE6FE6006C25A1 /* ContentView.swift */, 70 | 085E752C26CE6FE7006C25A1 /* Assets.xcassets */, 71 | 085E753126CE6FE7006C25A1 /* Info.plist */, 72 | ); 73 | path = Example; 74 | sourceTree = ""; 75 | }; 76 | 085E753726CE7040006C25A1 /* Frameworks */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 085E753826CE7040006C25A1 /* STDiscreteSlider */, 80 | ); 81 | name = Frameworks; 82 | sourceTree = ""; 83 | }; 84 | 085E753D26CE7156006C25A1 /* Components */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 088427BB26CE9A50001CFDDD /* Tick */, 88 | 085E753F26CE715F006C25A1 /* Handle */, 89 | 085E753E26CE715B006C25A1 /* Track */, 90 | ); 91 | path = Components; 92 | sourceTree = ""; 93 | }; 94 | 085E753E26CE715B006C25A1 /* Track */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 085E753B26CE70A4006C25A1 /* OrangeSliderTrack.swift */, 98 | 088427C026CE9BA9001CFDDD /* BlueSliderTrack.swift */, 99 | ); 100 | path = Track; 101 | sourceTree = ""; 102 | }; 103 | 085E753F26CE715F006C25A1 /* Handle */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 085E754026CE7166006C25A1 /* OrangeSliderHandle.swift */, 107 | 088427BE26CE9B69001CFDDD /* BlueSliderHandle.swift */, 108 | ); 109 | path = Handle; 110 | sourceTree = ""; 111 | }; 112 | 088427BB26CE9A50001CFDDD /* Tick */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 088427BC26CE9A74001CFDDD /* BlueSliderTick.swift */, 116 | ); 117 | path = Tick; 118 | sourceTree = ""; 119 | }; 120 | /* End PBXGroup section */ 121 | 122 | /* Begin PBXNativeTarget section */ 123 | 085E752426CE6FE6006C25A1 /* Example */ = { 124 | isa = PBXNativeTarget; 125 | buildConfigurationList = 085E753426CE6FE7006C25A1 /* Build configuration list for PBXNativeTarget "Example" */; 126 | buildPhases = ( 127 | 085E752126CE6FE6006C25A1 /* Sources */, 128 | 085E752226CE6FE6006C25A1 /* Frameworks */, 129 | 085E752326CE6FE6006C25A1 /* Resources */, 130 | ); 131 | buildRules = ( 132 | ); 133 | dependencies = ( 134 | ); 135 | name = Example; 136 | packageProductDependencies = ( 137 | 085E753926CE7086006C25A1 /* STDiscreteSlider */, 138 | ); 139 | productName = Example; 140 | productReference = 085E752526CE6FE6006C25A1 /* Example.app */; 141 | productType = "com.apple.product-type.application"; 142 | }; 143 | /* End PBXNativeTarget section */ 144 | 145 | /* Begin PBXProject section */ 146 | 085E751D26CE6FE6006C25A1 /* Project object */ = { 147 | isa = PBXProject; 148 | attributes = { 149 | LastSwiftUpdateCheck = 1250; 150 | LastUpgradeCheck = 1250; 151 | TargetAttributes = { 152 | 085E752426CE6FE6006C25A1 = { 153 | CreatedOnToolsVersion = 12.5.1; 154 | }; 155 | }; 156 | }; 157 | buildConfigurationList = 085E752026CE6FE6006C25A1 /* Build configuration list for PBXProject "Example" */; 158 | compatibilityVersion = "Xcode 9.3"; 159 | developmentRegion = en; 160 | hasScannedForEncodings = 0; 161 | knownRegions = ( 162 | en, 163 | Base, 164 | ); 165 | mainGroup = 085E751C26CE6FE6006C25A1; 166 | productRefGroup = 085E752626CE6FE6006C25A1 /* Products */; 167 | projectDirPath = ""; 168 | projectRoot = ""; 169 | targets = ( 170 | 085E752426CE6FE6006C25A1 /* Example */, 171 | ); 172 | }; 173 | /* End PBXProject section */ 174 | 175 | /* Begin PBXResourcesBuildPhase section */ 176 | 085E752326CE6FE6006C25A1 /* Resources */ = { 177 | isa = PBXResourcesBuildPhase; 178 | buildActionMask = 2147483647; 179 | files = ( 180 | 085E752D26CE6FE7006C25A1 /* Assets.xcassets in Resources */, 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | }; 184 | /* End PBXResourcesBuildPhase section */ 185 | 186 | /* Begin PBXSourcesBuildPhase section */ 187 | 085E752126CE6FE6006C25A1 /* Sources */ = { 188 | isa = PBXSourcesBuildPhase; 189 | buildActionMask = 2147483647; 190 | files = ( 191 | 088427BF26CE9B69001CFDDD /* BlueSliderHandle.swift in Sources */, 192 | 088427BD26CE9A74001CFDDD /* BlueSliderTick.swift in Sources */, 193 | 085E754126CE7166006C25A1 /* OrangeSliderHandle.swift in Sources */, 194 | 085E752B26CE6FE6006C25A1 /* ContentView.swift in Sources */, 195 | 085E753C26CE70A4006C25A1 /* OrangeSliderTrack.swift in Sources */, 196 | 088427C126CE9BA9001CFDDD /* BlueSliderTrack.swift in Sources */, 197 | 085E752926CE6FE6006C25A1 /* ExampleApp.swift in Sources */, 198 | ); 199 | runOnlyForDeploymentPostprocessing = 0; 200 | }; 201 | /* End PBXSourcesBuildPhase section */ 202 | 203 | /* Begin XCBuildConfiguration section */ 204 | 085E753226CE6FE7006C25A1 /* Debug */ = { 205 | isa = XCBuildConfiguration; 206 | buildSettings = { 207 | ALWAYS_SEARCH_USER_PATHS = NO; 208 | CLANG_ANALYZER_NONNULL = YES; 209 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 210 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 211 | CLANG_CXX_LIBRARY = "libc++"; 212 | CLANG_ENABLE_MODULES = YES; 213 | CLANG_ENABLE_OBJC_ARC = YES; 214 | CLANG_ENABLE_OBJC_WEAK = YES; 215 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 216 | CLANG_WARN_BOOL_CONVERSION = YES; 217 | CLANG_WARN_COMMA = YES; 218 | CLANG_WARN_CONSTANT_CONVERSION = YES; 219 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 220 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 221 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 222 | CLANG_WARN_EMPTY_BODY = YES; 223 | CLANG_WARN_ENUM_CONVERSION = YES; 224 | CLANG_WARN_INFINITE_RECURSION = YES; 225 | CLANG_WARN_INT_CONVERSION = YES; 226 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 227 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 228 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 229 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 230 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 231 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 232 | CLANG_WARN_STRICT_PROTOTYPES = YES; 233 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 234 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 235 | CLANG_WARN_UNREACHABLE_CODE = YES; 236 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 237 | COPY_PHASE_STRIP = NO; 238 | DEBUG_INFORMATION_FORMAT = dwarf; 239 | ENABLE_STRICT_OBJC_MSGSEND = YES; 240 | ENABLE_TESTABILITY = YES; 241 | GCC_C_LANGUAGE_STANDARD = gnu11; 242 | GCC_DYNAMIC_NO_PIC = NO; 243 | GCC_NO_COMMON_BLOCKS = YES; 244 | GCC_OPTIMIZATION_LEVEL = 0; 245 | GCC_PREPROCESSOR_DEFINITIONS = ( 246 | "DEBUG=1", 247 | "$(inherited)", 248 | ); 249 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 250 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 251 | GCC_WARN_UNDECLARED_SELECTOR = YES; 252 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 253 | GCC_WARN_UNUSED_FUNCTION = YES; 254 | GCC_WARN_UNUSED_VARIABLE = YES; 255 | IPHONEOS_DEPLOYMENT_TARGET = 14.5; 256 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 257 | MTL_FAST_MATH = YES; 258 | ONLY_ACTIVE_ARCH = YES; 259 | SDKROOT = iphoneos; 260 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 261 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 262 | }; 263 | name = Debug; 264 | }; 265 | 085E753326CE6FE7006C25A1 /* Release */ = { 266 | isa = XCBuildConfiguration; 267 | buildSettings = { 268 | ALWAYS_SEARCH_USER_PATHS = NO; 269 | CLANG_ANALYZER_NONNULL = YES; 270 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 271 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 272 | CLANG_CXX_LIBRARY = "libc++"; 273 | CLANG_ENABLE_MODULES = YES; 274 | CLANG_ENABLE_OBJC_ARC = YES; 275 | CLANG_ENABLE_OBJC_WEAK = YES; 276 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 277 | CLANG_WARN_BOOL_CONVERSION = YES; 278 | CLANG_WARN_COMMA = YES; 279 | CLANG_WARN_CONSTANT_CONVERSION = YES; 280 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 281 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 282 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 283 | CLANG_WARN_EMPTY_BODY = YES; 284 | CLANG_WARN_ENUM_CONVERSION = YES; 285 | CLANG_WARN_INFINITE_RECURSION = YES; 286 | CLANG_WARN_INT_CONVERSION = YES; 287 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 288 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 289 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 290 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 291 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 292 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 293 | CLANG_WARN_STRICT_PROTOTYPES = YES; 294 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 295 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 296 | CLANG_WARN_UNREACHABLE_CODE = YES; 297 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 298 | COPY_PHASE_STRIP = NO; 299 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 300 | ENABLE_NS_ASSERTIONS = NO; 301 | ENABLE_STRICT_OBJC_MSGSEND = YES; 302 | GCC_C_LANGUAGE_STANDARD = gnu11; 303 | GCC_NO_COMMON_BLOCKS = YES; 304 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 305 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 306 | GCC_WARN_UNDECLARED_SELECTOR = YES; 307 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 308 | GCC_WARN_UNUSED_FUNCTION = YES; 309 | GCC_WARN_UNUSED_VARIABLE = YES; 310 | IPHONEOS_DEPLOYMENT_TARGET = 14.5; 311 | MTL_ENABLE_DEBUG_INFO = NO; 312 | MTL_FAST_MATH = YES; 313 | SDKROOT = iphoneos; 314 | SWIFT_COMPILATION_MODE = wholemodule; 315 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 316 | VALIDATE_PRODUCT = YES; 317 | }; 318 | name = Release; 319 | }; 320 | 085E753526CE6FE7006C25A1 /* Debug */ = { 321 | isa = XCBuildConfiguration; 322 | buildSettings = { 323 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 324 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 325 | CODE_SIGN_STYLE = Automatic; 326 | DEVELOPMENT_ASSET_PATHS = ""; 327 | DEVELOPMENT_TEAM = H72YUS24CN; 328 | ENABLE_PREVIEWS = YES; 329 | INFOPLIST_FILE = Example/Info.plist; 330 | IPHONEOS_DEPLOYMENT_TARGET = 14.1; 331 | LD_RUNPATH_SEARCH_PATHS = ( 332 | "$(inherited)", 333 | "@executable_path/Frameworks", 334 | ); 335 | PRODUCT_BUNDLE_IDENTIFIER = tsatualdypov.Example; 336 | PRODUCT_NAME = "$(TARGET_NAME)"; 337 | SWIFT_VERSION = 5.0; 338 | TARGETED_DEVICE_FAMILY = 1; 339 | }; 340 | name = Debug; 341 | }; 342 | 085E753626CE6FE7006C25A1 /* Release */ = { 343 | isa = XCBuildConfiguration; 344 | buildSettings = { 345 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 346 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 347 | CODE_SIGN_STYLE = Automatic; 348 | DEVELOPMENT_ASSET_PATHS = ""; 349 | DEVELOPMENT_TEAM = H72YUS24CN; 350 | ENABLE_PREVIEWS = YES; 351 | INFOPLIST_FILE = Example/Info.plist; 352 | IPHONEOS_DEPLOYMENT_TARGET = 14.1; 353 | LD_RUNPATH_SEARCH_PATHS = ( 354 | "$(inherited)", 355 | "@executable_path/Frameworks", 356 | ); 357 | PRODUCT_BUNDLE_IDENTIFIER = tsatualdypov.Example; 358 | PRODUCT_NAME = "$(TARGET_NAME)"; 359 | SWIFT_VERSION = 5.0; 360 | TARGETED_DEVICE_FAMILY = 1; 361 | }; 362 | name = Release; 363 | }; 364 | /* End XCBuildConfiguration section */ 365 | 366 | /* Begin XCConfigurationList section */ 367 | 085E752026CE6FE6006C25A1 /* Build configuration list for PBXProject "Example" */ = { 368 | isa = XCConfigurationList; 369 | buildConfigurations = ( 370 | 085E753226CE6FE7006C25A1 /* Debug */, 371 | 085E753326CE6FE7006C25A1 /* Release */, 372 | ); 373 | defaultConfigurationIsVisible = 0; 374 | defaultConfigurationName = Release; 375 | }; 376 | 085E753426CE6FE7006C25A1 /* Build configuration list for PBXNativeTarget "Example" */ = { 377 | isa = XCConfigurationList; 378 | buildConfigurations = ( 379 | 085E753526CE6FE7006C25A1 /* Debug */, 380 | 085E753626CE6FE7006C25A1 /* Release */, 381 | ); 382 | defaultConfigurationIsVisible = 0; 383 | defaultConfigurationName = Release; 384 | }; 385 | /* End XCConfigurationList section */ 386 | 387 | /* Begin XCSwiftPackageProductDependency section */ 388 | 085E753926CE7086006C25A1 /* STDiscreteSlider */ = { 389 | isa = XCSwiftPackageProductDependency; 390 | productName = STDiscreteSlider; 391 | }; 392 | /* End XCSwiftPackageProductDependency section */ 393 | }; 394 | rootObject = 085E751D26CE6FE6006C25A1 /* Project object */; 395 | } 396 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom": "iphone", 6 | "filename" : "logo-20@2x.png", 7 | "scale": "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom": "iphone", 12 | "filename" : "logo-20@3x.png", 13 | "scale": "3x" 14 | }, 15 | { 16 | "size" : "20x20", 17 | "idiom": "ipad", 18 | "filename" : "logo-20.png", 19 | "scale": "1x" 20 | }, 21 | { 22 | "size" : "20x20", 23 | "idiom": "ipad", 24 | "filename" : "logo-20@2x.png", 25 | "scale": "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "logo-29@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "29x29", 35 | "idiom" : "iphone", 36 | "filename" : "logo-29@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "logo-40@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "40x40", 47 | "idiom" : "iphone", 48 | "filename" : "logo-40@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "logo-60@2x.png", 55 | "scale" : "2x" 56 | }, 57 | { 58 | "size" : "60x60", 59 | "idiom" : "iphone", 60 | "filename" : "logo-60@3x.png", 61 | "scale" : "3x" 62 | }, 63 | { 64 | "size" : "29x29", 65 | "idiom" : "ipad", 66 | "filename" : "logo-29.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "logo-29@2x.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "40x40", 77 | "idiom" : "ipad", 78 | "filename" : "logo-40.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "logo-40@2x.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "76x76", 89 | "idiom" : "ipad", 90 | "filename" : "logo-76.png", 91 | "scale" : "1x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "logo-76@2x.png", 97 | "scale" : "2x" 98 | }, 99 | { 100 | "size" : "83.5x83.5", 101 | "idiom" : "ipad", 102 | "filename" : "logo-83.5@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "1024x1024", 107 | "idiom" : "ios-marketing", 108 | "filename" : "logo-1024.png", 109 | "scale" : "1x" 110 | } 111 | ], 112 | "info" : { 113 | "version" : 1, 114 | "author" : "xcode" 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/logo-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/STDiscreteSlider/3bf42944532423e42092663ef1fba86ece00f2f1/Example/Example/Assets.xcassets/AppIcon.appiconset/logo-1024.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/logo-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/STDiscreteSlider/3bf42944532423e42092663ef1fba86ece00f2f1/Example/Example/Assets.xcassets/AppIcon.appiconset/logo-20.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/logo-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/STDiscreteSlider/3bf42944532423e42092663ef1fba86ece00f2f1/Example/Example/Assets.xcassets/AppIcon.appiconset/logo-20@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/logo-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/STDiscreteSlider/3bf42944532423e42092663ef1fba86ece00f2f1/Example/Example/Assets.xcassets/AppIcon.appiconset/logo-20@3x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/logo-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/STDiscreteSlider/3bf42944532423e42092663ef1fba86ece00f2f1/Example/Example/Assets.xcassets/AppIcon.appiconset/logo-29.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/logo-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/STDiscreteSlider/3bf42944532423e42092663ef1fba86ece00f2f1/Example/Example/Assets.xcassets/AppIcon.appiconset/logo-29@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/logo-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/STDiscreteSlider/3bf42944532423e42092663ef1fba86ece00f2f1/Example/Example/Assets.xcassets/AppIcon.appiconset/logo-29@3x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/logo-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/STDiscreteSlider/3bf42944532423e42092663ef1fba86ece00f2f1/Example/Example/Assets.xcassets/AppIcon.appiconset/logo-40.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/logo-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/STDiscreteSlider/3bf42944532423e42092663ef1fba86ece00f2f1/Example/Example/Assets.xcassets/AppIcon.appiconset/logo-40@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/logo-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/STDiscreteSlider/3bf42944532423e42092663ef1fba86ece00f2f1/Example/Example/Assets.xcassets/AppIcon.appiconset/logo-40@3x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/logo-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/STDiscreteSlider/3bf42944532423e42092663ef1fba86ece00f2f1/Example/Example/Assets.xcassets/AppIcon.appiconset/logo-60@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/logo-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/STDiscreteSlider/3bf42944532423e42092663ef1fba86ece00f2f1/Example/Example/Assets.xcassets/AppIcon.appiconset/logo-60@3x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/logo-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/STDiscreteSlider/3bf42944532423e42092663ef1fba86ece00f2f1/Example/Example/Assets.xcassets/AppIcon.appiconset/logo-76.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/logo-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/STDiscreteSlider/3bf42944532423e42092663ef1fba86ece00f2f1/Example/Example/Assets.xcassets/AppIcon.appiconset/logo-76@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/logo-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/onl1ner/STDiscreteSlider/3bf42944532423e42092663ef1fba86ece00f2f1/Example/Example/Assets.xcassets/AppIcon.appiconset/logo-83.5@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Example/Components/Handle/BlueSliderHandle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | import STDiscreteSlider 26 | 27 | struct BlueSliderHandle: SliderHandle { 28 | 29 | public var width: CGFloat = 16.0 30 | public var height: CGFloat = 16.0 31 | 32 | public func makeHandle() -> some View { 33 | ZStack { 34 | Circle() 35 | .frame(width: self.width, height: self.height) 36 | .foregroundColor(.blue) 37 | 38 | Circle() 39 | .frame(width: self.width - 4.0, height: self.height - 4.0) 40 | .foregroundColor(.white) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Example/Example/Components/Handle/OrangeSliderHandle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | import STDiscreteSlider 26 | 27 | struct OrangeSliderHandle: SliderHandle { 28 | 29 | public var width: CGFloat = 16.0 30 | public var height: CGFloat = 16.0 31 | 32 | public func makeHandle() -> some View { 33 | RoundedRectangle(cornerRadius: 4.0) 34 | .frame(width: self.width, height: self.height) 35 | .foregroundColor(.white) 36 | .shadow(radius: 1.0) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Example/Example/Components/Tick/BlueSliderTick.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | import STDiscreteSlider 26 | 27 | struct BlueSliderTick: SliderTick { 28 | 29 | public var width: CGFloat = 2.0 30 | public var height: CGFloat = 8.0 31 | 32 | public func makeTick() -> some View { 33 | RoundedRectangle(cornerRadius: 2.0) 34 | .frame(width: self.width, height: self.height) 35 | .foregroundColor(.blue) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Example/Example/Components/Track/BlueSliderTrack.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | import STDiscreteSlider 26 | 27 | struct BlueSliderTrack: SliderTrack { 28 | 29 | public var height: CGFloat = 2.0 30 | 31 | public func makeTrack() -> some View { 32 | RoundedRectangle(cornerRadius: 2.0) 33 | .frame(height: self.height) 34 | .foregroundColor(.gray.opacity(0.2)) 35 | } 36 | 37 | public func makeFillTrack() -> some View { 38 | RoundedRectangle(cornerRadius: 2.0) 39 | .frame(height: self.height) 40 | .foregroundColor(.blue) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /Example/Example/Components/Track/OrangeSliderTrack.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | import STDiscreteSlider 26 | 27 | struct OrangeSliderTrack: SliderTrack { 28 | 29 | public var height: CGFloat = 4.0 30 | 31 | public func makeTrack() -> some View { 32 | RoundedRectangle(cornerRadius: 2.0) 33 | .frame(height: self.height) 34 | .foregroundColor(.gray.opacity(0.2)) 35 | } 36 | 37 | public func makeFillTrack() -> some View { 38 | RoundedRectangle(cornerRadius: 2.0) 39 | .frame(height: self.height) 40 | .foregroundColor(.orange) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /Example/Example/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | import STDiscreteSlider 26 | 27 | struct ContentView: View { 28 | 29 | @State private var selectedItem: String 30 | 31 | private let options: [String] 32 | 33 | public init(options: [String]) { 34 | self.options = options 35 | self.selectedItem = options[0] 36 | } 37 | 38 | var body: some View { 39 | ZStack { 40 | Color.gray.opacity(0.1) 41 | 42 | VStack(alignment: .leading, spacing: 16.0) { 43 | VStack(alignment: .leading) { 44 | Text("Default") 45 | .font(.caption) 46 | 47 | STDiscreteSlider( 48 | options: self.options, 49 | selectedItem: $selectedItem 50 | ) 51 | .padding(.all, 16.0) 52 | .background(Color.white) 53 | .cornerRadius(8.0) 54 | } 55 | 56 | VStack(alignment: .leading) { 57 | Text("Custom #1") 58 | .font(.caption) 59 | 60 | STDiscreteSlider( 61 | options: self.options, 62 | track: OrangeSliderTrack(), 63 | handle: OrangeSliderHandle(), 64 | selectedItem: $selectedItem 65 | ) 66 | .padding(.all, 16.0) 67 | .background(Color.white) 68 | .cornerRadius(8.0) 69 | } 70 | 71 | VStack(alignment: .leading) { 72 | Text("Custom #2") 73 | .font(.caption) 74 | 75 | STDiscreteSlider( 76 | options: self.options, 77 | track: BlueSliderTrack(), 78 | tick: BlueSliderTick(), 79 | handle: BlueSliderHandle(), 80 | selectedItem: $selectedItem 81 | ) 82 | .padding(.all, 16.0) 83 | .background(Color.white) 84 | .cornerRadius(8.0) 85 | } 86 | } 87 | .padding() 88 | } 89 | } 90 | } 91 | 92 | struct ContentView_Previews: PreviewProvider { 93 | static var previews: some View { 94 | ContentView( 95 | options: 96 | ["First", 97 | "Second", 98 | "Third", 99 | "Fourth"] 100 | ) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Example/Example/ExampleApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | 26 | @main 27 | struct ExampleApp: App { 28 | var body: some Scene { 29 | WindowGroup { 30 | ContentView( 31 | options: 32 | ["First", 33 | "Second", 34 | "Third", 35 | "Fourth"] 36 | ) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Example/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | 28 | UIApplicationSupportsIndirectInputEvents 29 | 30 | UILaunchScreen 31 | 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | 40 | UISupportedInterfaceOrientations~ipad 41 | 42 | UIInterfaceOrientationPortrait 43 | UIInterfaceOrientationPortraitUpsideDown 44 | UIInterfaceOrientationLandscapeLeft 45 | UIInterfaceOrientationLandscapeRight 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Tamerlan Satualdypov 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 all 13 | 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 THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.2 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "STDiscreteSlider", 7 | platforms: [ 8 | .iOS(.v13) 9 | ], 10 | products: [ 11 | .library( 12 | name: "STDiscreteSlider", 13 | targets: ["STDiscreteSlider"] 14 | ) 15 | ], 16 | targets: [ 17 | .target(name: "STDiscreteSlider") 18 | ] 19 | ) 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # STDiscreteSlider 4 | 5 | ![](https://img.shields.io/badge/platform-iOS-lightgrey) 6 | ![](https://img.shields.io/badge/iOS-13.0%2B-blue) 7 | ![](https://cocoapod-badges.herokuapp.com/v/STDiscreteSlider/badge.png) 8 | ![](https://cocoapod-badges.herokuapp.com/l/STDiscreteSlider/badge.(png|svg)) 9 | ![](https://img.shields.io/badge/Swift-5-orange?logo=Swift&logoColor=white) 10 | ![](https://img.shields.io/github/last-commit/onl1ner/STDiscreteSlider) 11 | 12 | **STDiscreteSlider** – slider which allows user to choose value only from predefined set of data. Slider may receive any types of options, you may pass set of integers or strings, or any other type. Written using `SwiftUI`. 13 | 14 | ## Table of contents 15 | 16 | * [Requirements](#requirements) 17 | * [Installation](#installation) 18 | * [CocoaPods](#cocoapods) 19 | * [Swift Package Manager](#swift-package-manager) 20 | * [Usage](#usage) 21 | * [Quick start](#quick-start) 22 | * [Customization](#customization) 23 | * [Contribution](#contribution) 24 | * [License](#license) 25 | 26 | ## Requirements 27 | 28 | - SwiftUI 29 | - iOS 13.0 or above 30 | 31 | ## Installation 32 | 33 | **STDiscreteSlider** is available through [CocoaPods](https://cocoapods.org) and [Swift Package Manager](https://github.com/apple/swift-package-manager) 34 | 35 | ### CocoaPods 36 | - Add the following line into your Podfile: 37 | 38 | ```ruby 39 | pod 'STDiscreteSlider' 40 | ``` 41 | 42 | - Then run this command in your terminal: 43 | 44 | ```bash 45 | $ pod install 46 | ``` 47 | 48 | ### Swift Package Manager 49 | - In Xcode select: 50 | 51 | ``` 52 | File > Swift Packages > Add Package Dependency... 53 | ``` 54 | 55 | - Then paste this URL: 56 | 57 | ``` 58 | https://github.com/onl1ner/STDiscreteSlider.git 59 | ``` 60 | 61 | ## Usage 62 | 63 | **STDiscreteSlider** is highly customizable, you could use it with it's default appearance or create your own. 64 | 65 | ### Quick start 66 | 67 | To create a slider simply instantiate `STDiscreteSlider` class: 68 | 69 | ```swift 70 | STDiscreteSlider( 71 | options: [20, 40, 60, 80, 100], // Options that is used as a data source for the slider. 72 | selectedItem: $mySelectedItem // Binding to the property that will store the selected item. 73 | ) 74 | ``` 75 | 76 | This action will create a slider with default appearance. 77 | 78 | ### Customization 79 | 80 | Customization of a slider is not a big deal. **STDiscreteSlider** provides three protocols that is used to represent the components of a slider: `SliderTrack`, `SliderTick`, `SliderHandle`. By implementing each of the protocol you will be able to build your custom slider. 81 | 82 | Some examples of what you can achieve by customizing slider: 83 | 84 | ![](https://github.com/onl1ner/onl1ner/blob/master/Resources/STDiscreteSlider/Examples.png?raw=true) 85 | 86 | *Source code of these sliders provided in examples.* 87 | 88 | ## Contribution 89 | 90 | If you struggle with something feel free to [open an issue](https://github.com/onl1ner/STDiscreteSlider/issues/new). Pull requests are also appreciated. 91 | 92 | ## License 93 | 94 | **STDiscreteSlider** is under the terms and conditions of the MIT license. 95 | 96 | ``` 97 | MIT License 98 | 99 | Copyright (c) 2021 Tamerlan Satualdypov 100 | 101 | Permission is hereby granted, free of charge, to any person obtaining a copy 102 | of this software and associated documentation files (the "Software"), to deal 103 | in the Software without restriction, including without limitation the rights 104 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 105 | copies of the Software, and to permit persons to whom the Software is 106 | furnished to do so, subject to the following conditions: 107 | 108 | The above copyright notice and this permission notice shall be included in all 109 | copies or substantial portions of the Software. 110 | 111 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 112 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 113 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 114 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 115 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 116 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 117 | SOFTWARE. 118 | ``` 119 | -------------------------------------------------------------------------------- /STDiscreteSlider.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | 3 | spec.name = "STDiscreteSlider" 4 | spec.version = "1.0.0" 5 | spec.summary = "STDiscreteSlider – slider which allows user to choose value only from predefined set of data." 6 | 7 | spec.platform = :ios, '13.0' 8 | spec.framework = 'Foundation', 'SwiftUI' 9 | 10 | spec.swift_version = ['5.1'] 11 | 12 | spec.homepage = "https://github.com/onl1ner/STDiscreteSlider" 13 | 14 | spec.source = { :git => "https://github.com/onl1ner/STDiscreteSlider.git", :tag => "#{spec.version}" } 15 | 16 | spec.license = { :type => "MIT", :file => "LICENSE" } 17 | spec.author = { "Tamerlan Satualdypov" => "tsatualdypov@gmail.com" } 18 | 19 | spec.source_files = "Sources/STDiscreteSlider/**/*.swift" 20 | 21 | end 22 | -------------------------------------------------------------------------------- /Sources/STDiscreteSlider/Components/Handle/AnySliderHandle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | 26 | /** 27 | A type that represents any slider handle that 28 | can be used by `STDiscreteSlider`. 29 | */ 30 | public struct AnySliderHandle: SliderHandle { 31 | 32 | public let width: CGFloat 33 | public let height: CGFloat 34 | 35 | private let _makeHandle: () -> AnyView 36 | 37 | public init(handle: Handle) { 38 | self.width = handle.width 39 | self.height = handle.height 40 | 41 | self._makeHandle = handle.makeHandleErased 42 | } 43 | 44 | public func makeHandle() -> some View { 45 | return self._makeHandle() 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /Sources/STDiscreteSlider/Components/Handle/DefaultSliderHandle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | 26 | public struct DefaultSliderHandle: SliderHandle { 27 | 28 | public var width: CGFloat = 16.0 29 | public var height: CGFloat = 16.0 30 | 31 | public func makeHandle() -> some View { 32 | Circle() 33 | .frame(width: self.width, height: self.height) 34 | .foregroundColor(.blue) 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Sources/STDiscreteSlider/Components/Handle/SliderHandle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | 26 | /** 27 | Handle used to show user's selection and 28 | can be moved along the track. 29 | */ 30 | public protocol SliderHandle { 31 | associatedtype Handle: View 32 | 33 | /** 34 | The width of the slider's handle. 35 | */ 36 | var width: CGFloat { get } 37 | 38 | /** 39 | The height of the slider's handle. 40 | */ 41 | var height: CGFloat { get } 42 | 43 | /** 44 | Function that creates a handle of the slider. 45 | 46 | Implement this method to represent 47 | the handle that will be used in your slider. 48 | 49 | - Returns: 50 | Configured handle view. 51 | */ 52 | func makeHandle() -> Self.Handle 53 | } 54 | 55 | extension SliderHandle { 56 | 57 | /** 58 | Function used to type-erase view 59 | that represents slider's handle. 60 | 61 | - Returns: 62 | Type-erased handle view. 63 | */ 64 | public func makeHandleErased() -> AnyView { 65 | return .init(self.makeHandle()) 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /Sources/STDiscreteSlider/Components/Tick/AnySliderTick.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | 26 | /** 27 | A type that represents any slider tick that 28 | can be used by `STDiscreteSlider`. 29 | */ 30 | public struct AnySliderTick: SliderTick { 31 | 32 | public var width: CGFloat 33 | public var height: CGFloat 34 | 35 | private let _makeTick: () -> AnyView 36 | 37 | public init(tick: Tick) { 38 | self.width = tick.width 39 | self.height = tick.height 40 | 41 | self._makeTick = tick.makeTickErased 42 | } 43 | 44 | public func makeTick() -> some View { 45 | return self._makeTick() 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /Sources/STDiscreteSlider/Components/Tick/DefaultSliderTick.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | 26 | public struct DefaultSliderTick: SliderTick { 27 | 28 | public var width: CGFloat = 8.0 29 | public var height: CGFloat = 8.0 30 | 31 | public func makeTick() -> some View { 32 | Circle() 33 | .frame(width: self.width, height: self.height) 34 | .foregroundColor(.blue) 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Sources/STDiscreteSlider/Components/Tick/SliderTick.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | 26 | /** 27 | Tick marks are placed along a track and 28 | represent predetermined values that the 29 | user can move the slider to. 30 | */ 31 | public protocol SliderTick { 32 | associatedtype Tick: View 33 | 34 | /** 35 | The width of the tick view. 36 | */ 37 | var width: CGFloat { get } 38 | 39 | /** 40 | The height of the tick view. 41 | */ 42 | var height: CGFloat { get } 43 | 44 | /** 45 | Function that creates a tick for the slider. 46 | 47 | Implement this method to represent 48 | the ticks that will be used in your slider. 49 | 50 | - Returns: 51 | Configured tick view. 52 | */ 53 | func makeTick() -> Self.Tick 54 | } 55 | 56 | extension SliderTick { 57 | 58 | /** 59 | Function used to type-erase view 60 | that represents slider's tick. 61 | 62 | - Returns: 63 | Type-erased tick view. 64 | */ 65 | public func makeTickErased() -> AnyView { 66 | return .init(self.makeTick()) 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Sources/STDiscreteSlider/Components/Track/AnySliderTrack.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | 26 | /** 27 | A type that represents any slider track that 28 | can be used by `STDiscreteSlider`. 29 | */ 30 | public struct AnySliderTrack: SliderTrack { 31 | 32 | public let height: CGFloat 33 | 34 | private let _makeTrack: () -> AnyView 35 | private let _makeFillTrack: () -> AnyView 36 | 37 | public init(track: Track) { 38 | self.height = track.height 39 | 40 | self._makeTrack = track.makeTrackErased 41 | self._makeFillTrack = track.makeFillTrackErased 42 | } 43 | 44 | public func makeTrack() -> some View { 45 | return self._makeTrack() 46 | } 47 | 48 | public func makeFillTrack() -> some View { 49 | return self._makeFillTrack() 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Sources/STDiscreteSlider/Components/Track/DefaultSliderTrack.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | 26 | public struct DefaultSliderTrack: SliderTrack { 27 | 28 | public var height: CGFloat = 4.0 29 | 30 | public func makeTrack() -> some View { 31 | RoundedRectangle(cornerRadius: 2.0) 32 | .frame(height: self.height) 33 | .foregroundColor(.blue.opacity(0.4)) 34 | } 35 | 36 | public func makeFillTrack() -> some View { 37 | RoundedRectangle(cornerRadius: 2.0) 38 | .frame(height: self.height) 39 | .foregroundColor(.blue) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/STDiscreteSlider/Components/Track/SliderTrack.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | 26 | /** 27 | Track shows the range that can be used by a user. 28 | */ 29 | public protocol SliderTrack { 30 | associatedtype Track: View 31 | associatedtype FillTrack: View 32 | 33 | /** 34 | The height of the slider's track. 35 | */ 36 | var height: CGFloat { get } 37 | 38 | /** 39 | Function that builds a track for the slider. 40 | 41 | Implement this method to create your track 42 | that will be used in the slider. 43 | 44 | - Returns: 45 | Your configured track. 46 | */ 47 | func makeTrack() -> Self.Track 48 | 49 | /** 50 | Function that builds a track for the filled 51 | width of the track. 52 | 53 | - Returns: 54 | Your configured fill track. 55 | */ 56 | func makeFillTrack() -> Self.FillTrack 57 | } 58 | 59 | extension SliderTrack { 60 | 61 | /** 62 | Function used to type-erase view 63 | that represents slider's track. 64 | 65 | - Returns: 66 | Type-erased track view. 67 | */ 68 | public func makeTrackErased() -> AnyView { 69 | return .init(self.makeTrack()) 70 | } 71 | 72 | /** 73 | Function used to type-erase view 74 | that represents slider's filled width. 75 | 76 | - Returns: 77 | Type-erased view. 78 | */ 79 | public func makeFillTrackErased() -> AnyView { 80 | return .init(self.makeFillTrack()) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Sources/STDiscreteSlider/View/STDiscreteSlider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MIT License 3 | // 4 | // Copyright (c) 2021 Tamerlan Satualdypov 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | import SwiftUI 25 | 26 | public struct STDiscreteSlider