无法在UITableViewHeaderFooterView中布置子视图。

huangapple go评论107阅读模式
英文:

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:

  1. class ProfileHeaderView: UITableViewHeaderFooterView {
  2. // MARK: - Subviews
  3. private var statusText: String = ""
  4. private lazy var userImage: UIImageView = {
  5. let imageView = UIImageView(image: UIImage(named: me.login))
  6. imageView.layer.cornerRadius = 48
  7. imageView.clipsToBounds = true
  8. imageView.translatesAutoresizingMaskIntoConstraints = false
  9. return imageView
  10. }()
  11. ...
  12. // MARK: - Lifecycle
  13. override init(reuseIdentifier: String?) {
  14. super.init(reuseIdentifier: reuseIdentifier)
  15. setupUI()
  16. addSuviews()
  17. setupConstraints()
  18. }
  19. // MARK: - Private
  20. private func setupUI() {
  21. backgroundColor = .lightGray
  22. }
  23. private func addSuviews() {
  24. addSubview(userImage)
  25. }
  26. private func setupConstraints() {
  27. let layoutMarginGuide = contentView.layoutMarginsGuide
  28. NSLayoutConstraint.activate([
  29. userImage.leadingAnchor.constraint(equalTo: layoutMarginGuide.leadingAnchor, constant: 10),
  30. userImage.topAnchor.constraint(equalTo: layoutMarginGuide.topAnchor, constant: 16),
  31. userImage.bottomAnchor.constraint(equalTo: layoutMarginGuide.bottomAnchor, constant: -16),
  32. userImage.widthAnchor.constraint(equalToConstant: 90),
  33. userImage.heightAnchor.constraint(equalToConstant: 90),
  34. ])
  35. }
  36. }

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

  1. private func setupConstraints() {
  2. feedView.frame = view.bounds
  3. feedView.delegate = self
  4. feedView.dataSource = self
  5. feedView.register(PostViewCell.self, forCellReuseIdentifier: "cell")
  6. feedView.register(ProfileHeaderView.self, forHeaderFooterViewReuseIdentifier: "ProfileHeaderView")
  7. //feedView.register(ProfileHeaderView.self, forHeaderFooterViewReuseIdentifier: "profileView")
  8. }

Here's the result I'm getting:
无法在UITableViewHeaderFooterView中布置子视图。

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:

  1. class ProfileHeaderView: UITableViewHeaderFooterView {
  2. // MARK: - Subviews
  3. private var statusText: String = ""
  4. private lazy var userImage: UIImageView = {
  5. let imageView = UIImageView(image: UIImage(named: me.login))
  6. imageView.layer.cornerRadius = 48
  7. imageView.clipsToBounds = true
  8. imageView.translatesAutoresizingMaskIntoConstraints = false
  9. return imageView
  10. }()
  11. ...
  12. // MARK: - Lifecycle
  13. override init(reuseIdentifier: String?) {
  14. super.init(reuseIdentifier: reuseIdentifier)
  15. setupUI()
  16. addSuviews()
  17. setupConstraints()
  18. }
  19. // MARK: - Private
  20. private func setupUI() {
  21. backgroundColor = .lightGray
  22. }
  23. private func addSuviews() {
  24. addSubview(userImage)
  25. }
  26. private func setupConstraints() {
  27. let layoutMarginGuide = contentView.layoutMarginsGuide
  28. NSLayoutConstraint.activate([
  29. userImage.leadingAnchor.constraint(equalTo: layoutMarginGuide.leadingAnchor, constant: 10),
  30. userImage.topAnchor.constraint(equalTo: layoutMarginGuide.topAnchor, constant: 16),
  31. userImage.bottomAnchor.constraint(equalTo: layoutMarginGuide.bottomAnchor, constant: -16),
  32. userImage.widthAnchor.constraint(equalToConstant: 90),
  33. userImage.heightAnchor.constraint(equalToConstant: 90),
  34. ])
  35. }
  36. }

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

  1. private func setupConstraints() {
  2. feedView.frame = view.bounds
  3. feedView.delegate = self
  4. feedView.dataSource = self
  5. feedView.register(PostViewCell.self, forCellReuseIdentifier: "cell")
  6. feedView.register(ProfileHeaderView.self, forHeaderFooterViewReuseIdentifier: "ProfileHeaderView")
  7. //feedView.register(ProfileHeaderView.self, forHeaderFooterViewReuseIdentifier: "profileView")
  8. }

