Reputation: 3978
I'm working on a design application that has a section for selecting colors by three sliders for RGB. As we can see in xcode, where we want to select a color by RGB values, the slider tint color is a gradient color that changes when we change the sliders. I want to use this in my application. but I have no idea about how to do this?
I've found this code in a blog. but didn't work for me.
- (void)setGradientToSlider:(UISlider *)Slider WithColors:(NSArray *)Colors{
UIView * view = (UIView *)[[Slider subviews]objectAtIndex:0];
UIImageView * maxTrackImageView = (UIImageView *)[[view subviews]objectAtIndex:0];
CAGradientLayer * maxTrackGradient = [CAGradientLayer layer];
CGRect rect = maxTrackImageView.frame;
rect.origin.x = view.frame.origin.x;
maxTrackGradient.frame = rect;
maxTrackGradient.colors = Colors;
[maxTrackGradient setStartPoint:CGPointMake(0.0, 0.5)];
[maxTrackGradient setEndPoint:CGPointMake(1.0, 0.5)];
[[maxTrackImageView layer] insertSublayer:maxTrackGradient atIndex:0];
/////////////////////////////////////////////////////
UIImageView * minTrackImageView = (UIImageView *)[[view subviews]objectAtIndex:1];
CAGradientLayer * minTrackGradient = [CAGradientLayer layer];
rect = minTrackImageView.frame;
rect.size.width = maxTrackImageView.frame.size.width;
rect.origin.x = 0;
rect.origin.y = 0;
minTrackGradient.frame = rect;
minTrackGradient.colors = Colors;
[minTrackGradient setStartPoint:CGPointMake(0.0, 0.5)];
[minTrackGradient setEndPoint:CGPointMake(1.0, 0.5)];
[minTrackImageView.layer insertSublayer:minTrackGradient atIndex:0];
}
I would appreciate any helps. Thanks.
Upvotes: 8
Views: 9082
Reputation: 19946
While it didnt give me the desired results here is a down and dirty Swift version of the answer above for those that want to try it.
func setSlider(slider:UISlider) {
let tgl = CAGradientLayer()
let frame = CGRectMake(0, 0, slider.frame.size.width, 5)
tgl.frame = frame
tgl.colors = [UIColor.blueColor().CGColor, UIColor.greenColor().CGColor, UIColor.yellowColor().CGColor, UIColor.orangeColor().CGColor, UIColor.redColor().CGColor]
tgl.startPoint = CGPointMake(0.0, 0.5)
tgl.endPoint = CGPointMake(1.0, 0.5)
UIGraphicsBeginImageContextWithOptions(tgl.frame.size, tgl.opaque, 0.0);
tgl.renderInContext(UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
image.resizableImageWithCapInsets(UIEdgeInsetsZero)
slider.setMinimumTrackImage(image, forState: .Normal)
//slider.setMaximumTrackImage(image, forState: .Normal)
}
UPDATE for Swift 4.0
func setSlider(slider:UISlider) {
let tgl = CAGradientLayer()
let frame = CGRect.init(x:0, y:0, width:slider.frame.size.width, height:5)
tgl.frame = frame
tgl.colors = [UIColor.blue.cgColor, UIColor.green.cgColor, UIColor.yellow.cgColor, UIColor.orange.cgColor, UIColor.red.cgColor]
tgl.startPoint = CGPoint.init(x:0.0, y:0.5)
tgl.endPoint = CGPoint.init(x:1.0, y:0.5)
UIGraphicsBeginImageContextWithOptions(tgl.frame.size, tgl.isOpaque, 0.0);
tgl.render(in: UIGraphicsGetCurrentContext()!)
if let image = UIGraphicsGetImageFromCurrentImageContext() {
UIGraphicsEndImageContext()
image.resizableImage(withCapInsets: UIEdgeInsets.zero)
slider.setMinimumTrackImage(image, for: .normal)
}
}
Upvotes: 13
Reputation: 111
For Swift 3 and to prevent the slider from scaling the Min image, apply this when setting the its image. Recalculating the slider's left side is not necessary. Only recalc if you can changing the color of the gradient. The Max image does not seem to scale, but you should probably apply the same setting for consistency. There is a slight difference on the Max image when not applying its insets.
slider.setMinimumTrackImage(image?.resizableImage(withCapInsets:.zero), for: .normal)
For some reason it only works properly when resizableImage(withCapInsets:.zero) is all done at the same time. Running that part separate does not allow the image to work and gets scaled.
Here is the entire routine in Swift 3:
func setSlider(slider:UISlider) {
let tgl = CAGradientLayer()
let frame = CGRect(x: 0.0, y: 0.0, width: slider.bounds.width, height: 5.0 )
tgl.frame = frame
tgl.colors = [ UIColor.yellow.cgColor,UIColor.black.cgColor]
tgl.endPoint = CGPoint(x: 1.0, y: 1.0)
tgl.startPoint = CGPoint(x: 0.0, y: 1.0)
UIGraphicsBeginImageContextWithOptions(tgl.frame.size, false, 0.0)
tgl.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
slider.setMaximumTrackImage(image?.resizableImage(withCapInsets:.zero), for: .normal)
slider.setMinimumTrackImage(image?.resizableImage(withCapInsets:.zero), for: .normal)
}
Upvotes: 3
Reputation: 3978
This is a really effective approach that I've found after a lot of web search. So it's better to share it here as a complete answer. The following code is a Swift Class
That you can use to create and use gradients as UIView
or UIImage
.
import Foundation
import UIKit
class Gradient: UIView{
// Gradient Color Array
private var Colors: [UIColor] = []
// Start And End Points Of Linear Gradient
private var SP: CGPoint = CGPoint.zeroPoint
private var EP: CGPoint = CGPoint.zeroPoint
// Start And End Center Of Radial Gradient
private var SC: CGPoint = CGPoint.zeroPoint
private var EC: CGPoint = CGPoint.zeroPoint
// Start And End Radius Of Radial Gradient
private var SR: CGFloat = 0.0
private var ER: CGFloat = 0.0
// Flag To Specify If The Gradient Is Radial Or Linear
private var flag: Bool = false
// Some Overrided Init Methods
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
// Draw Rect Method To Draw The Graphics On The Context
override func drawRect(rect: CGRect) {
// Get Context
let context = UIGraphicsGetCurrentContext()
// Get Color Space
let colorSpace = CGColorSpaceCreateDeviceRGB()
// Create Arrays To Convert The UIColor to CG Color
var colorComponent: [CGColor] = []
var colorLocations: [CGFloat] = []
var i: CGFloat = 0.0
// Add Colors Into The Color Components And Use An Index Variable For Their Location In The Array [The Location Is From 0.0 To 1.0]
for color in Colors {
colorComponent.append(color.CGColor)
colorLocations.append(i)
i += CGFloat(1.0) / CGFloat(self.Colors.count - 1)
}
// Create The Gradient With The Colors And Locations
let gradient: CGGradientRef = CGGradientCreateWithColors(colorSpace, colorComponent, colorLocations)
// Create The Suitable Gradient Based On Desired Type
if flag {
CGContextDrawRadialGradient(context, gradient, SC, SR, EC, ER, 0)
} else {
CGContextDrawLinearGradient(context, gradient, SP, EP, 0)
}
}
// Get The Input Data For Linear Gradient
func CreateLinearGradient(startPoint: CGPoint, endPoint: CGPoint, colors: UIColor...) {
self.Colors = colors
self.SP = startPoint
self.EP = endPoint
self.flag = false
}
// Get The Input Data For Radial Gradient
func CreateRadialGradient(startCenter: CGPoint, startRadius: CGFloat, endCenter: CGPoint, endRadius: CGFloat, colors: UIColor...) {
self.Colors = colors
self.SC = startCenter
self.EC = endCenter
self.SR = startRadius
self.ER = endRadius
self.flag = true
}
// Function To Convert Gradient To UIImage And Return It
func getImage() -> UIImage {
// Begin Image Context
UIGraphicsBeginImageContext(self.bounds.size)
// Draw The Gradient
self.drawRect(self.frame)
// Get Image From The Current Context
let image = UIGraphicsGetImageFromCurrentImageContext()
// End Image Context
UIGraphicsEndImageContext()
// Return The Result Gradient As UIImage
return image
}
}
Upvotes: 2
Reputation: 680
Here is possible solution:
Usage:
//array of CGColor objects, color1 and color2 are UIColor objects
NSArray *colors = [NSArray arrayWithObjects:(id)color1.CGColor, (id)color2.CGColor, nil];
//your UISlider
[slider setGradientBackgroundWithColors:colors];
Implementation:
Create category on UISlider
:
- (void)setGradientBackgroundWithColors:(NSArray *)colors
{
CAGradientLayer *trackGradientLayer = [CAGradientLayer layer];
CGRect frame = self.frame;
frame.size.height = 5.0; //set the height of slider
trackGradientLayer.frame = frame;
trackGradientLayer.colors = colors;
//setting gradient as horizontal
trackGradientLayer.startPoint = CGPointMake(0.0, 0.5);
trackGradientLayer.endPoint = CGPointMake(1.0, 0.5);
UIImage *trackImage = [[UIImage imageFromLayer:trackGradientLayer] resizableImageWithCapInsets:UIEdgeInsetsZero];
[self setMinimumTrackImage:trackImage forState:UIControlStateNormal];
[self setMaximumTrackImage:trackImage forState:UIControlStateNormal];
}
Where colors
is array of CGColor.
I have also created a category on UIImage
which creates image from layer as you need an UIImage
for setting gradient on slider.
+ (UIImage *)imageFromLayer:(CALayer *)layer
{
UIGraphicsBeginImageContextWithOptions(layer.frame.size, layer.opaque, 0.0);
[layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return outputImage;
}
Upvotes: 6