Update
Как @Kurt Revis отметил в комментарии по этому вопросу, собственно - и самый быстрый - способ сделать это состоит в использовании CAGradientLayer
. Добавить CAGradientLayer
на ваш взгляд, что наполняет его пределы, то:
func updateGradient() {
// Sample random gradient
let gradientLocs:[CGFloat] = [0.0, 0.5, 1.0]
let gradientColors:[CGColorRef] = [
UIColor.whiteColor().CGColor,
UIColor.init(colorLiteralRed: 0.0, green: 0.0, blue: 0.25*Float(arc4random())/Float(UINT32_MAX), alpha: 1.0).CGColor,
UIColor.blackColor().CGColor
]
// Disable implicit animations if this is called via CADisplayLink
CATransaction.begin()
CATransaction.setDisableActions(true)
// Draw to existing CAGradientLayer
gradientBackgroundLayer.colors = gradientColors
gradientBackgroundLayer.locations = gradientLocs
CATransaction.commit()
}
Старый ответ
После нескольких экспериментов, я закончил с использованием CoreGraphics сделать градиент в 1px широкий CGImage
и затем положите на UIImageView
, чтобы сделать масштабирование. Я получаю твердые 60fps при температуре около 7-11% загрузки процессора, в зависимости от того, сколько цветов градиента содержит:
Подкласса UIImageView
с contentMode
установлен в ScaleToFill
, а затем вызвать следующий через CADisplayLink
для непрерывной анимации.
func updateGradient() {
// Sample random gradient
let gradientLocs:[CGFloat] = [0.0, 0.5, 1.0]
let gradientColors:[CGColorRef] = [
UIColor.whiteColor().CGColor,
UIColor.init(colorLiteralRed: 0.0, green: 0.0, blue: 0.25*Float(arc4random())/Float(UINT32_MAX), alpha: 1.0).CGColor,
UIColor.blackColor().CGColor
]
// Create context at 1px width and display height
let gradientWidth:Double = 1
let gradientHeight:Double = Double(UIScreen.mainScreen().bounds.height)
UIGraphicsBeginImageContext(CGSize(width: gradientWidth, height: gradientHeight))
let buffer:CGContextRef = UIGraphicsGetCurrentContext()!
// Draw gradient into buffer
let colorspace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradientCreateWithColors(colorspace, gradientColors, gradientLocs)
CGContextDrawLinearGradient(
buffer,
gradient,
CGPoint(x: 0.0, y: 0.0),
CGPoint(x: 0.0, y: gradientHeight),
CGGradientDrawingOptions.DrawsAfterEndLocation
)
// Let UIImageView superclass handle scaling
image = UIImage.init(CGImage: CGBitmapContextCreateImage(buffer)!)
// Avoid memory leaks...
UIGraphicsEndImageContext()
}
Предостережение: этот подход будет работать только для горизонтальных или вертикальных линейных градиентов.
Есть ли лучшие способы сделать это?
Почему бы не использовать ['CAGradientLayer'] (https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CAGradientLayer_class/index.html)? Рисование с помощью CA почти наверняка будет намного быстрее (и использовать гораздо меньше CPU), чем CG. –
Спасибо, Курт, я обновил ответ. – carton