Search code examples
iosswiftxcodeuicollectionviewuiblureffect

Swift - Blur UICollectionView Cell background


So I am trying to blur the background view of the UICollectionView cell. This is what I am trying to accomplish:

enter image description here

I tried using this extension:

extension UIView {
    func applyBlurEffect(_ style: UIBlurEffect.Style = .dark) {
        let blurEffect = UIBlurEffect(style: style)
        let blurEffectView = UIVisualEffectView(effect: blurEffect)
        blurEffectView.frame = bounds
        blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        addSubview(blurEffectView)
    }
}

And use it like this:

cell.backgroundColor = .clear
cell.backgroundView?.applyBlurEffect()

But this is the result I get:

enter image description here

Also tried changing from dark to light, but no changes.. What am I doing wrong here?

EDIT: Added UICollectionViewCell class:

import UIKit

class MenuCollectionViewCell: UICollectionViewCell {
    
    @IBOutlet weak var categoryEmoji: UILabel!
    @IBOutlet weak var categoryLabel: UILabel!
    @IBOutlet weak var lineView: UIView!
    
    override init(frame: CGRect) {
            super.init(frame: frame)
            commonInit()
        }
        required init?(coder: NSCoder) {
            super.init(coder: coder)
            commonInit()
        }
        private func commonInit() {

            contentView.backgroundColor = .clear
            
            let blurEffect = UIBlurEffect(style: .light)
            let blurEffectView = UIVisualEffectView(effect: blurEffect)
            blurEffectView.translatesAutoresizingMaskIntoConstraints = false
            contentView.addSubview(blurEffectView)
            
            blurEffectView.layer.cornerRadius = 20
            blurEffectView.clipsToBounds = true
            
            let g = contentView.layoutMarginsGuide
            NSLayoutConstraint.activate([
                // constrain blur view to all 4 sides of contentView
                blurEffectView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
                blurEffectView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
                blurEffectView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
                blurEffectView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
            ])
            
        }
}

And this is the result I have now. The label's are also blurred now.:

enter image description here


Solution

  • Don't try to modify the cell's background view. Much easier to add a UIVisualEffectView to the cell.

    Here's a very simple example. I created a background image similar to what you have in your post, and I used UIBlurEffect(style: .light) since the dark background doesn't really show the effect much:

    BlurCell class

    class BlurCell: UICollectionViewCell {
        public var text: String = "" {
            didSet {
                label.text = text.isEmpty ? " " : text
            }
        }
        
        private let label = UILabel()
        
        override init(frame: CGRect) {
            super.init(frame: frame)
            commonInit()
        }
        required init?(coder: NSCoder) {
            super.init(coder: coder)
            commonInit()
        }
        private func commonInit() {
    
            contentView.backgroundColor = .clear
            
            let blurEffect = UIBlurEffect(style: .light)
            let blurEffectView = UIVisualEffectView(effect: blurEffect)
            blurEffectView.translatesAutoresizingMaskIntoConstraints = false
            contentView.addSubview(blurEffectView)
            
            blurEffectView.layer.cornerRadius = 20
            blurEffectView.clipsToBounds = true
            
            label.translatesAutoresizingMaskIntoConstraints = false
            label.font = .systemFont(ofSize: 60.0, weight: .bold)
            label.textAlignment = .center
            label.textColor = .white
            
            contentView.addSubview(label)
            
            let g = contentView.layoutMarginsGuide
            NSLayoutConstraint.activate([
                // constrain blur view to all 4 sides of contentView
                blurEffectView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
                blurEffectView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
                blurEffectView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
                blurEffectView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
    
                // center the label
                label.centerXAnchor.constraint(equalTo: g.centerXAnchor),
                label.centerYAnchor.constraint(equalTo: g.centerYAnchor),
            ])
            
        }
    }
    

    Simple example controller class

    class BlurVC: UIViewController {
        
        var collectionView: UICollectionView!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            let imageView = UIImageView()
            if let img = UIImage(named: "bkg3") {
                imageView.image = img
            }
            //imageView.contentMode = .scaleAspectFill
            imageView.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(imageView)
            
            let fl = UICollectionViewFlowLayout()
            fl.scrollDirection = .vertical
            fl.itemSize = CGSize(width: 160.0, height: 180.0)
            fl.minimumLineSpacing = 0
            fl.minimumInteritemSpacing = 0
            
            collectionView = UICollectionView(frame: .zero, collectionViewLayout: fl)
            collectionView.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(collectionView)
            
            let g = view.safeAreaLayoutGuide
            NSLayoutConstraint.activate([
                
                imageView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
                imageView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
                imageView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
                imageView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
    
                collectionView.topAnchor.constraint(equalTo: g.topAnchor, constant: 160.0),
                collectionView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
                collectionView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
                collectionView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
    
            ])
            
            collectionView.backgroundColor = .clear
            
            collectionView.register(BlurCell.self, forCellWithReuseIdentifier: "c")
            collectionView.dataSource = self
            collectionView.delegate = self
        }
        
    }
    extension BlurVC: UICollectionViewDataSource, UICollectionViewDelegate {
        func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return 20
        }
        func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
            let c = collectionView.dequeueReusableCell(withReuseIdentifier: "c", for: indexPath) as! BlurCell
            c.text = "\(indexPath.item)"
            return c
        }
    }
    

    Result:

    enter image description here