英文:
Couldn't layout Subviews in UITableViewHeaderFooterView
问题
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?
英文:
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?
答案1
得分: 2
以下是您提供的代码的翻译部分:
好吧,您忽略了许多所需的代码(比如您的单元格类和控制器类)。
而且,您还没有展示您的`viewForHeaderInSection`方法的代码。
但是,我们可以看一个快速的示例...
**您的`ProfileHeaderView`稍作修改**
```swift
class ProfileHeaderView: UITableViewHeaderFooterView {
// MARK: - 子视图
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: - 生命周期
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
setupUI()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupUI()
}
// MARK: - 私有
private func setupUI() {
contentView.backgroundColor = .lightGray
addSuviews()
setupConstraints()
}
private func addSuviews() {
contentView.addSubview(userImage)
}
private func setupConstraints() {
let g = contentView.layoutMarginsGuide
// 这将避免自动布局的投诉
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),
])
}
}
一个简单的单标签单元格类
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),
])
}
}
一个带有表视图的简单视图控制器类 - 行数设置为30,以便我们可以看到部分标题保持在原位...
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")
// 移除默认填充
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 nil
}
}
当运行时看起来像这样:
请注意,我已经将HTML编码转换为适当的Swift代码。如果您需要更多帮助,请告诉我。
<details>
<summary>英文:</summary>
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][1]][1]
[1]: https://i.stack.imgur.com/euwNU.png
</details>
# 答案2
**得分**: 0
使用 `contentView.safeAreaLayoutGuide` 作为您的布局指南。
`safeAreaLayoutGuide` 表示 bars 之间的布局区域(例如状态栏和底部导航栏之间的布局)。
**编辑:** 更合理地设置您的表视图的约束(使用 `safeAreaLayoutGuide`),而不是对表视图中的各个视图分别进行设置。
<details>
<summary>英文:</summary>
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
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论