简体   繁体   中英

Swift How do I convert a UIImageView into a UIImage Without Losing blur effect

I am making an app using Swift 4.0. It is a sort of social media app. My app has a collectionView (the users feed) with multiple collectionViewCells. The problem with this however is that for every cell I have, I am blurring a portion or sometimes all of the image. This causes heavy lag on the device after a couple scrolls to the point where you can barely use it.

In order to counter this I thought it would make much more sense instead of blurring the cells image I would just blur it when the user uploads it into the sql database and when it shows up in other users feed/timeline they're iPhone won't have to blur the image because the image they pulled from the database is already pulled.

I have had some luck turning UIImageViews into UIImages but whenever I render it to an image the blurring effect gets distorted and essentially turns into a white overlay with a some transparency.

Code for turning UIImageViews into UIImages:

extension UIImage {
    convenience init(view: UIView) {
        UIGraphicsBeginImageContext(view.frame.size)
        view.layer.render(in:UIGraphicsGetCurrentContext()!)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        self.init(cgImage: image!.cgImage!)
    }
}

After that I simply call it with

let background = UIImageView(frame: CGRect(x: 0, y: 0, width: cell.frame.width, height: 200))
background.image = profileImage
let label = UIBlurEffect(style: UIBlurEffectStyle.prominent)
let blurEffectView = UIVisualEffectView(effect: label)
blurEffectView.frame = CGRect(x: 0, y: 0, width: background.frame.width, height: background.frame.height)
background.addSubview(blurEffectView)
let secondImage = UIImage(view: background)

这就是我得到的

这就是我要的

It may be hard to see but there is no blur in the first image it is just a transparent white overlay

You need to take a snapshot of the container view after the visual effect view is applied. I will demonstrate a flow which will work.

Your Controller:

class PreviewController: UIViewController,VisualEffectCustomDelegate{
@IBOutlet weak var screenshotView: UIView!
@IBOutlet weak var previewImageView: UIImageView!


override func viewDidLoad() {
    super.viewDidLoad()


    addBlur()
}

func addBlur(){
    let label = UIBlurEffect(style: UIBlurEffectStyle.prominent)
    let blurEffectView = CustomVisualEffect(effect: label)
    blurEffectView.frame = CGRect(x: 0, y: 0, width: screenshotView.frame.width, height: screenshotView.frame.height)
    blurEffectView.delegate = self
    screenshotView.addSubview(blurEffectView)

}

func viewAppeared() {
    print("Appeared")
    previewImageView.image = screenshotView.screenShot
}


}


extension UIView {

var screenShot: UIImage?  {
    UIGraphicsBeginImageContextWithOptions(bounds.size, false, 1.0);
    if let _ = UIGraphicsGetCurrentContext() {
        drawHierarchy(in: bounds, afterScreenUpdates: true)
        let screenshot = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return screenshot
    }
    return nil
}
}

We implement a protocol VisualEffectCustomDelegate to the controller class.

protocol VisualEffectCustomDelegate {

func viewAppeared()
}

Create your own custom class as a child of VisualEffectView class:

class CustomVisualEffect: UIVisualEffectView {

var delegate: VisualEffectCustomDelegate!

override init(effect: UIVisualEffect?) {
    super.init(effect: effect)
}

convenience init(){
    self.init()
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

override func didMoveToWindow() {
    print("Visible Now")
    delegate.viewAppeared()
}
}

The above implementation will work. What happens here is as follows: Your controller class confirms to a protocol VisualEffectCustomDelegate, which has a function named viewAppeared. We are going to use this method when we know for sure that the visual effect view is visible in the window. We use the didMoveToWindow method of the UIView class to fire the protocol method. When you initiate the CustomVisualEffect view in your controller, pass the controller to the view object. I hope this is clear.

Since you are dealing with a UITableView/UICollectionView, make the changes to the code as you see fit.

How Do I Take a Screen Shot of a UIView?

// try like this

public extension UIImageView {
public func snapshotImage() -> UIImage? {
    UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0)
    drawHierarchy(in: bounds, afterScreenUpdates: false)
    let snapshotImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return snapshotImage
}

}

// get image from your imageview 
 let image = background.snapshotImage()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM