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:
As you see, image is ignoring safeArea on the screen. How to fix it?
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: