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 t
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:
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.
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 ;)
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var data = " \
<svg xmlns='http://www.w3.org/2000/svg' width='86' height='86'> \
<foreignObject width='100%' height='100%'> \
<div xmlns='http://www.w3.org/1999/xhtml'> \
<style> \
#ios-uislider-thumb { \
-webkit-box-sizing: content-box; \
-moz-box-sizing: content-box; \
box-sizing: content-box; \
width: 66px; \
height: 66px; \
overflow: hidden; \
border: 1px solid #CCC; \
-webkit-border-radius: 33px; \
border-radius: 33px; \
background: #FFFFFF; \
-webkit-box-shadow: 0 6px 6px 0 rgba(0,0,0,0.2); \
box-shadow: 0 6px 6px 0 rgba(0,0,0,0.2); \
margin : 5px 10px 15px 10px; \
} \
</style> \
<div id='ios-uislider-thumb'></div> \
</div> \
</foreignObject> \
</svg> \
";
var DOMURL = self.URL || self.webkitURL || self;
var img = new Image();
var svg = new Blob([data], {
type: "image/svg+xml;charset=utf-8"
});
var url = DOMURL.createObjectURL(svg);
img.onload = function() {
ctx.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);
};
img.src = url;
<canvas id="canvas" style="border:2px dotted black;" width="86" height="86"></canvas>
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.
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.
Download an image similar to the one you have in the iOS control centre.
Scale it to the size you want (20x20 or even smaller) and save it in your assets.
Paste the following code in viewDidLoad:
self.yourSlider.setThumbImage(UIImage(named: "SliderName")!, for: .normal)