gpt4 book ai didi

ios - 如何让 tableFooterView 始终位于 UITableView 的底部

转载 作者:搜寻专家 更新时间:2023-11-01 06:52:32 25 4
gpt4 key购买 nike

我有一个包含可变数量部分的 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,所以我还没有找到解决方案。类似的情况是在最后一节用 sectionFooter 替换 tableFooterView,但我不能这样做,因为我已经有了 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)

}

}

}

最佳答案

一种方法是:

  • 使用扩展来定义“自适应非滚动”表格 View
  • 在“容器” View 中为“页脚” View 嵌入 TableView 和普通UIView
  • 将容器 View 嵌入到 ScrollView 中,高度与 ScrollView 相同,但优先级较低
  • 将页脚 View 限制在容器 View 的底部,并将 >= 限制在 TableView 的底部

所以,tableView的“auto-height”+footer view的高度决定了container view的高度,进而决定了scroll view的.contentSize。页脚 View 将“粘贴”到容器 View 的底部。当 ScrollView 有足够的内容时,它将“下推”页脚 View 。

例子:

enter image description here

enter image description here

这是创建它的代码。一切都是通过代码完成的……不需要 IBOutlets,所以只需创建一个新的 View Controller 并将其类分配给 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"
}

}

关于ios - 如何让 tableFooterView 始终位于 UITableView 的底部,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56132642/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com