单元格最初没有出现,但显示是否向下滚动并返回

时间:2019-05-09 21:31:28

标签: swift uitableview

我有一个动态变化的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)

3 个答案:

答案 0 :(得分:0)

问题在于,在之前添加任何子视图并应用约束,您需要将其.purple设置为translatesAutoresizing...

因此,您呼叫false并添加configureItemNameLabel,在呼叫sizeLabel之前 并修复其configureSizeLabel

答案 1 :(得分:0)

当您使用动态高度来建立表格视图时,并在这样的控制台中收到约束警告,通常是因为应用程序无法从给定的约束中获取当前高度。

对单元格使用动态高度最重要的是,需要从上到下给出正确的垂直约束,对于收集单元格,则需要给出正确的水平和垂直约束。

例如,我需要在一个单元格中显示三个标签。像这样

--------------------------
    LABLE_1
    LABEL_2
    LABEL_3   
--------------------------

我们需要添加

  • LABEL_1,位于视图的顶部
  • LABEL_2的顶部,LABEL_1的底部
  • LABEL_3的顶部,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
}