提问人:Philipp 提问时间:7/4/2023 更新时间:7/4/2023 访问量:52
无法在 UITableViewHeaderFooterView 中布局子视图
Couldn't layout Subviews in UITableViewHeaderFooterView
问:
我正在尝试为我的 UITableView 的 0 部分制作一个自定义标头。下面是我用来创建此标头的代码:
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),
])
}
}
以下是我在 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")
}
如您所见,图像忽略了屏幕上的 safeArea。如何解决?
答:
0赞
ProtocolGuy
7/4/2023
#1
使用而不是作为布局指南。contentView.safeAreaLayoutGuide
contentView.layoutMarginsGuide
safeAreaLayoutGuide
表示栏之间的布局区域(例如,状态栏和主栏之间的布局)
编辑:正确设置表视图的约束(使用 )可能更有意义,而不必对表视图中的单个视图执行此操作safeAreaLayoutGuide
2赞
DonMag
7/4/2023
#2
好吧,您遗漏了许多所需的代码(例如单元类和控制器类)。
而且,您尚未显示 的代码。viewForHeaderInSection
但是,我们可以看一个简单的例子......
您的 ProfileHeaderView
稍作修改
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),
])
}
}
一个简单的单标签单元格类
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")
// 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
}
}
运行时看起来像这样:
评论
0赞
Philipp
7/4/2023
这绝对是我需要的!感谢您的帮助!
上一个:以编程方式对单元格内容进行约束
评论
addSubview(userImage)
contentView.addSubview(userImage)
viewForHeaderInSection
tableVIew.tableHeaderView