将 CGGradient 转换为 CAGradientLayer
Converting a CGGradient to a CAGradientLayer
我正在使用 PaintCode StyleKit 生成一堆渐变,但 PaintCode 将它们导出为 CGGradient
。我想添加这些渐变 a layer
。是否可以将 CGGradient
转换为 CAGradientLayer
?
没有。 CAGradientLayer 的要点是你可以向它描述你想要的渐变,它会为你绘制渐变。你已经过了那一步;你已经已经描述了你想要的渐变(PaintCode instead CAGradientLayer)因此你已经有 你想要的渐变。因此,即使 想要 使用 CAGradientLayer 对你来说也是愚蠢的,因为如果你打算这样做,你为什么首先使用 PaintCode?只需将 CGGradient 本身绘制到图像、视图甚至图层中即可。
您无法从 CGGradient 中获取颜色,但您可以使用相同的值来设置 CAGradientLayer 的 colors
和 locations
属性。也许它会帮助您修改生成的 PCGradient
class 以将颜色和位置保持为 NSArrays,您可以将其传递给 CAGradientLayer。
如果您有一个渐变库并且只是偶尔需要使用两种格式之一的渐变,这可能很重要。
是的,这是可能的,但需要一些数学运算才能从常规坐标系(x 值从 0 到宽度,y 值从 0 到高度)转换为 CAGradientLayer 使用的坐标系(x从 0 到 1 的值和从 0 到 1 的 y 值)。它需要更多的数学运算(相当复杂)才能获得正确的斜率。
x 从 0 到 1 的距离取决于原始矩形的宽度。 y 从 0 到 1 的距离取决于原始矩形的高度。所以:
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
这是一个完整结构的代码,您可以使用它来存储渐变数据并根据需要取回 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
//
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
}
}
我正在使用 PaintCode StyleKit 生成一堆渐变,但 PaintCode 将它们导出为 CGGradient
。我想添加这些渐变 a layer
。是否可以将 CGGradient
转换为 CAGradientLayer
?
没有。 CAGradientLayer 的要点是你可以向它描述你想要的渐变,它会为你绘制渐变。你已经过了那一步;你已经已经描述了你想要的渐变(PaintCode instead CAGradientLayer)因此你已经有 你想要的渐变。因此,即使 想要 使用 CAGradientLayer 对你来说也是愚蠢的,因为如果你打算这样做,你为什么首先使用 PaintCode?只需将 CGGradient 本身绘制到图像、视图甚至图层中即可。
您无法从 CGGradient 中获取颜色,但您可以使用相同的值来设置 CAGradientLayer 的 colors
和 locations
属性。也许它会帮助您修改生成的 PCGradient
class 以将颜色和位置保持为 NSArrays,您可以将其传递给 CAGradientLayer。
如果您有一个渐变库并且只是偶尔需要使用两种格式之一的渐变,这可能很重要。
是的,这是可能的,但需要一些数学运算才能从常规坐标系(x 值从 0 到宽度,y 值从 0 到高度)转换为 CAGradientLayer 使用的坐标系(x从 0 到 1 的值和从 0 到 1 的 y 值)。它需要更多的数学运算(相当复杂)才能获得正确的斜率。
x 从 0 到 1 的距离取决于原始矩形的宽度。 y 从 0 到 1 的距离取决于原始矩形的高度。所以:
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
这是一个完整结构的代码,您可以使用它来存储渐变数据并根据需要取回 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
//
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
}
}