I've made UI for cell in cell class below:
final class OptionTVCell: UITableViewCell {
fileprivate static let id = String(describing: OptionTVCell.self)
private var defaultTintColor: UIColor {
let color = AppConfiguration.sharedAppConfiguration.appTextColor
return Utility.hexStringToUIColor(hex: color ?? "ffffff")
}
// MARK: - Subviews
lazy private(set) var optionImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.heightAnchor.constraint(equalToConstant: 24).isActive = true
imageView.setContentHuggingPriority(.defaultHigh, for: .horizontal)
imageView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
let widthConstraint = imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor)
widthConstraint.priority = UILayoutPriority(998)
widthConstraint.isActive = true
imageView.contentMode = .scaleAspectFit
imageView.tintColor = defaultTintColor
return imageView
}()
lazy private(set) var optionNameLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.setContentHuggingPriority(.defaultLow, for: .horizontal)
label.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
label.textColor = defaultTintColor
label.numberOfLines = 0
let fontSize: CGFloat = Constants.shared.IPHONE ? 14 : 20
label.font = UIFont(name: Utility.getFontName(), size: fontSize)
return label
}()
lazy private(set) var separatorLineView: UIView = {
let separator = UIView()
separator.translatesAutoresizingMaskIntoConstraints = false
let heightConstraint = separator.heightAnchor.constraint(equalToConstant: 1)
heightConstraint.priority = UILayoutPriority(999)
heightConstraint.isActive = true
separator.backgroundColor = defaultTintColor.withAlphaComponent(0.5)
return separator
}()
lazy private(set) var separatorContainerStackView: UIStackView = {
let verticalStackView = UIStackView()
verticalStackView.translatesAutoresizingMaskIntoConstraints = false
verticalStackView.axis = .vertical
verticalStackView.spacing = 10
verticalStackView.distribution = .fillProportionally
verticalStackView.alignment = .fill
return verticalStackView
}()
lazy private(set) var iconContainerStackView: UIStackView = {
let horizontalStackView = UIStackView()
horizontalStackView.translatesAutoresizingMaskIntoConstraints = false
horizontalStackView.axis = .horizontal
horizontalStackView.spacing = 16
horizontalStackView.distribution = .fill
horizontalStackView.alignment = .center
return horizontalStackView
}()
// MARK: - Init
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupView()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Life Cycle
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
super.setHighlighted(highlighted, animated: animated)
let color = highlighted
? Utility.hexStringToUIColor(hex: AppConfiguration.sharedAppConfiguration.primaryHoverColor ?? "ffffff")
: defaultTintColor
optionImageView.tintColor = color
optionNameLabel.textColor = color
}
// MARK: - Setup
private func setupView() {
selectionStyle = .none
backgroundColor = .clear
contentView.backgroundColor = .clear
setupIconStackView()
setupSeparatorStackView()
}
private func setupSeparatorStackView() {
contentView.addSubview(separatorContainerStackView)
NSLayoutConstraint.activate([
separatorContainerStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
separatorContainerStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),
separatorContainerStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8),
separatorContainerStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16)
])
separatorContainerStackView.addArrangedSubview(iconContainerStackView)
separatorContainerStackView.addArrangedSubview(separatorLineView)
}
private func setupIconStackView() {
iconContainerStackView.addArrangedSubview(optionImageView)
iconContainerStackView.addArrangedSubview(optionNameLabel)
let labelWidth = optionNameLabel.widthAnchor.constraint(greaterThanOrEqualTo: iconContainerStackView.widthAnchor, constant: -40)
labelWidth.isActive = true
}
// MARK: - Configure
}
Below is the tableView implementation for cell:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return CGFloat(cellHeight)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard
let cell = tableView.dequeueReusableCell(withIdentifier: OptionTVCell.id) as? OptionTVCell,
indexPath.row <= optionsArray.count-1,
let navItem = optionsArray[indexPath.row] as? OptionItem
else {
return UITableViewCell()
}
cell.separatorLineView.isHidden = navItem.hasSeparator == true ? false : true
if let imageName = navItem.pageIcon, !imageName.isEmpty {
if let optionImage = UIImage(named: imageName)?.withRenderingMode(.alwaysTemplate) {
cell.optionImageView.image = optionImage
cell.optionImageView.isHidden = false
} else {
let listImageStringURL = imageName.appending("?w=\(Utility.sharedUtility.getImageSizeAsPerScreenResolution(size: cell.optionImageView.frame.size.width)))&h=\(Utility.sharedUtility.getImageSizeAsPerScreenResolution(size: cell.optionImageView.frame.size.height))")
if let imageURL = URL(string: listImageStringURL) {
cell.optionImageView.af.setImage(
withURL: imageURL,
placeholderImage: nil,
filter: nil,
imageTransition: .crossDissolve(0.2)
)
}
}
} else {
cell.optionImageView.isHidden = true
}
cell.optionNameLabel.text = navItem.title?.uppercased()
return cell
}
As you can see the separator view and icon can be hidden or shown and modifies cell height accordingly. The issue is the self sizing does not work on initial dequeue but after scrolling it fixes itself.
Here is the runtime error thrown from autolayout: 1.
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:0x600002525810 'fittingSizeHTarget' UIStackView:0x7fafd1e8c330.width == 0 (active)>",
"<NSLayoutConstraint:0x600002524f50 'UISV-canvas-connection' UIStackView:0x7fafd1e8c330.leading == UIImageView:0x7fafd1e8c4c0.leading (active)>",
"<NSLayoutConstraint:0x600002524fa0 'UISV-canvas-connection' H:[UILabel:0x7fafd1e8aa30]-(0)-| (active, names: '|':UIStackView:0x7fafd1e8c330 )>",
"<NSLayoutConstraint:0x600002524ff0 'UISV-spacing' H:[UIImageView:0x7fafd1e8c4c0]-(16)-[UILabel:0x7fafd1e8aa30] (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600002524ff0 'UISV-spacing' H:[UIImageView:0x7fafd1e8c4c0]-(16)-[UILabel:0x7fafd1e8aa30] (active)>
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:0x600002500410 V:|-(8)-[UIStackView:0x7fafd1f47c90] (active, names: '|':UITableViewCellContentView:0x7fafd1f0cf90 )>",
"<NSLayoutConstraint:0x600002500820 UIStackView:0x7fafd1f47c90.bottom == UITableViewCellContentView:0x7fafd1f0cf90.bottom - 8 (active)>",
"<NSLayoutConstraint:0x600002500550 UIImageView:0x7fafd1f569f0.height == 24 (active)>",
"<NSLayoutConstraint:0x600002502120 'UISV-canvas-connection' V:[_UILayoutSpacer:0x60000399e2b0'UISV-alignment-spanner']-(0)-| (active, names: '|':UIStackView:0x7fafd1f5a1e0 )>",
"<NSLayoutConstraint:0x600002500370 'UISV-canvas-connection' UIStackView:0x7fafd1f5a1e0.centerY == UIImageView:0x7fafd1f569f0.centerY (active)>",
"<NSLayoutConstraint:0x600002500000 'UISV-canvas-connection' UIStackView:0x7fafd1f47c90.top == UIStackView:0x7fafd1f5a1e0.top (active)>",
"<NSLayoutConstraint:0x6000025d2260 'UISV-canvas-connection' V:[UIView:0x7fafd1f48db0]-(0)-| (active, names: '|':UIStackView:0x7fafd1f47c90 )>",
"<NSLayoutConstraint:0x6000025b2490 'UISV-spacing' V:[UIStackView:0x7fafd1f5a1e0]-(10)-[UIView:0x7fafd1f48db0] (active)>",
"<NSLayoutConstraint:0x600002502210 'UISV-spanning-boundary' _UILayoutSpacer:0x60000399e2b0'UISV-alignment-spanner'.bottom >= UIImageView:0x7fafd1f569f0.bottom (active)>",
"<NSLayoutConstraint:0x6000025f2cb0 'UIView-Encapsulated-Layout-Height' UITableViewCellContentView:0x7fafd1f0cf90.height == 43.5 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x600002500550 UIImageView:0x7fafd1f569f0.height == 24 (active)>
What I did:
I have added a few constraints and reduced priority as they were giving some errors when made hidden but they had fixed height/width. But errors are still thrown and self sizing still not working properly.