skip to Main Content

I’m trying to make a custom header for 0 section of my UITableView. Here’s the code I’m using to create this header:

class ProfileHeaderView: UITableViewHeaderFooterView {
    
    // MARK: - Subviews
    
    private var statusText: String = ""
    
    private lazy var userImage: UIImageView = {
        let imageView = UIImageView(image: UIImage(named: me.login))
                
        imageView.layer.cornerRadius = 48
        imageView.clipsToBounds = true
        
        imageView.translatesAutoresizingMaskIntoConstraints = false
        
        return imageView
    }()
    
    ...
    
    // MARK: - Lifecycle
    
    override init(reuseIdentifier: String?) {
        super.init(reuseIdentifier: reuseIdentifier)
        setupUI()
        addSuviews()
        setupConstraints()
    }
     // MARK: - Private

    private func setupUI() {
        backgroundColor = .lightGray
    }
    
    private func addSuviews() {
        addSubview(userImage)
    }
    
    private func setupConstraints() {
        let layoutMarginGuide = contentView.layoutMarginsGuide
            
        NSLayoutConstraint.activate([
            userImage.leadingAnchor.constraint(equalTo: layoutMarginGuide.leadingAnchor, constant: 10),
            userImage.topAnchor.constraint(equalTo: layoutMarginGuide.topAnchor, constant: 16),
            userImage.bottomAnchor.constraint(equalTo: layoutMarginGuide.bottomAnchor, constant: -16),
            userImage.widthAnchor.constraint(equalToConstant: 90),
            userImage.heightAnchor.constraint(equalToConstant: 90),
        ])
    }
}

Here’s how I add this header in my ViewController:

    private func setupConstraints() {
        feedView.frame = view.bounds
        
        feedView.delegate = self
        feedView.dataSource = self
        feedView.register(PostViewCell.self, forCellReuseIdentifier: "cell")
        feedView.register(ProfileHeaderView.self, forHeaderFooterViewReuseIdentifier: "ProfileHeaderView")
        //feedView.register(ProfileHeaderView.self, forHeaderFooterViewReuseIdentifier: "profileView")
    }

Here’s the result I’m getting:
Screenshot

As you see, image is ignoring safeArea on the screen. How to fix it?

2

Answers


  1. Use contentView.safeAreaLayoutGuide instead of contentView.layoutMarginsGuide as your layout guide.

    safeAreaLayoutGuide represents the layout area in between bars (e.g the layout between the status bar and the home bar)

    EDIT: It probably makes more sense to correctly set the constraints of your table view (using the safeAreaLayoutGuide) instead of having to do that for individual views within your table view

    Login or Signup to reply.
  2. Well, you left out much of the needed code (such as your cell class and your controller class).

    And, you haven’t shown your code for viewForHeaderInSection.

    But, we can look at a quick example…

    your ProfileHeaderView with minor modifications

    class ProfileHeaderView: UITableViewHeaderFooterView {
        
        // MARK: - Subviews
        
        private var statusText: String = ""
        
        private lazy var userImage: UIImageView = {
            //let imageView = UIImageView(image: UIImage(named: me.login))
            let imageView = UIImageView(image: UIImage(named: "face"))
    
            imageView.layer.cornerRadius = 48
            imageView.clipsToBounds = true
            
            imageView.translatesAutoresizingMaskIntoConstraints = false
            
            return imageView
        }()
        
        //...
        
        // MARK: - Lifecycle
        
        override init(reuseIdentifier: String?) {
            super.init(reuseIdentifier: reuseIdentifier)
            setupUI()
        }
        required init?(coder: NSCoder) {
            super.init(coder: coder)
            setupUI()
        }
        // MARK: - Private
        
        private func setupUI() {
            contentView.backgroundColor = .lightGray
            addSuviews()
            setupConstraints()
        }
        
        private func addSuviews() {
            contentView.addSubview(userImage)
        }
        
        private func setupConstraints() {
            let g = contentView.layoutMarginsGuide
            
            // this will avoid auto-layout complaints
            let bottomC = userImage.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -16.0)
            bottomC.priority = .required - 1
            
            NSLayoutConstraint.activate([
                userImage.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 10),
                userImage.topAnchor.constraint(equalTo: g.topAnchor, constant: 16),
                
                //userImage.bottomAnchor.constraint(equalTo: layoutMarginGuide.bottomAnchor, constant: -16),
                bottomC,
                
                userImage.widthAnchor.constraint(equalToConstant: 90),
                userImage.heightAnchor.constraint(equalToConstant: 90),
            ])
        }
    }
    

    a simple single-label cell class

    class PostViewCell: UITableViewCell {
        let theLabel = UILabel()
        override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            commonInit()
        }
        required init?(coder: NSCoder) {
            super.init(coder: coder)
            commonInit()
        }
        private func commonInit() {
            theLabel.translatesAutoresizingMaskIntoConstraints = false
            contentView.addSubview(theLabel)
            let g = contentView.layoutMarginsGuide
            NSLayoutConstraint.activate([
                theLabel.topAnchor.constraint(equalTo: g.topAnchor),
                theLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor),
                theLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor),
                theLabel.bottomAnchor.constraint(equalTo: g.bottomAnchor),
            ])
        }
    }
    

    a simple view controller class with table view – number of rows set to 30 so we can see the section header stays in place…

    class FeedViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
        
        let feedView = UITableView()
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            self.title = "Log In"
            view.backgroundColor = .systemBackground
            
            feedView.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(feedView)
            
            let g = view.safeAreaLayoutGuide
            NSLayoutConstraint.activate([
                feedView.topAnchor.constraint(equalTo: g.topAnchor),
                feedView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
                feedView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
                feedView.bottomAnchor.constraint(equalTo: g.bottomAnchor),
            ])
            
            feedView.delegate = self
            feedView.dataSource = self
            feedView.register(PostViewCell.self, forCellReuseIdentifier: "cell")
            feedView.register(ProfileHeaderView.self, forHeaderFooterViewReuseIdentifier: "ProfileHeaderView")
            
            // remove default padding
            feedView.sectionHeaderTopPadding = 0.0
    
        }
        func numberOfSections(in tableView: UITableView) -> Int {
            return 1
        }
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 30
        }
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! PostViewCell
            cell.theLabel.text = "(indexPath)"
            return cell
        }
        func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
            if section == 0 {
                let v = tableView.dequeueReusableHeaderFooterView(withIdentifier: "ProfileHeaderView")
                return v
            }
            // return some other header view for subsequent sections?
            return nil
        }
    }
    

    Looks like this when run:

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search