Here's the result I'm getting:
无法在UITableViewHeaderFooterView中布置子视图。

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

答案1

得分: 2

以下是您提供的代码的翻译部分:

  1. 好吧,您忽略了许多所需的代码(比如您的单元格类和控制器类)。
  2. 而且,您还没有展示您的`viewForHeaderInSection`方法的代码。
  3. 但是,我们可以看一个快速的示例...
  4. **您的`ProfileHeaderView`稍作修改**
  5. ```swift
  6. class ProfileHeaderView: UITableViewHeaderFooterView {
  7. // MARK: - 子视图
  8. private var statusText: String = ""
  9. private lazy var userImage: UIImageView = {
  10. //let imageView = UIImageView(image: UIImage(named: me.login))
  11. let imageView = UIImageView(image: UIImage(named: "face"))
  12. imageView.layer.cornerRadius = 48
  13. imageView.clipsToBounds = true
  14. imageView.translatesAutoresizingMaskIntoConstraints = false
  15. return imageView
  16. }()
  17. //...
  18. // MARK: - 生命周期
  19. override init(reuseIdentifier: String?) {
  20. super.init(reuseIdentifier: reuseIdentifier)
  21. setupUI()
  22. }
  23. required init?(coder: NSCoder) {
  24. super.init(coder: coder)
  25. setupUI()
  26. }
  27. // MARK: - 私有
  28. private func setupUI() {
  29. contentView.backgroundColor = .lightGray
  30. addSuviews()
  31. setupConstraints()
  32. }
  33. private func addSuviews() {
  34. contentView.addSubview(userImage)
  35. }
  36. private func setupConstraints() {
  37. let g = contentView.layoutMarginsGuide
  38. // 这将避免自动布局的投诉
  39. let bottomC = userImage.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -16.0)
  40. bottomC.priority = .required - 1
  41. NSLayoutConstraint.activate([
  42. userImage.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 10),
  43. userImage.topAnchor.constraint(equalTo: g.topAnchor, constant: 16),
  44. //userImage.bottomAnchor.constraint(equalTo: layoutMarginGuide.bottomAnchor, constant: -16),
  45. bottomC,
  46. userImage.widthAnchor.constraint(equalToConstant: 90),
  47. userImage.heightAnchor.constraint(equalToConstant: 90),
  48. ])
  49. }
  50. }

一个简单的单标签单元格类

  1. class PostViewCell: UITableViewCell {
  2. let theLabel = UILabel()
  3. override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
  4. super.init(style: style, reuseIdentifier: reuseIdentifier)
  5. commonInit()
  6. }
  7. required init?(coder: NSCoder) {
  8. super.init(coder: coder)
  9. commonInit()
  10. }
  11. private func commonInit() {
  12. theLabel.translatesAutoresizingMaskIntoConstraints = false
  13. contentView.addSubview(theLabel)
  14. let g = contentView.layoutMarginsGuide
  15. NSLayoutConstraint.activate([
  16. theLabel.topAnchor.constraint(equalTo: g.topAnchor),
  17. theLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor),
  18. theLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor),
  19. theLabel.bottomAnchor.constraint(equalTo: g.bottomAnchor),
  20. ])
  21. }
  22. }

一个带有表视图的简单视图控制器类 - 行数设置为30,以便我们可以看到部分标题保持在原位...

  1. class FeedViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
  2. let feedView = UITableView()
  3. override func viewDidLoad() {
  4. super.viewDidLoad()
  5. self.title = "Log In"
  6. view.backgroundColor = .systemBackground
  7. feedView.translatesAutoresizingMaskIntoConstraints = false
  8. view.addSubview(feedView)
  9. let g = view.safeAreaLayoutGuide
  10. NSLayoutConstraint.activate([
  11. feedView.topAnchor.constraint(equalTo: g.topAnchor),
  12. feedView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
  13. feedView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
  14. feedView.bottomAnchor.constraint(equalTo: g.bottomAnchor),
  15. ])
  16. feedView.delegate = self
  17. feedView.dataSource = self
  18. feedView.register(PostViewCell.self, forCellReuseIdentifier: "cell")
  19. feedView.register(ProfileHeaderView.self, forHeaderFooterViewReuseIdentifier: "ProfileHeaderView")
  20. // 移除默认填充
  21. feedView.sectionHeaderTopPadding = 0.0
  22. }
  23. func numberOfSections(in tableView: UITableView) -> Int {
  24. return 1
  25. }
  26. func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  27. return 30
  28. }
  29. func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  30. let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! PostViewCell
  31. cell.theLabel.text = "\(indexPath)"
  32. return cell
  33. }
  34. func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
  35. if section == 0 {
  36. let v = tableView.dequeueReusableHeaderFooterView(withIdentifier: "ProfileHeaderView")
  37. return v
  38. }
  39. // 为后续部分返回其他标题视图?
  40. return nil
  41. }
  42. }

当运行时看起来像这样:

无法在UITableViewHeaderFooterView中布置子视图。

  1. 请注意,我已经将HTML编码转换为适当的Swift代码。如果您需要更多帮助,请告诉我。
  2. <details>
  3. <summary>英文:</summary>
  4. Well, you left out much of the needed code (such as your cell class and your controller class).
  5. And, you haven&#39;t shown your code for `viewForHeaderInSection`.
  6. But, we can look at a quick example...
  7. **your `ProfileHeaderView` with minor modifications**
  8. class ProfileHeaderView: UITableViewHeaderFooterView {
  9. // MARK: - Subviews
  10. private var statusText: String = &quot;&quot;
  11. private lazy var userImage: UIImageView = {
  12. //let imageView = UIImageView(image: UIImage(named: me.login))
  13. let imageView = UIImageView(image: UIImage(named: &quot;face&quot;))
  14. imageView.layer.cornerRadius = 48
  15. imageView.clipsToBounds = true
  16. imageView.translatesAutoresizingMaskIntoConstraints = false
  17. return imageView
  18. }()
  19. //...
  20. // MARK: - Lifecycle
  21. override init(reuseIdentifier: String?) {
  22. super.init(reuseIdentifier: reuseIdentifier)
  23. setupUI()
  24. }
  25. required init?(coder: NSCoder) {
  26. super.init(coder: coder)
  27. setupUI()
  28. }
  29. // MARK: - Private
  30. private func setupUI() {
  31. contentView.backgroundColor = .lightGray
  32. addSuviews()
  33. setupConstraints()
  34. }
  35. private func addSuviews() {
  36. contentView.addSubview(userImage)
  37. }
  38. private func setupConstraints() {
  39. let g = contentView.layoutMarginsGuide
  40. // this will avoid auto-layout complaints
  41. let bottomC = userImage.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -16.0)
  42. bottomC.priority = .required - 1
  43. NSLayoutConstraint.activate([
  44. userImage.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 10),
  45. userImage.topAnchor.constraint(equalTo: g.topAnchor, constant: 16),
  46. //userImage.bottomAnchor.constraint(equalTo: layoutMarginGuide.bottomAnchor, constant: -16),
  47. bottomC,
  48. userImage.widthAnchor.constraint(equalToConstant: 90),
  49. userImage.heightAnchor.constraint(equalToConstant: 90),
  50. ])
  51. }
  52. }
  53. **a simple single-label cell class**
  54. class PostViewCell: UITableViewCell {
  55. let theLabel = UILabel()
  56. override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
  57. super.init(style: style, reuseIdentifier: reuseIdentifier)
  58. commonInit()
  59. }
  60. required init?(coder: NSCoder) {
  61. super.init(coder: coder)
  62. commonInit()
  63. }
  64. private func commonInit() {
  65. theLabel.translatesAutoresizingMaskIntoConstraints = false
  66. contentView.addSubview(theLabel)
  67. let g = contentView.layoutMarginsGuide
  68. NSLayoutConstraint.activate([
  69. theLabel.topAnchor.constraint(equalTo: g.topAnchor),
  70. theLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor),
  71. theLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor),
  72. theLabel.bottomAnchor.constraint(equalTo: g.bottomAnchor),
  73. ])
  74. }
  75. }
  76. **a simple view controller class with table view** - number of rows set to 30 so we can see the section header stays in place...
  77. class FeedViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
  78. let feedView = UITableView()
  79. override func viewDidLoad() {
  80. super.viewDidLoad()
  81. self.title = &quot;Log In&quot;
  82. view.backgroundColor = .systemBackground
  83. feedView.translatesAutoresizingMaskIntoConstraints = false
  84. view.addSubview(feedView)
  85. let g = view.safeAreaLayoutGuide
  86. NSLayoutConstraint.activate([
  87. feedView.topAnchor.constraint(equalTo: g.topAnchor),
  88. feedView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
  89. feedView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
  90. feedView.bottomAnchor.constraint(equalTo: g.bottomAnchor),
  91. ])
  92. feedView.delegate = self
  93. feedView.dataSource = self
  94. feedView.register(PostViewCell.self, forCellReuseIdentifier: &quot;cell&quot;)
  95. feedView.register(ProfileHeaderView.self, forHeaderFooterViewReuseIdentifier: &quot;ProfileHeaderView&quot;)
  96. // remove default padding
  97. feedView.sectionHeaderTopPadding = 0.0
  98. }
  99. func numberOfSections(in tableView: UITableView) -&gt; Int {
  100. return 1
  101. }
  102. func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
  103. return 30
  104. }
  105. func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
  106. let cell = tableView.dequeueReusableCell(withIdentifier: &quot;cell&quot;, for: indexPath) as! PostViewCell
  107. cell.theLabel.text = &quot;\(indexPath)&quot;
  108. return cell
  109. }
  110. func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -&gt; UIView? {
  111. if section == 0 {
  112. let v = tableView.dequeueReusableHeaderFooterView(withIdentifier: &quot;ProfileHeaderView&quot;)
  113. return v
  114. }
  115. // return some other header view for subsequent sections?
  116. return nil
  117. }
  118. }
  119. Looks like this when run:
  120. [![enter image description here][1]][1]
  121. [1]: https://i.stack.imgur.com/euwNU.png
  122. </details>
  123. # 答案2
  124. **得分**: 0
  125. 使用 `contentView.safeAreaLayoutGuide` 作为您的布局指南。
  126. `safeAreaLayoutGuide` 表示 bars 之间的布局区域(例如状态栏和底部导航栏之间的布局)。
  127. **编辑:** 更合理地设置您的表视图的约束(使用 `safeAreaLayoutGuide`),而不是对表视图中的各个视图分别进行设置。
  128. <details>
  129. <summary>英文:</summary>
  130. Use `contentView.safeAreaLayoutGuide` instead of `contentView.layoutMarginsGuide` as your layout guide.
  131. `safeAreaLayoutGuide` represents the layout area in between bars (e.g the layout between the status bar and the home bar)
  132. **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
  133. </details>

huangapple
  • 本文由 发表于 2023年7月4日 20:33:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/76612691.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定