Harry J
Harry J

Reputation: 1966

Swift image blur

I could be completely googling the wrong thing however I am trying to achieve this effect when images don't fit the required aspect ratio/dimensions. However, if the image is of size and doesn't require resizing, then this effect is not necessary. It's seen on the majority of large social medias, especially in stories.

Source: Google


Source: Google Images

Is there a library or code that mimics this sort of behaviour?

Upvotes: 2

Views: 2684

Answers (3)

Pankaj Kulkarni
Pankaj Kulkarni

Reputation: 561

The traditional UIKit solution is creating your own control view. Following is @IBDesignable and @IBInspectable class BlurImageView subclass of UIView. Create a file with name BlurImageView.swift and add following code to it. In storyboard in your view controller add an UIVIew and change its custom class using identity inspector to BlurImageView. Set image and you are all set.

@IBDesignable
class BlurImageView: UIView {

    private var backgroundImageView: UIImageView!
    private var foregroundImageView: UIImageView!

    private lazy var blurEffectView: UIVisualEffectView = UIVisualEffectView(effect: UIVisualEffect())

    @IBInspectable
    public var alphaForBlurEffect: CGFloat = 0.7 {
        didSet {
            applyBlur()
        }
    }

    public var blurEffect = UIBlurEffect(style: .regular) {
        didSet {
            applyBlur()
        }
    }

    @IBInspectable
    public var image: UIImage? {
        set {
            backgroundImageView.image = newValue
            foregroundImageView.image = newValue
        }
        get {
            return foregroundImageView.image
        }
    }

    // MARK: Initilisation
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupImages()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupImages()
    }

    private func createBlurEffectView() -> UIVisualEffectView {

        // create effect
        let effectView = UIVisualEffectView(effect: blurEffect)

        // set boundry and alpha
        effectView.frame = self.bounds
        effectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        effectView.alpha = alphaForBlurEffect

        return effectView
    }

    fileprivate func addImageView() -> UIImageView {
        let imageView = UIImageView(frame: self.bounds)
        imageView.clipsToBounds = true
        self.addSubview(imageView)
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
        imageView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
        imageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
        imageView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true

        return imageView
    }

    private func setupImages() {

        self.clipsToBounds = true

        // Setup background view
        backgroundImageView = addImageView()
        backgroundImageView.contentMode = .scaleAspectFill
        applyBlur()

        // setup foreground view
        foregroundImageView = addImageView()
        foregroundImageView.contentMode = .scaleAspectFit

    }

    private func applyBlur() {
        blurEffectView.removeFromSuperview()

        // generate new view
        blurEffectView = createBlurEffectView()

        backgroundImageView.addSubview(blurEffectView)
    }

}

Upvotes: 0

Pankaj Kulkarni
Pankaj Kulkarni

Reputation: 561

Here is SwiftUI solution inline with the one mentioned by Chris

I tested it using Xcode 11.2 and iOS 13.2. Note: I did not include the two test images named "VRectImage" and "HRectImage".

struct BlurImageView: View {
    let name = "VRectImage" // "VRectImage"

    var body: some View {

        ZStack {

            Image(self.name)
            .resizable()
            .aspectRatio(contentMode: .fill)
            .frame(width: 300, height: 300)
            .clipped()
            .blur(radius: 15)


            Image(self.name)
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: 300, height: 300)

        }
        .clipped()

    }
}

Upvotes: -1

Chris
Chris

Reputation: 8126

"Normally" i would say, this is the solution:

...but sigh unfortunately - and i have no idea why - the .fit does not work anymore as i tested it (just could test on 13.2) and it does not (!) show the whole picture but with .filled) ( to test it you have to insert a portrait photo, which is bigger than the screen to see my effect)

or shouldn't .fit show the whole picture? Am i wrong!?

struct ContentView: View {

    var name : String

    var body: some View {

        ZStack {

            Image(self.name)
                .resizable()
                .scaledToFill()
                .blur(radius: 15)


            Image(self.name)
                .resizable()
                .scaledToFit()

        }
    }
}

Upvotes: 2

Related Questions