2015-04-20 3 views
2

Я использую PaintCode StyleKit для генерации кучи градиентов, но PaintCode экспортирует их как CGGradient. Я хотел добавить эти градиенты layer. Можно ли преобразовать CGGradient в CAGradientLayer?Преобразование CGGradient в CAGradientLayer

+0

ли вы * необходимости *, чтобы преобразовать его в какой-то конкретной причине? Вы можете нарисовать CGGradient в UIView. – EmilioPelaez

+0

Исправление: PaintCode генерирует класс 'PCGradient', который обертывает' CGGradientRef'. – Tricertops

ответ

3

№ Пункт CAGradientLayer заключается в том, что вы можете описать ему желаемый градиент и нарисовать градиент для вас. Вы уже прошли этот шаг; у вас есть уже описал градиент, который вы хотите (в PaintCode вместо от CAGradientLayer), и вы уже имеете желаемый градиент. Таким образом, глупо для вас даже хотите использовать CAGradientLayer, поскольку, если вы собираетесь это сделать, почему вы использовали PaintCode в первую очередь? Просто нарисуйте сам CGGradient в изображение, представление или даже слой.

+1

Частично верно, но когда вы создаете цельное приложение в PaintCode и хотите только один градиент, используемый в 'CAShapeLayer' (для анимации или что-то еще), это действительный запрос, чтобы иметь возможность получать цвета и места отдельно. Мы посмотрим на это. – Tricertops

3

Вы не можете получить цвета из CGGradient, но вы можете использовать одни и те же значения, чтобы установить свойства colors и locations CAGradientLayer. Возможно, это поможет вам изменить созданный класс PCGradient, чтобы сохранить цвета и местоположения в виде NSArrays, которые вы можете передать в CAGradientLayer.

1

Это может быть важно, если у вас есть библиотека градиентов и только изредка нужно использовать градиент в одном из двух форматов.

Да, это возможно, но для преобразования из обычной системы координат (с значениями от 0 до ширины и значений y от 0 до высоты) требуется математическая математика для системы координат, используемой CAGradientLayer (со значениями x от 0 до 1 и значения y от 0 до 1). И для этого требуется еще одна математика (довольно сложная), чтобы получить наклон.

Расстояние от 0 до 1 для x будет зависеть от ширины исходного прямоугольника. И расстояние от 0 до 1 для y будет зависеть от высоты исходного прямоугольника. Итак:

let convertedStartX = startX/Double(width) 
let convertedStartY = startY/Double(height) 
let convertedEndX = endX/Double(width) 
let convertedEndY = endY/Double(height) 

let intermediateStartPoint = CGPoint(x:convertedStartX,y:convertedStartY) 
let intermediateEndPoint = CGPoint(x:convertedEndX,y:convertedEndY) 

Это работает, если ваш первоначальный прямоугольник был квадратным. Если нет, наклон линии, определяющей угол градиента, будет неправильным! Чтобы исправить это увидеть отличный ответ здесь: CAGradientLayer diagonal gradient

Если вы выбираете утилиту оттуда, то вы можете установить окончательные преобразованные начальные и конечные точки следующим образом, начиная с уже скорректированными значениями точки сверху:

let fixedStartEnd:(CGPoint,CGPoint) = LinearGradientFixer.fixPoints(start: intermediateStartPoint, end: intermediateEndPoint, bounds: CGSize(width:width,height:height)) 

let myGradientLayer = CAGradientLayer() 
myGradientLayer.startPoint = fixedStartEnd.0 
myGradientLayer.endPoint = fixedStartEnd.1 

Вот код для полного Struct, который можно использовать для хранения данных градиента и получить обратно CGGradients или CAGradientLayers при необходимости:

import UIKit 

struct UniversalGradient { 

    //Doubles are more precise than CGFloats for the 
    //calculations needed to convert start and end 
    //to CAGradientLayers 1...0 format 

    var startX: Double 
    var startY: Double 
    var endX: Double 
    var endY: Double 

    let options: CGGradientDrawingOptions = [.drawsBeforeStartLocation, .drawsAfterEndLocation] 

    //for CAGradientLayer 
    var colors: [UIColor] 
    var locations: [Double] 

    //computed conversions 
    private var myCGColors: [CGColor] { 
     return self.colors .map {color in color.cgColor} 
    } 

    private var myCGFloatLocations: [CGFloat] { 
     return self.locations .map {location in CGFloat(location)} 
    } 

    //computed properties 
    var gradient: CGGradient { 
     return CGGradient(colorsSpace: nil, colors: myCGColors as CFArray, locations: myCGFloatLocations)! 
    } 

    var start: CGPoint { 
     return CGPoint(x: startX,y: startY) 
    } 
    var end: CGPoint { 
     return CGPoint(x: endX,y: endY) 
    } 

    //can't use computed property here 
    //since we need details of the specific environment's bounds to be passed in 
    //so this will be an instance function 

    func gradientLayer(width: CGFloat, height: CGFloat) -> CAGradientLayer { 

     //convert location x and y values from full coordinates to 0...1 for start and end 
     //this works great for position, but it gets the slope incorrect if the view is not square 

     //this is because the gradient is not drawn with the final scale 
     //it is drawn while the view is square, and then it gets stretched, changing the angle 
     //https://stackoverflow.com/questions/38821631/cagradientlayer-diagonal-gradient 

     let convertedStartX = startX/Double(width) 
     let convertedStartY = startY/Double(height) 
     let convertedEndX = endX/Double(width) 
     let convertedEndY = endY/Double(height) 

     let intermediateStartPoint = CGPoint(x:convertedStartX,y:convertedStartY) 
     let intermediateEndPoint = CGPoint(x:convertedEndX,y:convertedEndY) 

     let fixedStartEnd:(CGPoint,CGPoint) = LinearGradientFixer.fixPoints(start: intermediateStartPoint, end: intermediateEndPoint, bounds: CGSize(width:width,height:height)) 

     let myGradientLayer = CAGradientLayer() 
     myGradientLayer.startPoint = fixedStartEnd.0 
     myGradientLayer.endPoint = fixedStartEnd.1 

     myGradientLayer.locations = self.locations .map {location in NSNumber(value: location)} 
     myGradientLayer.colors = self.colors .map {color in color.cgColor} 

     return myGradientLayer 
    } 

} 
Смежные вопросы