我有一个动态变化的tableview单元格,它们彼此之间具有两个标签。顶部标签始终带有一些文本,但底部标签有时没有。加载表格视图时,底部标签无文本的单元格完全消失,仅显示其标题。如果我向下滚动并返回上一步,这些以前丢失的单元格将正确显示。
我认为这与我的约束有关,但是当我尝试调整约束时,我只会使事情变得更糟。
我如何进行限制,以使单元格始终在加载屏幕时首先出现,包括底部标签没有文本时?
这是表格视图单元格的代码:
class TransactionHistoryTableViewCell: UITableViewCell {
private var itemView = UIView()
private var itemNameLabel = UILabel()
private var sizeLabel = UILabel()
func setup(_ lineItem: MenuItem) {
contentView.backgroundColor = .white
configureItemNameLabel(lineItem)
configureSizeLabel(lineItem)
configureTransactionView(lineItem)
}
private func configureTransactionView(_ lineItem: MenuItem) {
itemView.clipsToBounds = true
itemView.layer.cornerRadius = 5
itemView.layer.borderColor = UIColor.lightGray.cgColor
itemView.layer.borderWidth = 0.5
itemView.backgroundColor = .white
contentView.addSubview(itemView)
itemView.translatesAutoresizingMaskIntoConstraints = false
itemView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
itemView.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.8).isActive = true
itemView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 4).isActive = true
itemView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -4).isActive = true
}
private func returnText(_ menuItem: MenuItem) -> String {
var text = ""
guard let modifiers = menuItem.modifiers else { print("modifiers are nil"); return "" }
if modifiers.isEmpty && menuItem.quantity == 1 {
text = ""
} else if !modifiers.isEmpty && menuItem.quantity == 1 {
text = generateModifierText(menuItem)
} else if !modifiers.isEmpty && menuItem.quantity > 1 {
let theText = generateModifierText(menuItem)
text = "\(theText); Quantity: \(menuItem.quantity)"
} else {
text = "Quantity: \(menuItem.quantity)"
}
return text
}
private func configureItemNameLabel(_ lineItem: MenuItem) {
itemNameLabel.text = lineItem.name
let fontSize = getSize(large: 14, medium: 13.5, small: 12)
itemNameLabel.font = UIFont(name: AppFont.secondary.name, size: fontSize)
itemNameLabel.numberOfLines = 0
itemView.addSubview(itemNameLabel)
itemNameLabel.translatesAutoresizingMaskIntoConstraints = false
itemNameLabel.leftAnchor.constraint(equalTo: itemView.leftAnchor, constant: 15).isActive = true
let verticalOffset = getSize(large: 10, medium: 7, small: 5)
itemNameLabel.topAnchor.constraint(equalTo: itemView.topAnchor, constant: verticalOffset).isActive = true
itemNameLabel.widthAnchor.constraint(equalToConstant: 195).isActive = true
itemView.addSubview(sizeLabel)
itemNameLabel.bottomAnchor.constraint(equalTo: sizeLabel.topAnchor, constant: -3).isActive = true
}
func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height
}
override func prepareForReuse() {
super.prepareForReuse()
itemNameLabel.text = ""
sizeLabel.text = ""
}
private func configureSizeLabel(_ menuItem: MenuItem) {
guard let modifiers = menuItem.modifiers else { print("modifiers are nil"); return }
if modifiers.isEmpty && menuItem.quantity == 1 {
sizeLabel.text = ""
} else if !modifiers.isEmpty && menuItem.quantity == 1 {
sizeLabel.text = generateModifierText(menuItem)
} else if !modifiers.isEmpty && menuItem.quantity > 1 {
let text = generateModifierText(menuItem)
if text != "" {
sizeLabel.text = "\(text); Quantity: \(menuItem.quantity)"
} else {
sizeLabel.text = "Quantity: \(menuItem.quantity)"
}
} else {
sizeLabel.text = "Quantity: \(menuItem.quantity)"
}
sizeLabel.backgroundColor = .white
sizeLabel.textColor = .gray
sizeLabel.numberOfLines = 0
let fontSize = getSize(large: 11, medium: 10.5, small: 9.5)
sizeLabel.font = UIFont(name: AppFont.secondary.name, size: fontSize)
sizeLabel.translatesAutoresizingMaskIntoConstraints = false
sizeLabel.topAnchor.constraint(equalTo: itemNameLabel.bottomAnchor, constant: 3).isActive = true
sizeLabel.leftAnchor.constraint(equalTo: itemNameLabel.leftAnchor).isActive = true
sizeLabel.widthAnchor.constraint(equalToConstant: 200).isActive = true
sizeLabel.bottomAnchor.constraint(equalTo: itemView.bottomAnchor, constant: -3).isActive = true
}
private func generateModifierText(_ menuItem: MenuItem) -> String {
var text = ""
guard let modifiers = menuItem.modifiers else { return "" }
var optionNames = [String]()
for modifier in modifiers {
if !modifier.options.isEmpty {
for options in modifier.options{
if options.name.uppercased() != "NONE" {
optionNames.append(options.name)
}
}
}
}
for x in 0..<optionNames.count {
if x != optionNames.count - 1 {
text += "\(optionNames[x]), "
} else {
text += "\(optionNames[x])"
}
}
return text
}
private func generateSizeLabelFontSize() -> CGFloat {
return getSize(large: 11, medium: 10, small: 9.5)
}
}
来自视图控制器的代码:
override func viewDidLoad() {
super.viewDidLoad()
configureNavBar()
configureTableView()
getOrders()
NotificationCenter.default.addObserver(self, selector: #selector(popToRootVC), name: NSNotification.Name(rawValue: "PopToRootVCFromSettingsVC"), object: nil)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "transactionHistoryCell", for: indexPath) as? TransactionHistoryTableViewCell else { getOrders(); return UITableViewCell() }
if let lineItem = orders[indexPath.section].lineItems?[indexPath.row] {
cell.setup(lineItem)
}
return cell
}
private func getOrders() {
let service = TransactionService()
service.getTransactionData(completion: { (orders) in
guard let orders = orders else { self.handleNoOrderHistory(); return }
let filteredOrders = orders.filter{ $0.status == "NEW" || $0.status == "IN_PROGRESS" || $0.status == "READY" || $0.status == "COMPLETE" }
if filteredOrders.isEmpty {
DispatchQueue.main.async {
self.handleNoOrderHistory()
return
}
} else {
DispatchQueue.main.async {
self.orders = filteredOrders.sorted{ $0.date > $1.date }
self.noOrdersView.isHidden = true
self.tableView.reloadData()
}
}
})
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 85
}
编译器发出这样的警告:
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.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
NSAutoresizingMaskLayoutConstraint:0x600001e972a0 h=--& v=--& UILabel:0x7f9a0050b780.midY == 0 (active),
NSAutoresizingMaskLayoutConstraint:0x600001e97610 h=--& v=--& UILabel:0x7f9a0050b780.height == 0 (active),
NSLayoutConstraint:0x600001e8bca0 V:|-(5)-[UILabel:0x7f9a0050b490'5\" Focaccia Everything'] (active, names: '|':UIView:0x7f9a0050b2b0 ),
NSLayoutConstraint:0x600001d63660 UILabel:0x7f9a0050b490'5\" Focaccia Everything'.bottom == UILabel:0x7f9a0050b780.top - 3 (active)
)
Will attempt to recover by breaking constraint
NSLayoutConstraint:0x600001d63660 UILabel:0x7f9a0050b490'5" Focaccia Everything'.bottom == UILabel:0x7f9a0050b780.top - 3 (active)
答案 0 :(得分:0)
问题在于,在之前添加任何子视图并应用约束,您需要将其.purple
设置为translatesAutoresizing...
。
因此,您呼叫false
并添加configureItemNameLabel
,在呼叫sizeLabel
之前 并修复其configureSizeLabel
。
答案 1 :(得分:0)
当您使用动态高度来建立表格视图时,并在这样的控制台中收到约束警告,通常是因为应用程序无法从给定的约束中获取当前高度。
对单元格使用动态高度最重要的是,需要从上到下给出正确的垂直约束,对于收集单元格,则需要给出正确的水平和垂直约束。
例如,我需要在一个单元格中显示三个标签。像这样
--------------------------
LABLE_1
LABEL_2
LABEL_3
--------------------------
我们需要添加
还有一点是某些UI组件可以自行调整高度,例如UIButton,UILabel等。因此,如果您只想显示内容,则不需要为某种组件提供高度限制。如果需要,可以将约束的优先级编辑为999,它始终可以解决警告。
我了解的原因是,如果您要使用动态高度,则组件需要自行决定高度,因此我们给tableview估计了RowHeight,并提供了一些关于组件之间关系的约束。如果确实需要给定高度限制,请使用限制的优先级。
最后一点是,如果组件无法自行调整高度,例如UIView,则可以给定高度限制并更改高度的优先级,或者与其他组件一起提供顶部,底部约束,其中包括的某些组件可以自行调整高度,而某些组件可以自行调整高度组件的视图具有正确的垂直约束
答案 2 :(得分:0)
我不得不将heightForRowAt从automaticDimensions更改为:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
//return UITableView.automaticDimension
guard let lineItem = self.orders[indexPath.section].lineItems?[indexPath.row] else { return 0 }
let fontSize = getSize(large: 14, medium: 13.5, small: 12)
guard let topFont = UIFont(name: AppFont.secondary.name, size: fontSize) else { return 0 }
let heightForTopLabel = heightForView(text: lineItem.name, font: topFont, width: 195)
let text = returnText(lineItem)
let bottomFontSize = getSize(large: 11, medium: 10.5, small: 9.5)
guard let font = UIFont(name: AppFont.secondary.name, size: bottomFontSize) else { return 0 }
let heightForBottomLabel = heightForView(text: text, font: font, width: 200)
let padding = getSize(large: 27.5, medium: 14, small: 21)
let height = heightForTopLabel + heightForBottomLabel + padding
return height
}
func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat{
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height
}
private func returnText(_ menuItem: MenuItem) -> String {
var text = ""
guard let modifiers = menuItem.modifiers else { print("modifiers are nil"); return "" }
if modifiers.isEmpty && menuItem.quantity == 1 {
text = ""
} else if !modifiers.isEmpty && menuItem.quantity == 1 {
text = generateModifierText(menuItem)
} else if !modifiers.isEmpty && menuItem.quantity > 1 {
let theText = generateModifierText(menuItem)
text = "\(theText); Quantity: \(menuItem.quantity)"
} else {
text = "Quantity: \(menuItem.quantity)"
}
return text
}
private func generateModifierText(_ menuItem: MenuItem) -> String {
var text = ""
guard let modifiers = menuItem.modifiers else { return "" }
var optionNames = [String]()
for modifier in modifiers {
if !modifier.options.isEmpty {
for options in modifier.options{
if options.name.uppercased() != "NONE" {
optionNames.append(options.name)
}
}
}
}
for x in 0..<optionNames.count {
if x != optionNames.count - 1 {
text += "\(optionNames[x]), "
} else {
text += "\(optionNames[x])"
}
}
return text
}