在iOS

时间:2015-12-30 21:25:15

标签: ios swift core-graphics gradient linear-gradients

我需要使用CADisplayLink绘制每帧更新的动画线性渐变。使用CoreGraphics直接绘制到全屏幕上下文很慢,我在iPad Air上以全CPU负载大约40fps。

最快的方法是什么?

1 个答案:

答案 0 :(得分:1)

<强>更新

正如@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进行缩放。根据渐变包含的颜色数量,我在CPU负载大约7-11%时得到稳定的60fps:

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()
}

警告:此方法仅适用于水平或垂直线性渐变。

有更好的方法吗?