【发布时间】:2018-09-20 14:45:00
【问题描述】:
我正在做一个项目,需要在 UITableViewCell 中添加一个 UICollectionView(水平方向)。 UITableViewCell 高度使用 UITableViewAutoDimension 并且每个 UITableViewCell 我都有一个 UIView(带有设计要求的边框)作为基本视图,并且在 UIView 中,我添加了一个 UIStackView 作为 containerView 以按比例填充 UICollectionView 与其他两个按钮垂直。然后对于 UICollectionViewCell,我添加了一个 UIStackView 来填充五个标签。
现在,如果 UITableViewDelegate 分配了固定高度,则自动布局可以工作。但它不适用于 UITableViewAutoDimension。我的猜测是 UICollectionView 框架在 UITableView 渲染它的单元格时还没有准备好。所以 UITableViewAutoDimension 使用 UICollectionView 的默认高度计算 UITableViewCell 高度,该高度为零。
所以,当然,在我在互联网上提出问题之前,我一直在搜索,但没有适合我的解决方案。这是我尝试过的一些链接。
UICollectionView inside a UITableViewCell — dynamic height?
Making UITableView with embedded UICollectionView using UITableViewAutomaticDimension
UICollectionView inside UITableViewCell does NOT dynamically size correctly
有人有同样的问题吗?如果上面的链接确实有效,请随时让我知道,以防我做错了。谢谢你
--- 2018 年 9 月 23 日更新:
-
布局可视化: 有一些 UI 修改,但这并没有改变我面临的问题。希望图片能帮到你。
- 代码: 我当前的代码实际上没有使用 UITableViewCell 中的 UIStackView 和 UITableView heightForRowAtIndex 我返回一个固定高度为 250.0。但是,如果我返回 UITableViewAutoDimension,UITableView 将无法正确配置单元格高度,正如我在问题中提到的那样。
1. UITableViewController
class ViewController: UIViewController {
private let tableView: UITableView = {
let tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(ViewControllerTableViewCell.self, forCellReuseIdentifier: ViewControllerTableViewCell.identifier)
return tableView
}()
private lazy var viewModel: ViewControllerViewModel = {
return ViewControllerViewModel(models: [
Model(title: "TITLE", description: "SUBTITLE", currency: "USD", amount: 100, summary: "1% up"),
Model(title: "TITLE", description: "SUBTITLE", currency: "USD", amount: 200, summary: "2% up"),
Model(title: "TITLE", description: "SUBTITLE", currency: "USD", amount: 300, summary: "3% up"),
])
}()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
view.addSubview(tableView)
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return viewModel.numberOfSections
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.numberOfRowsInSection
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: ViewControllerTableViewCell.identifier, for: indexPath) as! ViewControllerTableViewCell
cell.configure(viewModel: viewModel.cellViewModel)
return cell
}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 250.0
}
}
2。 UITableViewCell
class ViewControllerTableViewCell: UITableViewCell {
static let identifier = "ViewControllerTableViewCell"
private var viewModel: ViewControllerTableViewCellViewModel!
private let borderView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.borderColor = UIColor.black.cgColor
view.layer.borderWidth = 1
return view
}()
private let stackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.distribution = .fillProportionally
return stackView
}()
private let seperator: UIView = {
let seperator = UIView()
seperator.translatesAutoresizingMaskIntoConstraints = false
seperator.backgroundColor = .lightGray
return seperator
}()
private let actionButton: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Show business insight", for: .normal)
button.setTitleColor(.black, for: .normal)
return button
}()
private let pageControl: UIPageControl = {
let pageControl = UIPageControl()
pageControl.translatesAutoresizingMaskIntoConstraints = false
pageControl.pageIndicatorTintColor = .lightGray
pageControl.currentPageIndicatorTintColor = .black
pageControl.hidesForSinglePage = true
return pageControl
}()
private let collectionView: UICollectionView = {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: 200, height: 200), collectionViewLayout: layout)
collectionView.isPagingEnabled = true
collectionView.backgroundColor = .white
collectionView.showsHorizontalScrollIndicator = false
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.register(ViewControllerCollectionViewCell.self, forCellWithReuseIdentifier: ViewControllerCollectionViewCell.identifier)
return collectionView
}()
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setUpConstraints()
setUpUserInterface()
}
func configure(viewModel: ViewControllerTableViewCellViewModel) {
self.viewModel = viewModel
pageControl.numberOfPages = viewModel.items.count
collectionView.reloadData()
}
@objc func pageControlValueChanged() {
let indexPath = IndexPath(item: pageControl.currentPage, section: 0)
collectionView.scrollToItem(at: indexPath, at: .left, animated: true)
}
private func setUpConstraints() {
contentView.addSubview(borderView)
borderView.addSubview(actionButton)
borderView.addSubview(seperator)
borderView.addSubview(pageControl)
borderView.addSubview(collectionView)
NSLayoutConstraint.activate([
borderView.topAnchor.constraint(equalTo: topAnchor, constant: 10),
borderView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20),
borderView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20),
borderView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10),
])
NSLayoutConstraint.activate([
actionButton.heightAnchor.constraint(greaterThanOrEqualToConstant: 44),
actionButton.leadingAnchor.constraint(equalTo: borderView.leadingAnchor),
actionButton.trailingAnchor.constraint(equalTo: borderView.trailingAnchor),
actionButton.bottomAnchor.constraint(equalTo: borderView.bottomAnchor)
])
NSLayoutConstraint.activate([
seperator.heightAnchor.constraint(equalToConstant: 1),
seperator.leadingAnchor.constraint(equalTo: borderView.leadingAnchor),
seperator.trailingAnchor.constraint(equalTo: borderView.trailingAnchor),
seperator.bottomAnchor.constraint(equalTo: actionButton.topAnchor)
])
NSLayoutConstraint.activate([
pageControl.heightAnchor.constraint(greaterThanOrEqualToConstant: 40),
pageControl.leadingAnchor.constraint(equalTo: borderView.leadingAnchor),
pageControl.trailingAnchor.constraint(equalTo: borderView.trailingAnchor),
pageControl.bottomAnchor.constraint(equalTo: seperator.topAnchor)
])
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: borderView.topAnchor),
collectionView.leadingAnchor.constraint(equalTo: borderView.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: borderView.trailingAnchor),
collectionView.bottomAnchor.constraint(equalTo: pageControl.topAnchor)
])
}
private func setUpUserInterface() {
selectionStyle = .none
collectionView.delegate = self
collectionView.dataSource = self
pageControl.addTarget(self, action: #selector(pageControlValueChanged), for: .valueChanged)
}
}
extension ViewControllerTableViewCell: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return viewModel!.numberOfSections
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return viewModel!.numberOfRowsInSection
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ViewControllerCollectionViewCell.identifier, for: indexPath) as! ViewControllerCollectionViewCell
let collectionCellViewModel = viewModel!.collectionCellViewModel(at: indexPath)
cell.configure(viewModel: collectionCellViewModel)
return cell
}
}
extension ViewControllerTableViewCell: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
debugPrint("did select \(indexPath.row)")
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
pageControl.currentPage = indexPath.row
}
}
extension ViewControllerTableViewCell: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width - 40.0, height: collectionView.frame.height)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 20.0, bottom: 0, right: 20.0)
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 40.0
}
}
3. UICollectionViewCell
class ViewControllerCollectionViewCell: UICollectionViewCell {
override class var requiresConstraintBasedLayout: Bool {
return true
}
static let identifier = "ViewControllerCollectionViewCell"
private let stackView: UIStackView = {
let stackView = UIStackView()
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.distribution = .fillEqually
return stackView
}()
private let titleLabel: UILabel = {
let titleLabel = UILabel()
titleLabel.textColor = .black
titleLabel.font = UIFont.systemFont(ofSize: 20, weight: .bold)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
return titleLabel
}()
private let descriptionLabel: UILabel = {
let descriptionLabel = UILabel()
descriptionLabel.textAlignment = .right
descriptionLabel.textColor = .black
descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
return descriptionLabel
}()
private let amountLabel: UILabel = {
let amountLabel = UILabel()
amountLabel.textColor = .black
amountLabel.textAlignment = .right
amountLabel.translatesAutoresizingMaskIntoConstraints = false
return amountLabel
}()
private let summaryLabel: UILabel = {
let summaryLabel = UILabel()
summaryLabel.textColor = .black
summaryLabel.textAlignment = .right
summaryLabel.translatesAutoresizingMaskIntoConstraints = false
return summaryLabel
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(stackView)
stackView.addArrangedSubview(titleLabel)
stackView.addArrangedSubview(descriptionLabel)
stackView.addArrangedSubview(amountLabel)
stackView.addArrangedSubview(summaryLabel)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor)
])
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configure(viewModel: CollectionCellViewModel) {
titleLabel.text = viewModel.title
descriptionLabel.text = viewModel.description
amountLabel.text = viewModel.amount.localizedCurrencyString(with: viewModel.currency)
summaryLabel.text = viewModel.summary
}
}
【问题讨论】:
标签: uitableview uicollectionview uistackview uitableviewautomaticdimension