UISlider clone with multiple thumbs and values, range highlight, optional snap intervals, optional value labels, either vertical or horizontal.

Overview

MultiSlider

UISlider clone with multiple thumbs and values, range highlight, optional snap intervals, optional value labels, either vertical or horizontal.

Swift Version Build Status License CocoaPods Compatible Platform PRs Welcome

Features

  • Multiple thumbs
  • Range slider (optional) - track color between thumbs different from track color outside thumbs
  • Vertical (optional)
  • Value labels (optional)
  • Snap interval (optional)
  • Haptic feedback
  • Configurable thumb image, minimum and maximum images.
  • Configurable track width, color, rounding.

Usage

let slider = MultiSlider()
slider.minimumValue = 1    // default is 0.0
slider.maximumValue = 5    // default is 1.0

slider.value = [1, 4.5, 5]

slider.addTarget(self, action: #selector(sliderChanged(_:)), for: .valueChanged) // continuous changes
slider.addTarget(self, action: #selector(sliderDragEnded(_:)), for: . touchUpInside) // sent when drag ends

SwiftUI

Use MultiValueSlider from the swiftui branch.

Getting multiple thumb values

Use value to get all thumbs values, and draggedThumbIndex to find which thumb was last moved.

func sliderChanged(slider: MultiSlider) {
    print("thumb \(slider.draggedThumbIndex) moved")
    print("now thumbs are at \(slider.value)") // e.g., [1.0, 4.5, 5.0]
}

Range slider

slider.outerTrackColor = .lightGray // outside of first and last thumbs

Vertical / horizontal orientation

slider.orientation = .horizontal // default is .vertical
slider.isVertical = false // same effect, but accessible from Interface Builder

Value labels

slider.valueLabelPosition = .left // .notAnAttribute = don't show labels
slider.isValueLabelRelative = true // show differences between thumbs instead of absolute values
slider.valueLabelFormatter.positiveSuffix = " 𝞵s"
slider.valueLabelColor = .green
slider.valueLabelFont = someFont

Snap interval

slider.snapStepSize = 0.5 // default is 0.0, i.e. don't snap
slider.isHapticSnap = false // default is true, i.e. generate haptic feedback when sliding over snap values

Changing Appearance

slider.tintColor = .cyan // color of track
slider.trackWidth = 32
slider.hasRoundTrackEnds = true
slider.showsThumbImageShadow = false // wide tracks look better without thumb shadow

Images

// add images at the ends of the slider:
slider.minimumImage = UIImage(named: "clown")
slider.maximumImage = UIImage(named: "cloud")

// change image for all thumbs:
slider.thumbImage = UIImage(named: "balloon")

// or let each thumb have a different image:
slider.thumbViews[0].image = UIImage(named: "ball")
slider.thumbViews[1].image = UIImage(named: "club")

Distance/Overlap Between Thumbs

// allow thumbs to overlap:
slider.keepsDistanceBetweenThumbs = false

// make thumbs keep a greater distance from each other (default = half the thumb size):
slider.distanceBetweenThumbs = 3.14

Disabling/freezing thumbs

slider.disabledThumbIndices = [1, 3]

Requirements

  • iOS 9.0+
  • Xcode 10

Installation

CocoaPods:

pod 'MultiSlider'

Legacy versions:

Swift version MultiSlider version
4.0 (Xcode 9.4) pod 'MiniLayout', '~> 1.2.1'
pod 'MultiSlider', '~> 1.6.0'
3 pod 'MiniLayout', '~> 1.1.0'
pod 'MultiSlider', '~> 1.1.2'
2.3 pod 'MiniLayout', '~> 1.0.1'
pod 'MultiSlider', '~> 1.0.1'

Swift Package Manager:

dependencies: [
    .package(url: "https://github.com/yonat/MultiSlider", from: "1.11.2")
]

Meta

@yonatsharon

https://github.com/yonat/MultiSlider

Comments
  • Build on xcode 9.4.1

    Build on xcode 9.4.1

    I'm trying to run the example source code in xocde version 9.4.1 but I get errors like this " 'Attribute' is not a member type of 'NSLayoutConstraint' , 'Relation' is not a member type of 'NSLayoutConstraint' " in it's miniLayout class.

    opened by niloufarMakhzani 15
  • Slider track gets aligned to top of UIView

    Slider track gets aligned to top of UIView

    I am facing an issue where the slider track gets aligned to the top of the UIView. Has anyone faced such issue? I am attaching the screenshots of the MultiSliders along with UIDebugger screenshot. TIA.

    The UIView is vertically centered to UIImageView with horizontal spacing.

    Screen Shot 2019-04-15 at 5 49 44 PM Screen Shot 2019-04-15 at 5 50 11 PM Screen Shot 2019-04-15 at 5 50 18 PM

    This is the screenshot of UIDebugger.

    Screen Shot 2019-04-15 at 5 53 17 PM

    opened by vaibhavarora03 11
  • Add .touchDown event

    Add .touchDown event

    I needed to specifically listen for the .touchDown event and when I added the below code it didn't work.

    lazy var slider: MultiSlider = {
        let s = MultiSlider()
        // ...
        s.addTarget(self, action: #selector(sliderBeganTracking(_:)), for: .touchDown)
        return s
    }()
    
    @objc func sliderBeganTracking(_ slider: MultiSlider) {
        print("Finger initial tap: \(slider.draggedThumbIndex)")
        // do something **only** on initial touch
    }
    

    To get it to work, I had to go into your MultiSlider+Drag file and add the sendActions(for: .touchDown) event to your .began gesture

    @objc open func didDrag(_ panGesture: UIPanGestureRecognizer) {
            switch panGesture.state {
            case .began:
                // ...
                sendActions(for: .touchDown)
    

    Can you please add the sendActions(for: .touchDown) event?

    enhancement 
    opened by lsamaria 7
  • Need to set distance between to sliders to a minimum of 4 but can't

    Need to set distance between to sliders to a minimum of 4 but can't

    ageSlider.distanceBetweenThumbs = 4 causes my app to crash every time. I do not understand why or what to do to get a minimum distance of 4 between my two sliders. Crash report says the following:

    2020-04-30 18:18:45.152808-0400 Revibe[14213:2645545] -[MultiSlider.MultiSlider setDistanceBetweenThumbs:]: unrecognized selector sent to instance 0x7fbedc95c820 2020-04-30 18:18:45.164995-0400 Revibe[14213:2645545] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MultiSlider.MultiSlider setDistanceBetweenThumbs:]: unrecognized selector sent to instance 0x7fbedc95c820'

    opened by michaeldebo 7
  • Layout of horizontal slider looks weird on iOS 12

    Layout of horizontal slider looks weird on iOS 12

    Xcode 10.0 beta 3 (10L201y)

    …moving the slider crashes the App: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Multiplier is not finite! That's illegal. multiplier:inf'

    simulator screen shot - iphone 8 - 2018-07-16 at 21 18 34

    opened by benjaminfischer 7
  • add value label text property

    add value label text property

    There is a demand to use custom text for valueLabel, such as below. slider-with-label-text

    This revision enables to set custom text by passing string array. multiSlider.valueLabelTexts = ["value1", "value2"]

    Below are the points that can be considered

    • In this implementation, when the size of valueLabelTexts differs from the size of value, original text (which is the value) is displayed.
    • It might be better to rename valueLabel to a name such as thumbLabel, since the label will not always be a value.
    opened by ryota765 6
  • How to get the 2nd/right side thumbnail to show?

    How to get the 2nd/right side thumbnail to show?

    Everything with your library seems to work fine except I can't get the right side thumbnail to show:

    var leftThumbValue: CGFloat = 0 // this always gets set as I slide the slider
    var rightThumbValue: CGFloat = 0 // this NEVER gets set as I slide the slider
    
    lazy var slider: MultiSlider = {
            let s = MultiSlider()
            s.translatesAutoresizingMaskIntoConstraints = false
    
            s.orientation = .horizontal
            s.minimumValue = 0
            
            s.keepsDistanceBetweenThumbs = false
            
            s.outerTrackColor = .white
            s.tintColor = .red
            s.thumbTintColor = .orange
            
            s.trackWidth = 10
            s.showsThumbImageShadow = false
            
            s.valueLabelTextForThumb = { [weak self](thumbIndex, thumbValue) in
                
                if thumbIndex == 0 {
                    self?.leftThumbValue = thumbValue
                }
                
                if thumbIndex == 1 {
                    self?.rightThumbValue = thumbValue
                }
                
                return ["Parasol", "Umbrella"][thumbIndex] + " \(thumbValue)"
            }
            
            s.addTarget(self, action: #selector(sliderBeganTracking(_:)), for: .touchDown) // I adde the .touchDown event to  MultiSlider+Drag
            s.addTarget(self, action: #selector(sliderValueChanged(_:)), for: .valueChanged)
            s.addTarget(self, action: #selector(sliderEndedTracking(_:)), for: [.touchUpInside, .touchUpOutside, .touchCancel])
            return s
    }()
    
    override func viewDidLoad() {
            super.viewDidLoad()
    
            // set anchors for slider 
            // set up AVPlayer with AVAsset
    
           let videoDurationTime: Float64 = CMTimeGetSeconds(asset.duration)
           slider.maximumValue = CGFloat(videoDurationTime)
    
           setTimeObserverToken()
    }
    
    func setTimeObserverToken() {
    
        timeObserverToken = player?.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using: {
                [weak self] (progressTime) in
    
                let seconds = CMTimeGetSeconds(progressTime)
    
                self?.trimSlider.value = [CGFloat(seconds)]
        }
    }
    
    

    What am I doing wrong?

    I also tried to add icons in the slider closure but not only is the right thumbnail not showing, the left thumbnail is just a circle, it doesn't take the form of the beeIcon. Both icons are in the Assets folder and spelled correctly

    lazy var slider: MultiSlider = {
        let s = MultiSlider()
        // ... all the other code from above
    
        s.minimumImage = UIImage(systemName: "beeIcon")
        s.maximumImage = UIImage(systemName: "antIcon")
    
        return s
    }()
    
    bug 
    opened by lsamaria 5
  • SwiftUI MultiSlider - Changing label font

    SwiftUI MultiSlider - Changing label font

    Description: Using your swiftui slider for my project and was wondering if you'd be able to add the ability to choose the font for the labels.

    Wondering if it would be possible to add the ability to change the size of the thumbs (the circles).

    Thank you!

    enhancement 
    opened by JKim0119 5
  • Thumb can go below minimum value

    Thumb can go below minimum value

    Description of the problem: With a 2 thumb slider, the 2nd thumb can go below the minimum value.

    Minimal project that reproduces the problem (so I'll be able to figure out how to fix it): slider.minimumValue = 18 slider.maximumValue = 100 slider.value = [18, 100] sliderOrientation = .horizontal slider.keepsDistanceBetweenThumbs = false slider.widthAnchor.constraint(equalToConstant: 200)

    // Drag the 2nd thumb all the way left... print("slider.value[1]") // prints 17.920077972709553

    bug 
    opened by JohnCarlyle 5
  • Gap at the end of sliders

    Gap at the end of sliders

    Description of the problem: [description]

    I have added a UIImage to each thumb in the MultiSlider but when I drag either the left thumb to the most minimum value or the right thumb to the most maximum value, it leaves a gap. So I thought if I increase the image size then I would solve that issue, what actually happened is the gap became bigger on both sides

    Minimal project that reproduces the problem (so I'll be able to figure out how to fix it): [github repo or a zipped project] Screen Shot 2020-05-14 at 11 30 56 AM Screen Shot 2020-05-14 at 11 32 54 AM

    bug 
    opened by mkifetew2 5
  • Send UIControlEvent when dragging ends

    Send UIControlEvent when dragging ends

    This helps reacting on the “final” value change rather than every value change while dragging the thumb.

    Example: track live changes to the slider in a UILabel via .valueChanged while waiting to apply the value until the user finished dragging via .touchDragExit.

    Additions cause SwiftLint to complain: Cyclomatic Complexity Violation: Function should have complexity 10 or less: currently complexity equals 12 (cyclomatic_complexity) …so, raise the limit? :)

    UPDATE: Now sending .touchUpInside

    opened by benjaminfischer 5
  • How to restrict dragging on condition

    How to restrict dragging on condition

    Hello, I've used Multi slider in my project. But now I what to restrict the dragging of sliders for a particular user.

    So what I want is, I want to check a condition before starting dragging.

    Is there any way to do such thing?

    Thanks in advance

    bug 
    opened by kishanbarmawala 5
  • Support for multiple snap step sizes

    Support for multiple snap step sizes

    Description:

    Support for multiple snap step sizes on one slider, e.g 2 and 4 The x value represents a size of 2. The y value represents a size of 4.

    image

    Here, snap step size should be 2. [x] - [x] - [x] - [x] - [ ] - [y] - [ ] - [y]

    Here, snap step size should be 4. Allowing the first thumb to move to the next y ignoring the blank node which would be a 2 step. [x] - [x] - [x] - [x] - [ ] - [y] - [ ] - [y]

    At the moment, there's only support for one step size and we were wondering if it would be possible to snap onto bigger gaps.

    Problems we encountered when trying to implement this myself:

    We've added an if statement to change the snap step size to 2 or 4 depending on where the second thumb is. This has caused the following problems.

    1. When we try to move the first thumb onto the next y node, it snaps in between because it's making a size 2 step. [x] - [x] - [x] - [x] - [ ] - [y] - [ ] - [y] [x] - [x] - [x] - [x] - [!] - [y] - [ ] - [y]

    2. When moving the last y node to the previous y, the x moves as well.

    [x] - [x] - [x] - [x] - [y] - [y] [x] - [x] - [x] - [x] - [y] - [y]

    We wanted to check if there is a more efficient way of doing this as we've spent lots of time trying to achieve the desired behaviour and creating a new Slider from UIControl proves to be somehow tricky for our team.

    Thank you, Christian

    enhancement 
    opened by kuriishu27 1
  • Carthage Support

    Carthage Support

    Description: You currently do not have support for Carthage.

    Problems I encountered when trying to implement this myself: I'm working in a project where we are trying to remove the cocoapods, and we've moved all our libs to Carthage.

    We would like to use your lib without the need to use cocoapods.

    enhancement 
    opened by reybriel 1
Owner
Yonat Sharon
Freelance iOS developer. Agile, TDD, and all that jazz. 🎸
Yonat Sharon
RangeSeedSlider provides a customizable range slider like a UISlider.

RangeSeekSlider Overview RangeSeekSlider provides a customizable range slider like a UISlider. This library is based on TomThorpe/TTRangeSlider (Objec

WorldDownTown 644 Dec 12, 2022
UISegmentedControl remake that supports selecting multiple segments, vertical stacking, combining text and images.

MultiSelectSegmentedControl UISegmentedControl remake that supports selecting multiple segments, vertical stacking, combining text and images. Feature

Yonat Sharon 286 Dec 15, 2022
Step-by-step progress view with labels and shapes. A good replacement for UIActivityIndicatorView and UIProgressView.

StepProgressView Step-by-step progress view with labels and shapes. A good replacement for UIActivityIndicatorView and UIProgressView. Usage let progr

Yonat Sharon 340 Dec 16, 2022
A horizontal scroll dial like Instagram.

HorizontalDial Preview Requirements iOS 8.0+ Swift 5 Storyboard support Installation CocoaPods use_frameworks! pod "HorizontalDial" Manually To instal

Lee Sun-Hyoup 210 Nov 22, 2022
🏞 A simple iOS photo and video browser with optional grid view, captions and selections written in Swift5.0

Introduction ?? MediaBrowser can display one or more images or videos by providing either UIImage objects, PHAsset objects, or URLs to library assets,

Kyle Yi 631 Dec 29, 2022
:octocat:💧 A slider widget with a popup bubble displaying the precise value selected. Swift UI library made by @Ramotion

FLUID SLIDER A slider widget with a popup bubble displaying the precise value selected written on Swift. We specialize in the designing and coding of

Ramotion 1.9k Dec 23, 2022
A swift PropertyWrapper to provide automatic NSView/UIView invalidation when the properties value changes.

A swift PropertyWrapper to provide automatic NSView/UIView invalidation when the properties value changes. It duplicates the @Invalidating propertyWrapper for build targets prior to macOS 12 and iOS 15.

Darren Ford 8 Oct 15, 2021
A SwiftUI Views for wrapping HStack elements into multiple lines

SwiftUI WrappingStack A SwiftUI Views for wrapping HStack elements into multiple lines. List of supported views WrappingHStack - provides HStack that

Denis 50 Jan 6, 2023
SheetPresentation for SwiftUI. Multiple devices support: iOS, watchOS, tvOS, macOS, macCatalyst.

SheetPresentation for SwiftUI. Multiple devices support: iOS, watchOS, tvOS, macOS, macCatalyst.

Aben 13 Nov 17, 2021
Pull up controller with multiple sticky points like in iOS Maps

PullUpController Create your own pull up controller with multiple sticky points like in iOS Maps Features Multiple sticky points Landscape support Scr

Mario Iannotta 1.2k Dec 22, 2022
A minimalistic looking banner library for iOS. It supports multiple customizable kinds of Banner types

A minimalistic looking banner library for iOS. It supports multiple customizable kinds of Banner types

Emre Armagan 12 Oct 10, 2022
Fetch the star wars api from all the planets and list and show details using Swift UI and Combine

Star Wars Planets Fetch the star wars planet data by using stat war api, list and show details using SwiftUI and Combine frameworks ?? Swift UI Framew

null 1 Aug 10, 2022
A custom stretchable header view for UIScrollView or any its subclasses with UIActivityIndicatorView and iPhone X safe area support for content reloading. Built for iOS 10 and later.

Arale A custom stretchable header view for UIScrollView or any its subclasses with UIActivityIndicatorView support for reloading your content. Built f

Putra Z. 43 Feb 4, 2022
MZFormSheetPresentationController provides an alternative to the native iOS UIModalPresentationFormSheet, adding support for iPhone and additional opportunities to setup UIPresentationController size and feel form sheet.

MZFormSheetPresentationController MZFormSheetPresentationController provides an alternative to the native iOS UIModalPresentationFormSheet, adding sup

Michał Zaborowski 979 Nov 17, 2022
High performance and lightweight UIView, UIImage, UIImageView, UIlabel, UIButton, Promise and more.

SwiftyUI High performance and lightweight UIView, UIImage, UIImageView, UIlabel, UIButton and more. Features SwiftyView GPU rendering Image and Color

Haoking 336 Nov 26, 2022
UIPheonix is a super easy, flexible, dynamic and highly scalable UI framework + concept for building reusable component/control-driven apps for macOS, iOS and tvOS

UIPheonix is a super easy, flexible, dynamic and highly scalable UI framework + concept for building reusable component/control-driven apps for macOS, iOS and tvOS

Mohsan Khan 29 Sep 9, 2022
BulletinBoard is an iOS library that generates and manages contextual cards displayed at the bottom of the screen

BulletinBoard is an iOS library that generates and manages contextual cards displayed at the bottom of the screen. It is especially well

Alexis (Aubry) Akers 5.3k Jan 2, 2023
Custom segue for OSX Storyboards with slide and cross fade effects (NSViewControllerTransitionOptions)

CustomSegue Custom segue for OSX Storyboards. Slide and cross fade effects, new customized window. class MyViewController: NSViewController { overr

Eric Marchand 123 May 21, 2022
Fashion is your helper to share and reuse UI styles in a Swifty way.

Fashion is your helper to share and reuse UI styles in a Swifty way. The main goal is not to style your native apps in CSS, but use a set

Vadym Markov 124 Nov 20, 2022