1

I have created a UIImageView BackView to create a blurry background with a gradient Layer to black. (To create something like Spotify artists profile.)

I want to place this imageview behind the navigationBar for better looks. But to achieve this, I need a UIImage. I cannot just take BackView.image because this is just the source image without the BlurryView or the gradient Layer.

So I found this code on HackingWithSwift:

let renderer = UIGraphicsImageRenderer(size: rect.size)
let image = renderer.image { ctx in
    backView.drawHierarchy(in: backView.bounds, afterScreenUpdates: true)
}

But this does not render the view as it is sadly. It draws just the gradientLayer without anything behind it. Does someone have a code snippet to get all Subviews into the rendered Image?

Below I added my UIImageView-class and the function which handles the renderer:

class BackView: UIImageView {

var thisframe: CGRect
var anImage: UIImage? {
    didSet {
        setupImage()
    }
}

override init(frame: CGRect) {
    self.thisframe = frame
    super.init(frame: .zero)
    self.anImage = UIImage(named: "gray")
    setupImage()
}

func setupImage() {
    self.image = anImage
    self.addSubview(blurry)
    self.addSubview(blacky)
    gradientLayer.removeFromSuperlayer()
    self.layer.insertSublayer(gradientLayer, at: 1)
    print(gradientLayer.bounds)
}

lazy var blurry: UIVisualEffectView = {
    let blur = UIVisualEffectView()
    blur.effect = UIBlurEffect(style: .regular)
    blur.frame = (thisframe)
    return blur
}()

lazy var blacky: UIImageView = {
    let black = UIImageView()
    black.backgroundColor = .black
    black.alpha = 0.0
    black.frame = (thisframe)
    return black
}()

lazy var gradientLayer: CAGradientLayer = {
    let gradient = CAGradientLayer()
    gradient.colors = [UIColor.black.withAlphaComponent(0.0).cgColor,
                       UIColor.black.withAlphaComponent(1.0).cgColor]
    gradient.frame = (thisframe)
    gradient.startPoint = CGPoint(x: 0.5, y: 0)
    gradient.endPoint = CGPoint(x: 0.5, y: 1)
    return gradient
}()

And here the function:

    func setupNavBarBackground() {
    let renderer = UIGraphicsImageRenderer(size: rect.size)
    let image = renderer.image { ctx in
        backView.drawHierarchy(in: backView.bounds, afterScreenUpdates: true)
    }
    self.navigationController?.navigationBar.barTintColor = .clear
    self.navigationController?.navigationBar.backgroundColor = .clear
    self.navigationController?.navigationBar.setBackgroundImage(image, for: .default)
    self.navigationController?.navigationBar.shadowImage = image
}
Noodledew
  • 509
  • 4
  • 19
  • You're calling `setupImage()` twice. First in your `init` code and second in `didSet` which is called when you assign image to `anImage` – inokey Sep 14 '18 at 15:06
  • I have to call it twice. First to present a default Image and after I fetched the actual image It sets it again. It doesn't get called too much. – Noodledew Sep 14 '18 at 15:29
  • Yeah, I understand that. I mean that you call it twice during the initialisation process which causes all of your `setupImage `code getting executed twice. Now every time you will set a new image, it will be executed again, meaning all of your gradient layers and blurs will be added again and again. That is probably the reason why you don't see anything at all. It's just getting obscured with all the stuff you add there on top of it. – inokey Sep 14 '18 at 15:32
  • I have an accepted answer that I think may help you: https://stackoverflow.com/questions/51813876/how-to-save-a-couple-of-images-as-one-image-to-photo-library-in-swift/51813899#51813899 –  Sep 14 '18 at 15:44
  • @inokey You are mixing "anImage" with the image of the UIImageView. It's not an endless loop. – Noodledew Sep 14 '18 at 15:49
  • @dfd Thanks, I'm getting an error of it, but maybe I can do it with this approach. – Noodledew Sep 14 '18 at 15:55
  • What error? Maybe I can help - and yeah, maybe I'm not grasping the actual issue. –  Sep 14 '18 at 16:37
  • Separate comment in case I'm really not getting it - your question title says "render UIImageView to UIImage". What does that mean? A `UIImageView` **renders** a `UIImage`. (It doesn't go backwards.) You can do several things *with* a `UIImageView.image` property - which is *always* a `UIImage`. But that already *is* a `UIImage`. I was assuming you had a UIImageView with subviews and needed to simply use CoreGraphics to create a new one with everything inside it. –  Sep 14 '18 at 16:42
  • I did not know that such thing as CoreGraphics exist. I'm only 6 weeks into Swift. What aspect of it should I look for? – Noodledew Sep 14 '18 at 20:09

0 Answers0