Home > Software engineering >  Swift - Blur UICollectionView Cell background
Swift - Blur UICollectionView Cell background

Time:08-19

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

CodePudding user response:

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

  • Related