我有一段可变数量的UITableView
。每个节都有可变数量的单元格,每个节都有页眉和页脚。我的UITableView
也有一个tableFooterView
,我想一直将其保留在屏幕底部,除非表格太大而无法容纳在屏幕上,那么tableFooterView
应该显示在最后一节的下方。我要完成的任务在此处说明:
Example of what I want, scenario 1
Example of what I want, scenario 2
但是,当前tableFooterView
始终位于最后一部分的正下方,因此,例如,当只有两个部分时,它看起来像这样:
Example of what I currently have
我正在寻找一种在任何可能的情况下始终将其保持在底部的方法。我一直在寻找,并且因为Apple不支持tableFooterView
的AutoLayout,所以我还没有找到解决方案。在上一节中,类似的情况用tableFooterView
替换了sectionFooter
,但是由于已经有了sectionFooters
,所以我不能这样做。
是否有人可以帮助我或为我指明正确的方向?需要考虑的几件事:
tableFooterView
; UITableView
中,并将行添加到这些部分中,因此tableFooterView应该随后更新其位置我现在如何设置
tableFooterView
:class CustomView: UITableViewDelegate, UITableViewDataSource {
var myTableFooter: UIView = {
let myTableFooter = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
myTableFooter.backgroundColor = .red
myTableFooter.isUserInteractionEnabled = true
return myTableFooter
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
MyTableView.tableFooterView = myTableFooter
}
}
编辑:根据建议尝试了
scrollViewDidScroll
方法,但是没有用:func scrollViewDidScroll(_ scrollView: UIScrollView) {
if(scrollView == myTableView) {
let neededHeight = myTableView.frame.height - 50 - view.safeAreaInsets.bottom
let currentHeight = myTableView.contentSize.height - 50
let heightDifference = neededHeight - currentHeight
if(heightDifference > 0) {
myTableView.tableFooterView?.transform = CGAffineTransform(translationX: 0, y: heightDifference)
}
}
}
最佳答案
一种方法是:
UIView
嵌入“容器”视图>=
限制在表视图的底部因此,tableView的“自动高度” +页脚视图的高度确定了容器视图的高度,而容器视图的高度决定了滚动视图的
.contentSize
。页脚视图将“粘贴”到容器视图的底部。当滚动视图具有足够的内容时,它将“下推”页脚视图。例:
这是创建代码的代码。一切都通过代码完成...不需要IBOutlets,因此只需创建一个新的视图控制器并将其类分配给
PennyWiseViewController
://
// PennyWiseViewController.swift
//
// Created by Don Mag on 5/14/19.
//
import UIKit
final class ContentSizedTableView: UITableView {
override var contentSize:CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
layoutIfNeeded()
return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height)
}
}
class MyOneLabelCell: UITableViewCell {
// very simple one-label tableView cell
let theLabel: UILabel = {
let v = UILabel()
v.translatesAutoresizingMaskIntoConstraints = false
v.numberOfLines = 0
return v
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(theLabel)
NSLayoutConstraint.activate([
theLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8.0),
theLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8.0),
theLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0),
theLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8.0),
])
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class PennyWiseViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let theContainerView: UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
let theScrollView: UIScrollView = {
let v = UIScrollView()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
let theTableView: ContentSizedTableView = {
let v = ContentSizedTableView()
v.translatesAutoresizingMaskIntoConstraints = false
v.isScrollEnabled = false
return v
}()
let theFooterView: UILabel = {
let v = UILabel()
v.translatesAutoresizingMaskIntoConstraints = false
v.backgroundColor = .red
v.textColor = .white
v.text = "The Footer View"
v.textAlignment = .center
return v
}()
// start with 3 sections
// selecting the row in the first section allows adding sections
// selecting the row in the second section allows deleting sections
var numSections = 3
let reuseID = "MyOneLabelCell"
override func viewDidLoad() {
super.viewDidLoad()
theTableView.dataSource = self
theTableView.delegate = self
theTableView.register(MyOneLabelCell.self, forCellReuseIdentifier: reuseID)
// add the views
view.addSubview(theScrollView)
theScrollView.addSubview(theContainerView)
theContainerView.addSubview(theTableView)
theContainerView.addSubview(theFooterView)
// this will allow the container height to be at least the height of the scroll view
// when enough content is added to the container, it will grow
let containerHeightConstraint = theContainerView.heightAnchor.constraint(equalTo: theScrollView.heightAnchor, multiplier: 1.0)
containerHeightConstraint.priority = .defaultLow
NSLayoutConstraint.activate([
// constrain scrollView to all 4 sides (safe-area)
theScrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
theScrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
theScrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
theScrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
// constrain containerView to all 4 sides of scrollView
theContainerView.topAnchor.constraint(equalTo: theScrollView.topAnchor),
theContainerView.bottomAnchor.constraint(equalTo: theScrollView.bottomAnchor),
theContainerView.leadingAnchor.constraint(equalTo: theScrollView.leadingAnchor),
theContainerView.trailingAnchor.constraint(equalTo: theScrollView.trailingAnchor),
theContainerView.widthAnchor.constraint(equalTo: theScrollView.widthAnchor),
// constrain tableView to top/leading/trailing of constainerView
theTableView.topAnchor.constraint(equalTo: theContainerView.topAnchor),
theTableView.leadingAnchor.constraint(equalTo: theContainerView.leadingAnchor),
theTableView.trailingAnchor.constraint(equalTo: theContainerView.trailingAnchor),
// constrain footerView >= 20 from bottom of tableView
theFooterView.topAnchor.constraint(greaterThanOrEqualTo: theTableView.bottomAnchor, constant: 20.0),
theFooterView.leadingAnchor.constraint(equalTo: theContainerView.leadingAnchor, constant: 0.0),
theFooterView.trailingAnchor.constraint(equalTo: theContainerView.trailingAnchor, constant: 0.0),
theFooterView.bottomAnchor.constraint(equalTo: theContainerView.bottomAnchor, constant: 0.0),
theFooterView.heightAnchor.constraint(equalToConstant: 150.0),
containerHeightConstraint,
])
}
// MARK: - Table view data source
func numberOfSections(in tableView: UITableView) -> Int {
return numSections
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return section < 2 ? 1 : 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: reuseID, for: indexPath) as! MyOneLabelCell
switch indexPath.section {
case 0:
cell.theLabel.text = "Add a section"
case 1:
cell.theLabel.text = "Delete a section"
default:
cell.theLabel.text = "\(indexPath)"
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
switch indexPath.section {
case 0:
numSections += 1
tableView.reloadData()
case 1:
if numSections > 2 {
numSections -= 1
tableView.reloadData()
}
default:
print("\(indexPath) was selected")
}
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "Section \(section) Header"
}
func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return "Section \(section) Footer"
}
}