Как добавить цвет градиентного оттенка к UISlider в XCode 6?

Я работаю над дизайнерским приложением, в котором есть раздел для выбора цветов тремя ползунками для RGB. Как мы видим в xcode, где мы хотим выбрать цвет по значениям RGB, цвет оттенка ползунка - это цвет градиента, который изменяется, когда мы меняем ползунки. Я хочу использовать это в своем приложении. но я понятия не имею, как это сделать?

Я нашел этот код в блоге. но у меня не сработало.

- (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];

}

Буду признателен за любую помощь. Спасибо.


person hmak.me    schedule 15.01.2015    source источник


Ответы (4)


Хотя это не дало мне желаемых результатов, вот грязная версия Swift ответа выше для тех, кто хочет попробовать.

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)

}

ОБНОВЛЕНИЕ для 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)
    }
}
person DogCoffee    schedule 27.03.2016
comment
Но у меня есть быстрая версия, которая дает желаемые результаты. Если вы захотите его использовать, я поделюсь им здесь - person hmak.me; 27.03.2016
comment
@HosseinMaktoobian, это работает ... только не так, как я хотел. Изображения масштабируются при скольжении, поэтому, например, если бы у меня были только красный и синий, я бы хотел, чтобы красный отображал до 50% слайда, а остальные 50% отображали синий. Но это был красный и синий, которые всегда были видны, только в уменьшенном масштабе, чтобы соответствовать размеру контента. - person DogCoffee; 27.03.2016
comment
Взгляните на мой ответ. Вы должны манипулировать локациями для решения вашей проблемы. И вам нужно обновлять градиент всякий раз, когда вид меняется - person hmak.me; 27.03.2016
comment
это должно быть приемлемым решением! спасибо @DogCoffee - person AouledIssa; 17.06.2018
comment
градиент добавляется, но управление становится неработоспособным - нет границ линий, смещения по оси y и т. д. - person Vyachaslav Gerchicov; 18.04.2019
comment
Это так близко, за исключением того, что image.resizableImage(withCapInsets: UIEdgeInsets.zero) возвращает UIImage, но он не присваивается переменной. если вы присваиваете результат этого вызова переменной, а затем передаете его в setMinTrackImage, он отлично работает - person user1366911; 13.08.2019

Вот возможное решение:

Использование:

//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];

Реализация:

Создать категорию на 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];
}

Где colors - это массив CGColor.

Я также создал категорию на UIImage, которая создает изображение из слоя, поскольку вам нужен UIImage для настройки градиента на слайдере.

+ (UIImage *)imageFromLayer:(CALayer *)layer
{
    UIGraphicsBeginImageContextWithOptions(layer.frame.size, layer.opaque, 0.0);

    [layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return outputImage;
}
person Palli    schedule 13.04.2015
comment
отлично! спасибо, хотя для 100% правильности я бы использовал frame = [self trackRectForBounds: self.bounds]; так что он будет работать нормально даже с максимальным и минимальным изображениями - person PakitoV; 11.04.2019

Для Swift 3 и чтобы слайдер не масштабировал минимальное изображение, примените это при установке его изображения. Пересчет левой части ползунка не требуется. Выполняйте пересчет только в том случае, если вы можете изменить цвет градиента. Изображение Max не масштабируется, но вам, вероятно, следует применить те же настройки для единообразия. На изображении Max есть небольшая разница, если не применять его вставки.

slider.setMinimumTrackImage(image?.resizableImage(withCapInsets:.zero), for: .normal)

По какой-то причине он работает правильно только тогда, когда resizableImage (withCapInsets: .zero) выполняется одновременно. Выполнение этой части отдельно не позволяет изображению работать и масштабируется.

Вот вся процедура в 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)
}
person Goodtime    schedule 18.11.2016

Это действительно эффективный подход, который я нашел после долгого поиска в Интернете. Так что лучше поделиться им здесь как полный ответ. Следующий код - это Swift Class, который вы можете использовать для создания и использования градиентов как UIView или 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
    }
}
person hmak.me    schedule 27.03.2016
comment
Не могли бы вы объяснить использование этого кода? - person Mykyta Savchuk; 12.12.2017