swiftuikit

Blur container with a button anchored to the bottom of the screen with a table view


I have this code and I'm trying to make the top edge of the bottom container (the one with the button) blurred, so that the content from the table view appears blurred at the bottom.

Unfortunately, I can't get this to work. Here's my code and an example of what I'm trying to achieve — does anyone have an idea how to make this work? Just to remind you, I want to do this in UIKit

Expected: enter image description here

What I have: enter image description here

My code

import UIKit
import SnapKit

final class BlurredTableViewController: UIViewController {
    
    private let tableView = UITableView()
    
    private lazy var blurView: UIVisualEffectView = {
        let blurEffect = UIBlurEffect(style: .systemThinMaterial)
        let blurView = UIVisualEffectView(effect: blurEffect)
        blurView.clipsToBounds = true
        blurView.contentView.addSubview(actionButton)
        actionButton.snp.makeConstraints { make in
            make.leading.trailing.top.equalToSuperview().inset(16)
            make.bottom.equalToSuperview().inset(32)
        }
        
        return blurView
    }()
    
    private lazy var actionButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Tap me", for: .normal)
        button.titleLabel?.font = .boldSystemFont(ofSize: 18)
        button.backgroundColor = .systemBlue
        button.setTitleColor(.white, for: .normal)
        button.layer.cornerRadius = 12
        button.clipsToBounds = true
        return button
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .systemBackground
        setupLayout()
    }
    
    private func setupLayout() {
        view.addSubview(tableView)
        view.addSubview(blurView)
        
        tableView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        
        blurView.snp.makeConstraints { make in
            make.leading.trailing.equalTo(view.safeAreaLayoutGuide)
            make.bottom.equalToSuperview()
            make.height.equalTo(100)
        }
        
        tableView.backgroundColor = .clear
        tableView.contentInset.bottom = 100
        tableView.scrollIndicatorInsets.bottom = 100
        
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        tableView.dataSource = self
    }
}

// MARK: - UITableViewDataSource
extension BlurredTableViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 50
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = "Row \(indexPath.row + 1)"
        cell.backgroundColor = .clear
        cell.contentView.backgroundColor = .clear
        cell.textLabel?.backgroundColor = .clear
        cell.selectionStyle = .none
        
        return cell
    }
}

Solution

  • ... the same kind of blur effect that, for example, iOS 26 uses at the top edge of the screen. What I’m aiming for is that the top edge of the area containing the button would blur the content from the table view behind it.

    I don't know what iOS 26 does. What I can tell you is what we have always done in our app, namely to use a gradient mask view whose background color matches the background color of what's behind it. To me, the result looks like your desired result. But it is not a true blur; it's a fade. You cannot apply a gradient mask to a UIVisualEffectView, so that approach is just not going to work.

    enter image description here