Apply gradient effect to a blur view

2019-05-21 04:19发布

问题:

How can I can add a gradient view that has blur effects in Swift? I can add a gradient layer (CAGradientLayer) quite easily to a view. I can also add a blur view (UIVisualEffectView) separately.

How can I combine both to create a blur view that also has a gradient element where by full blur fading to no blur?

An example of a similiar effect:

回答1:

If you know CoreImage, you can easily chain two filters together, one from the CICategoryBlur and one from the category CICategoryGradient.

Here's an example of usage. TO chain, just take the output of the first filter as the input of the next:

func convertImageToBW(image:UIImage) -> UIImage {

    let filter = CIFilter(name: "CIPhotoEffectMono")

    // convert UIImage to CIImage and set as input

    let ciInput = CIImage(image: image)
    filter?.setValue(ciInput, forKey: "inputImage")

    // get output CIImage, render as CGImage first to retain proper UIImage scale

    let ciOutput = filter?.outputImage
    let ciContext = CIContext()
    let cgImage = ciContext.createCGImage(ciOutput!, from: (ciOutput?.extent)!)

    return UIImage(cgImage: cgImage!)
}

The link above is to the Apple documentation.



回答2:

To achieve a blur view with gradient blur radius, you can do the following (per Apple document):

let ciContext = CIContext(options: nil)

if let inputImage = CIImage(image: yourUIImage) {
        let extent = inputImage.extent
        let h = extent.size.height
        guard let gradient = CIFilter(name: "CILinearGradient") else { return }
        gradient.setValue(CIVector(x: 0, y: 0.85 * h), forKey: "inputPoint0")
        gradient.setValue(CIColor.green, forKey: "inputColor0")
        gradient.setValue(CIVector(x: 0, y: 0.50 * h), forKey: "inputPoint1")
        gradient.setValue(CIColor(red: 0, green: 1, blue: 0, alpha: 0), forKey: "inputColor1")

        guard let mask = CIFilter(name: "CIMaskedVariableBlur") else { return }
        mask.setValue(inputImage.clampedToExtent(), forKey: kCIInputImageKey)
        // Set your blur radius here, default is 5
        mask.setValue(10, forKey: kCIInputRadiusKey) 
        mask.setValue(gradient.outputImage, forKey: "inputMask")

        guard let output = mask.outputImage,
            let cgImage = ciContext.createCGImage(output, from: extent) else { return }
        outUIImage = UIImage(cgImage: cgImage)
}

Here, inputPoint0 is the starting point of gradient ramp, inputPoint1 is the ending point. Note that for CIVector y increases from bottom to top. The input color you set doesn't matter, only its alpha is used to determine blur radius.

For your second question of dynamically applying CIFilter to an image underneath it, no, it's not possible. There is an Apple document on backgroundFilters that might make you think it is doable, until you see at the bottom ...

This property is not supported on layers in iOS.

What you should do is that, whenever you reset the image, apply the above operation to that image and set it to the image view.



标签: ios swift uiview