ios - UITableViewCell contentView 具有 autoResizingMask 约束“UIView-Encapsulated-Layout-Height”与自动调整大小的自动布局冲突
问题描述
我正在尝试创建一个表格视图,其单元格在选择单元格时展开并保持展开直到再次被选中。
我试图让单元格的高度由它们的内容决定。我已经知道设置 tableView 的 rowHeight 和 estimagedRowHeight 以使自我调整大小正常工作,所以这不是问题。
ViewController.swift:
import UIKit
class ViewController: UIViewController {
lazy var tableView: UITableView = {
let tv = UITableView(frame: .zero, style: .plain)
tv.register(ExpandingCell.self, forCellReuseIdentifier: ExpandingCell.reuseIdentifier)
tv.estimatedRowHeight = 85.0
tv.rowHeight = UITableViewAutomaticDimension
return tv
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: self.view.topAnchor),
tableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
tableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)])
tableView.dataSource = self
tableView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 50
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: ExpandingCell.reuseIdentifier, for: indexPath) as! ExpandingCell
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 50.0
}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
}
}
ExpandingCell.swift
import UIKit
class ExpandingCell: UITableViewCell {
static let reuseIdentifier = "dafasdfadfagr"
let minimumDisplayedView = UIView()
let extraContentView = UIView()
var expandingConstraint: NSLayoutConstraint?
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
self.setupViews()
self.contentView.clipsToBounds = true
}
private func setupViews() {
self.addSubviews()
self.customizeSubviews()
self.constrainSubviews()
}
private func addSubviews() {
self.contentView.addSubview(minimumDisplayedView)
self.contentView.addSubview(extraContentView)
}
private func customizeSubviews() {
self.customizeMinimumDisplayedView()
self.customizeExtraContentView()
}
private func constrainSubviews() {
self.constrainMinimumDisplayedView()
self.constrainExtraContentView()
}
// MARK: - MinimumDisplayView
private func customizeMinimumDisplayedView() {
minimumDisplayedView.backgroundColor = .blue
}
private func constrainMinimumDisplayedView() {
minimumDisplayedView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
minimumDisplayedView.heightAnchor.constraint(equalToConstant: 50),
minimumDisplayedView.topAnchor.constraint(equalTo: self.contentView.topAnchor),
minimumDisplayedView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor),
minimumDisplayedView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor)
])
expandingConstraint = minimumDisplayedView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor)
expandingConstraint?.isActive = true
}
// MARK: - ExtraContentView
private func customizeExtraContentView() {
extraContentView.backgroundColor = .red
}
private func constrainExtraContentView() {
extraContentView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
extraContentView.heightAnchor.constraint(equalToConstant: 200),
extraContentView.topAnchor.constraint(equalTo: minimumDisplayedView.bottomAnchor),
extraContentView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor),
extraContentView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor)
])
}
// MARK: - Animate Expansion
// override func setSelected(_ selected: Bool, animated: Bool) {
// super.setSelected(selected, animated: animated)
// print("selected: \(selected)")
// resize(selected)
// }
private func resize(_ expand: Bool) {
expandingConstraint?.isActive = false
if expand {
expandingConstraint = extraContentView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor)
expandingConstraint?.isActive = true
} else {
expandingConstraint = minimumDisplayedView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor)
expandingConstraint?.isActive = true
}
UIView.animate(withDuration: 0.3) {
self.layoutIfNeeded()
}
}
}
我有 2 个视图被添加到 contentView 并在初始化单元格时将 contentView 的边缘固定到第一个视图。第一个视图是蓝色且短,而第二个视图是红色且高。
我希望 tableView 最初看起来都是蓝色的,但它看起来像这样:
我怀疑它与视图生命周期中单元格的布局方式有关,所以我也遇到了这个答案:reload tableview after first load as a workaround
当我运行代码时,我得到了这些约束错误
2018-05-05 18:00:15.108634-0400 TestExpandingCells[1022:13932317] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x6000000961c0 UIView:0x7fe583700df0.height == 50 (active)>",
"<NSLayoutConstraint:0x600000096580 V:|-(0)-[UIView:0x7fe583700df0] (active, names: '|':UITableViewCellContentView:0x7fe583704850 )>",
"<NSLayoutConstraint:0x600000096760 UIView:0x7fe583700df0.bottom == UITableViewCellContentView:0x7fe583704850.bottom (active)>",
"<NSLayoutConstraint:0x600000096bc0 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7fe583704850.height == 50 (active)>"
)
该列表上的最后一个约束“UIView-Encapsulated-Layout-Height”似乎来自 UIKit 为布局单元格创建的一些 autoresizingmask-to-constraint 东西。
所以我的问题是,我怎样才能删除这个约束以允许 AutoLayout 完全处理我的单元格的制作,而无需解决方法。我还希望将其全部包含在 ExpansionCell 类中,而不是将其包含在 tableview 的委托方法中。
如果您还找到了使用 AutoLayout 触发单元格扩展的方法,则可以加分。
解决方案
首先要摆脱约束的冲突,将连接到 contentView 的任何视图的底部约束的优先级设置为 999,其次触发扩展钩子高度约束并更改它,还在您的模型中声明任何 bool 值数组以确定是否为滚动后单元格是否展开以恢复单元格状态和
在cellForRow
cell.viewHeighcon.constant = isExpanded ? 200 : 50
推荐阅读
- r - R从序列中选择特定长度
- r - 单一主题数据的逻辑回归?
- c# - .NET Core 3.1 Sdk.Worker 与 Sdk.Web Razor 模板?(Sdk.Web 做了什么来允许 Razor 模板?)
- python - Selenium 帮助切换到 iframe 然后点击链接
- mysql - sql编码中的日期间隔
- reactjs - TypeScript 和 JSX 不理解我想设置特定道具时的情况
- firebase - 将 vuexfire 与模块一起使用时如何处理突变?
- networking - 如果我正在体验完美的互联网连接,为什么“ping google.com”会返回 100% 的数据包丢失?
- flutter - 无法在 YoutubeVideoPlayer Flutter 上使用全屏(发生在 android 本机设备上)
- javascript - 如何使用 CSS 或 JavaScript 调整打印机的颜色配置文件/选项