How to make UISlider default thumb to be smaller like the ones in the iOS control center

i0S Swift Issue

Question or problem in the Swift programming language:

I’m working on an app and I have a custom UISlider.
However, I’m having some issues on how to make the default thumb to appear smaller like the ones in the iOS control center.
Note that I want the same iOS thumb, not a custom thumb image. So far, I’ve tried thumbRect(forBounds…) but no luck.
Any suggestions?

How to solve the problem:

Solution 1:

You can’t change the size of the default thumb image, but UISlider has a method setThumbImage(_:for:) that will allow you to pass a similar, smaller image.

enter image description here

In your view controller viewDidLoad :

let image:UIImage? = // ...
yourSlider.setThumbImage(image, for: .normal)
yourSlider.setThumbImage(image, for: .highlighted) // Also change the image when dragging the slider

See Customizing the Slider’s Appearance of the API Reference.


On iOS10, the default thumb image appear to be no more than a bordered white circle with a thin shadow dropped under (if you don’t set the thumbTintColor).

I use this snippet to generate a similar image that can be scaled down 😉

Solution 2:

I created a UISlider subclass that allows to change the thumb size as well as track size, all without using images.

import UIKit

class CustomSlider: UISlider {

    @IBInspectable var trackHeight: CGFloat = 3

    @IBInspectable var thumbRadius: CGFloat = 20

    // Custom thumb view which will be converted to UIImage
    // and set as thumb. You can customize it's colors, border, etc.
    private lazy var thumbView: UIView = {
        let thumb = UIView()
        thumb.backgroundColor = .yellow//thumbTintColor
        thumb.layer.borderWidth = 0.4
        thumb.layer.borderColor = UIColor.darkGray.cgColor
        return thumb
    }()

    override func awakeFromNib() {
        super.awakeFromNib()
        let thumb = thumbImage(radius: thumbRadius)
        setThumbImage(thumb, for: .normal)
    }

    private func thumbImage(radius: CGFloat) -> UIImage {
        // Set proper frame
        // y: radius / 2 will correctly offset the thumb

        thumbView.frame = CGRect(x: 0, y: radius / 2, width: radius, height: radius)
        thumbView.layer.cornerRadius = radius / 2

        // Convert thumbView to UIImage
        // See this: https://stackoverflow.com/a/41288197/7235585

        let renderer = UIGraphicsImageRenderer(bounds: thumbView.bounds)
        return renderer.image { rendererContext in
            thumbView.layer.render(in: rendererContext.cgContext)
        }
    }

    override func trackRect(forBounds bounds: CGRect) -> CGRect {
        // Set custom track height
        // As seen here: https://stackoverflow.com/a/49428606/7235585
        var newRect = super.trackRect(forBounds: bounds)
        newRect.size.height = trackHeight
        return newRect
    }

}

Result:

enter image description here

Solution 3:

If you want to change Thumb Image as well as Tint Color then both can’t be possible; There is one workaround of this issue. Create circular image programmatically and change the color of the image and assign that image to slider thumb; In this way, you can also resize the image as well as color.

Here is the fully working sample code:

fileprivate func makeCircleWith(size: CGSize, backgroundColor: UIColor) -> UIImage? {
    UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
    let context = UIGraphicsGetCurrentContext()
    context?.setFillColor(backgroundColor.cgColor)
    context?.setStrokeColor(UIColor.clear.cgColor)
    let bounds = CGRect(origin: .zero, size: size)
    context?.addEllipse(in: bounds)
    context?.drawPath(using: .fill)
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
}

You can call this function like this:

    func setSliderThumbTintColor(_ color: UIColor) {
    let circleImage = makeCircleWith(size: CGSize(width: 20, height: 20),
                   backgroundColor: color)
    slider.setThumbImage(circleImage, for: .normal)
    slider.setThumbImage(circleImage, for: .highlighted)
}

This method setSliderThumbTintColor will be called on valueChanged event of UISlider.

Solution 4:

Here’s an option for you, use a CGAffineTransform.

Swift 4

mySlider.transform = CGAffineTransform(scaleX: 0.85, y: 0.85)

This will change the width and height of the slider, so you may need to realign it with your interface.

Solution 5:

  1. Download an image similar to the one you have in the iOS control centre.

  2. Scale it to the size you want (20×20 or even smaller) and save it in your assets.

  3. Paste the following code in viewDidLoad:

    self.yourSlider.setThumbImage(UIImage(named: "SliderName")!, for: .normal)
    

Hope this helps!