{"id":21187029,"url":"https://github.com/thunderstruct/mscircularslider","last_synced_at":"2026-04-01T21:50:51.105Z","repository":{"id":49171863,"uuid":"105839664","full_name":"ThunderStruct/MSCircularSlider","owner":"ThunderStruct","description":"A fully-featured, powerful circular slider for iOS applications","archived":false,"fork":false,"pushed_at":"2023-05-23T22:40:34.000Z","size":624,"stargazers_count":119,"open_issues_count":16,"forks_count":31,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-07-19T14:32:40.620Z","etag":null,"topics":["circular","cocoapods","ibdesignable","ibinspectable","ios","ios-swift","library","slider","swift","xcode"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ThunderStruct.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-10-05T02:02:40.000Z","updated_at":"2025-01-16T03:33:14.000Z","dependencies_parsed_at":"2022-07-30T22:08:02.311Z","dependency_job_id":"28ed39b6-ab98-4377-b349-0042517c61a5","html_url":"https://github.com/ThunderStruct/MSCircularSlider","commit_stats":{"total_commits":47,"total_committers":4,"mean_commits":11.75,"dds":"0.21276595744680848","last_synced_commit":"c9a96a42d0088841713152bd72580fa8792dc017"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/ThunderStruct/MSCircularSlider","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThunderStruct%2FMSCircularSlider","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThunderStruct%2FMSCircularSlider/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThunderStruct%2FMSCircularSlider/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThunderStruct%2FMSCircularSlider/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ThunderStruct","download_url":"https://codeload.github.com/ThunderStruct/MSCircularSlider/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThunderStruct%2FMSCircularSlider/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267780054,"owners_count":24143201,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-29T02:00:12.549Z","response_time":2574,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["circular","cocoapods","ibdesignable","ibinspectable","ios","ios-swift","library","slider","swift","xcode"],"created_at":"2024-11-20T18:27:57.058Z","updated_at":"2026-03-27T07:21:17.980Z","avatar_url":"https://github.com/ThunderStruct.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MSCircularSlider\n[![Build Status](https://travis-ci.org/ThunderStruct/MSCircularSlider.svg?branch=master)](https://travis-ci.org/ThunderStruct/MSCircularSlider) [![Platform](https://img.shields.io/badge/platform-iOS-lightgrey.svg)](https://github.com/ThunderStruct/MSCircularSlider) [![CocoaPods](https://img.shields.io/badge/pod-1.3.2-blue.svg)](https://cocoapods.org/pods/MSCircularSlider) [![License](https://img.shields.io/cocoapods/l/AFNetworking.svg)](https://github.com/ThunderStruct/MSCircularSlider/blob/master/LICENSE)\n\nA fully `IBDesignable` and `IBInspectable` circular slider for iOS applications\n\n------------------------\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://i.imgur.com/KOy1UHn.gif\"\u003e\n\u003c/p\u003e\n\n## Getting Started\nMSCircularSlider provides a fluid and straightforward interface to a multipurpose slider UIControl. The entire library is written in Swift 5 along with the accompanying example project\n\n### Installation\n#### CocoaPods (recommended)\nFor the latest [CocoaPods](https://cocoapods.org/) release\n```ruby\npod 'MSCircularSlider'\n```\n#### Manual Installation\nSimply clone the entire repo and extract the files in the `MSCircularSlider` folder, then import them into your XCode project.\n\nOr use one of the shorthand methods below\n##### GIT\n  - `cd` into your project directory\n  - Use `sparse-checkout` to pull the library files only into your project directory\n    ```sh\n    git init MSCircularSlider\n    cd MSCircularSlider\n    git remote add -f origin https://github.com/ThunderStruct/MSCircularSlider.git\n    git config core.sparseCheckout true\n    echo \"MSCircularSlider/*\" \u003e\u003e .git/info/sparse-checkout\n    git pull --depth=1 origin master\n    ```\n   - Import the newly pulled files into your XCode project\n##### SVN\n  - `cd` into your project directory\n  - `checkout` the library files\n    ```sh\n    svn checkout https://github.com/ThunderStruct/MSCircularSlider/trunk/MSCircularSlider\n    ```\n  - Import the newly checked out files into your XCode project\n  \n\n### Usage\n#### Initialization\nMost members are `IBInspectable`, providing multiple ways of complete initialization; through the `Interface Builder` or programmatically\n##### Interface Builder Initialization\n\n\u003cp\u003e\n  \u003cimg src=\"https://i.imgur.com/iLp7ifC.png\"\u003e\n\u003c/p\u003e\n\n##### Programmatic Initialization\nThe following code instantiates and initializes the slider to make it identical to the one in the IB sample above\n```swift\nlet frame = CGRect(x: view.center.x - 200, y: view.center.y - 200, width: 400, height 400)     // center in superview\nlet slider = MSCircularSlider(frame: frame)\nslider.currentValue = 60.0\nslider.maximumAngle = 300.0\nslider.filledColor = UIColor(red: 127 / 255.0, green: 168 / 255.0, blue: 198 / 255.0, alpha: 1.0)\nslider.unfilledColor = UIColor(red: 80 / 255.0, green: 148 / 255.0, blue: 95 / 255.0, alpha: 1.0)\nslider.handleType = .doubleCircle\nslider.handleColor = UIColor(red: 35 / 255.0, green: 69 / 255.0, blue: 96 / 255.0, alpha: 1.0)\nslider.handleEnlargementPoints = 12\nslider.labels = [\"1\", \"2\", \"3\", \"4\", \"5\"]\nview.addSubview(slider!)\n```\n\n### Members and Methods\n#### MSCircularSlider\n  - `delegate`: takes a class conforming to MSCircularSliderDelegate and handles delegation - default nil\n    - note: please check the _Protocols_ segment below for more info about the abstract delegation model used\n  - `minimumValue`: the value the slider takes at angle 0° - default 0.0\n  - `maximumValue`: the value the slider takes at maximumAngle - default 100.0\n  - `currentValue`: the value the slider has at the current angle - default 0.0\n  - `maximumAngle`: the arc's maximum angle (360° = full circle) - default 360.0\n  - `sliderPadding`: the padding between the frame and the drawn slider (can be used to prevent labels' clipping by enlarging the frame and increasing the padding) - default 0.0\n  - `lineWidth`: the arc's line width - default 5\n  - `filledColor`: the color shown for the part \"filled\" by the handle - default .darkGrey\n  - `unfilledColor`: the color shown for the \"unfilled\" part of the circle - default .lightGrey\n  - `rotationAngle`: the rotation transformation angle of the entire slider view - default calculated so that the _gap_ is facing downwards\n    - note: the slider adds an inverted rotational transformation to all of its subviews to cancel any applied rotation\n  - `handleType`: indicates the type of the handle - default .largeCircle\n  - `handleColor`: the handle's color - default .darkGrey\n  - `hanldeImage`: the handle's image - default nil\n  - `handleEnlargementPoints`: the number of points the handle is larger than lineWidth - default 10\n    - note: this property only applies to handles of types .largeCircle or .doubleCircle\n  - `handleHighlightable`: indicates whether the handle should _highlight_ (becomes semitransparent) while being pressed - default true\n  - `handleRotatable`: specifies whether or not the handle should rotate to always point outwards - default false\n  - `labels`: the string array that contains all labels to be displayed in an evenly-distributed manner - default [ ]\n    - note: all changes to this array will not be applied instantly unless they go through the assignment operator (=). To perform changes, use the provided methods below\n  - `labelColor`: the color applied to the displayed labels - default .black\n  - `snapToLabels`: indicates whether the handle should _snap_ to the nearest label upon handle-release - default false\n  - `labelFont`: the font applied to the displayed labels - default .systemFont(ofSize: 12)\n  - `labelOffset`: the number of point labels are pushed off away from the slider's center - default 0.0\n    - note: a negative number can be used to draw the labels inwards towards the center\n  - `markerCount`: indicates the number of markers to be displayed in an evenly-distributed manner - default 0\n  - `markerColor`: the color applied to the displayed markers - default .darkGrey\n  - `markerPath`: an optional UIBezierPath to draw custom-shaped markers instead of the standard ellipse markers - default nil\n  - `markerImage`: an optional UIImage to be drawn instead of the standard ellipse markers - default nil\n    - note: markerPath takes precedence over markerImage, so if both members are set, the images will not be drawn\n  - `snapToMarkers`: indicates whether the handle should _snap_ to the nearest marker upon handle-release - default false\n    - ~note: if both snapToMarkers and snapToLabels are true, the handle will be snapped to the nearest marker~ _removed mutual-exclusion in 1.1.0_\n  - `slidingDirection`: indicates the current handle sliding direction - default .none\n  - `revolutionsCount`: indicates the number of times the handle has revolved (requires `maximumAngle` = 360) - default 0\n  - `maximumRevolutions`: specifies the maximum number of revolutions before the slider is bounded at 100% (`angle` = 360.0) - default -1\n    - note: this property is valid only when `maximumAngle = 360.0`, it also prevents -ve revolutions by bounding the counter-clockwise sliding at 0% (`angle` = 0.0) and `revolutionsCount` = 0. Setting this property to any -ve value will allow the slider to revolve endlessly\n  - `addLabel(_ string: String)`: adds a string to the labels array and triggers required drawing methods\n  - `changeLabel(at index: Int, string: String)`: replaces the label's string at the given index with the provided string\n  - `removeLabel(at index: Int)`: removes the string from the labels array at the given index\n\n#### MSDoubleHandleCircularSlider\nInherits from MSCircularSlider with the following differences\n\n  - `delegate`: takes a class conforming to MSDoubleHandleCircularSliderDelegate and handles delegation - default nil\n    - note: please check the _Protocols_ segment below for more info about the abstract delegation model used\n  - `minimumHandlesDistance`: indicates the minimum arc length between the two handles - default 10.0\n  - `secondCurrentValue`: the current value of the second handle - default calculated from 60° angle\n  - `secondHandleType`: indicates the type of the second handle - default .largeCircle\n  - `secondHandleColor`: the second handle's color - default .darkGrey\n  - `secondHandleImage`: the second handle's image - default nil\n  - `secondHandleEnlargementPoints`: the number of points the second handle is larger than lineWidth - default 10\n    - note: this property only applies to handles of types .largeCircle or .doubleCircle\n  - `secondHandleHighlightable`: indicates whether the second handle should _highlight_ (becomes semitransparent) while being pressed - default true\n  - `secondHandleRotatable`: specifies whether or not the second handle should rotate to always point outwards - default false\n  - `snapToLabels`: indicates whether both handles should _snap_ to the nearest marker upon handle-release - default false - ~overridden and made unavailable~ _available in 1.3.0_\n  - `snapToMarkers`: findicates whether both handles should _snap_ to the nearest label upon handle-release - default false - ~overriden and made unavailable~ _available in 1.3.0_\n\n#### MSGradientCircularSlider\nInherits from MSCircularSlider with the following differences\n\n  - `gradientColors`: the colors array upon which the gradient is calculated (as ordered in the array) - default [.lightGray, .blue, .darkGray]\n    - note: all changes to this array will not be applied instantly unless they go through the assignment operator (=). To perform changes, use the provided methods below\n  - `addColor(_ color: UIColor)`: adds a color to the gradientColors array and triggers required drawing methods\n  - `changeColor(at index: Int, newColor: UIColor)`: replaces the color at the given index with the provided newColor\n  - `removeColor(at index: Int)`: removes the color from the gradientColors array at the given index\n\n### Protocols  and Enums\nThere are three protocols used in the MSCircularSlider library\n\n#### MSCircularSliderProtocol\nAn internal protocol that acts only as an abstract super class with no defined methods. The main and only `delegate` member exposed in all classes is of type MSCircularSliderProtocol and gets cast to one of the other two protocols appropriately\n\n#### MSCircularSliderDelegate\nInherits from MSCircularSliderProtocol and contains all methods (documented below) used by MSCircularSlider and MSGradientCircularSlider\n\n  - `circularSlider(_ slider: MSCircularSlider, valueChangedTo value: Double, fromUser: Bool)`: called upon currentValue change and provides a _fromUser_ Bool that indicates whether the value was changed by the user (by scrolling the handle) or through other means (programmatically or so - `currentValue = 20`)\n  \n  - `circularSlider(_ slider: MSCircularSlider, startedTrackingWith value: Double)`: indicates that the handle started scrolling\n  \n  - `circularSlider(_ slider: MSCircularSlider, endedTrackingWith value: Double)`: indicates that the slider's handle was released\n  - `circularSlider(_ slider: MSCircularSlider, directionChangedTo value: MSCircularSliderDirection)`: indicates which direction the user is currently sliding\n  - `circularSlider(_ slider: MSCircularSlider, revolutionsChangedTo value: Int)`: indicates how many times the handle has revolved around the entire slider (only valid for `maximumAngle` = 360.0 / full circle)\n\n#### MSDoubleHandleCircularSliderDelegate\nInherits from MSCircularSliderProtocol and is used only by MSDoubleHandleCircularSlider\n\n  - `circularSlider(_ slider: MSCircularSlider, valueChangedTo firstValue: Double, secondValue: Double, isFirstHandle: Bool?, fromUser: Bool) `: called upon any of the two current values changes and provides an isFirstHandle Bool indicating whether the change came from the first or second handle\n  \n  - `circularSlider(_ slider: MSCircularSlider, startedTrackingWith firstValue: Double, secondValue: Double, isFirstHandle: Bool)`: indicates that the handle started scrolling\n  \n  - `circularSlider(_ slider: MSCircularSlider, endedTrackingWith firstValue: Double, secondValue: Double, isFirstHandle: Bool)`: indicates that the active slider's handle was released\n\n#### MSCircularSliderDirection\nUsed to indicate which direction the user is currently sliding\n\n  - `.none`\n  - `.clockwise`\n  - `.counterclockwise`\n\n## Todos\n\n - [x] Eliminate mutual-exlusion between `snapToLabels` and `snapToMarkers`\n - [x] Add snapping feature for `MSDoubleHandleCircularSlider`\n - [x] Add independent members for the second handle in `MSDoubleHandleCircularSlider` to customize each handle individually\n - [ ] Add `MSCircularSliderMaterial` enum that specifies different _finishes_ for the slider, including\n   - Glossy\n   - Matte\n   - Pearlescent\n- [ ] Add a `setValue` method with an optional animation parameter\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](https://github.com/ThunderStruct/MSCircularSlider/blob/master/LICENSE) file for details\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthunderstruct%2Fmscircularslider","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthunderstruct%2Fmscircularslider","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthunderstruct%2Fmscircularslider/lists"}