UIStackView внутри UITableViewCell
Итак, я пытаюсь увидеть, как я могу сделать следующий пользовательский интерфейс в коде с помощью UIStackView
:
Обратите внимание, что изображение может быть скрыто или даже иметь другой размер. Единственное, что постоянно в изображении - это ширина.
Ниже приводится класс, который я придумал:
public class MenuItemTableViewCell: UITableViewCell {
//MARK: UI elements
var titleLabel = UILabel()
var detailsLabel = UILabel()
var itemImageView = UIImageView()
var mainStackView = UIStackView()
//MARK: Variables
var menuItem: MenuItem? {
didSet {
if let item = menuItem {
titleLabel.text = item.name
detailsLabel.text = item.itemDescription
if let imageURL = item.imageURL {
itemImageView.af_setImage(withURL: imageURL) { [weak self] response in
guard let imageView = self?.itemImageView else {
return
}
switch response.result {
case .success(let image):
// Instance variable:
var imageAspectRatioConstraint: NSLayoutConstraint?
// When you set the image:
imageAspectRatioConstraint?.isActive = false
imageAspectRatioConstraint = imageView.heightAnchor.constraint(
equalTo: imageView.widthAnchor,
multiplier: 100 / image.size.height)
imageAspectRatioConstraint!.isActive = true
default:
return
}
}
} else {
itemImageView.isHidden = true
}
} else {
titleLabel.text = ""
detailsLabel.text = ""
itemImageView.image = nil
}
}
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
initViews()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
private func initViews() {
self.accessoryType = .disclosureIndicator
self.selectionStyle = .none
setupMainStackView()
setupTitleLabel()
setupDetailLabel()
setupItemImageViewLabel()
}
//MARK: Components setup
private func setupMainStackView() {
mainStackView.alignment = .fill
mainStackView.distribution = .fillProportionally
mainStackView.spacing = 5
mainStackView.axis = .vertical
mainStackView.translatesAutoresizingMaskIntoConstraints = false
mainStackView.layoutMargins = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
mainStackView.isLayoutMarginsRelativeArrangement = true
mainStackView.setContentCompressionResistancePriority(UILayoutPriorityRequired, for: .vertical)
mainStackView.distribution = .fillProportionally
self.contentView.addSubview(mainStackView)
addMainStackViewContraints()
}
//
// Title Label
//
private func setupTitleLabel() {
titleLabel.textColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
titleLabel.numberOfLines = 1
mainStackView.addArrangedSubview(titleLabel)
addTitleLabelConstraints()
}
//
// Detail Label
//
private func setupDetailLabel() {
detailsLabel.textColor = #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)
detailsLabel.setContentHuggingPriority(UILayoutPriorityRequired, for: .vertical)
detailsLabel.numberOfLines = 2
mainStackView.addArrangedSubview(detailsLabel)
addDetailsLabelContraints()
}
//
// Item Image
//
private func setupItemImageViewLabel() {
itemImageView.contentMode = .scaleAspectFit
itemImageView.clipsToBounds = true
mainStackView.addArrangedSubview(itemImageView)
addItemImageViewConstraitns()
}
//MARK: Constraints setup
private func addTitleLabelConstraints() {
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.setContentCompressionResistancePriority(UILayoutPriorityRequired, for: .vertical)
titleLabel.setContentHuggingPriority(UILayoutPriorityRequired, for: .vertical)
}
func addDetailsLabelContraints() {
detailsLabel.translatesAutoresizingMaskIntoConstraints = false
detailsLabel.setContentCompressionResistancePriority(UILayoutPriorityRequired, for: .vertical)
detailsLabel.setContentHuggingPriority(UILayoutPriorityRequired, for: .vertical)
}
func addItemImageViewConstraitns() {
itemImageView.translatesAutoresizingMaskIntoConstraints = false
itemImageView.widthAnchor.constraint(equalTo: mainStackView.widthAnchor).isActive = true
itemImageView.leftAnchor.constraint(equalTo: mainStackView.leftAnchor).isActive = true
}
private func addMainStackViewContraints() {
mainStackView.topAnchor.constraint(equalTo: self.contentView.topAnchor).isActive = true
mainStackView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor).isActive = true
mainStackView.leftAnchor.constraint(equalTo: self.contentView.leftAnchor).isActive = true
mainStackView.rightAnchor.constraint(equalTo: self.contentView.rightAnchor).isActive = true
}
}
В настоящее время это выглядит так:
и если я уберу нижнее ограничение из моего UIStackView
было бы так:
Любая помощь в получении лучшего понимания того, как UIStackView
работает и с авторазмером один в UITableViewCell
высоко ценится
2 ответа
Как выглядит ваша логика в:
- (CGSize) collectionView:(UICollectionView *)collectionView
layout:(UICollectionViewLayout*)collectionViewLayout
sizeForItemAtIndexPath:(NSIndexPath *)indexPath
Должно быть что-то вроде...
- захватить ячейку для этого пути индекса
- определить высоту ячейки на основе ширины
вернуть соответствующую высоту
Здесь есть несколько хороших примеров того, что такое NSLayoutConstraint "UIView-Encapsulated-Layout-Height" и как мне заставить его пересчитывать чисто
В общем, использование UIStackView в UITableViewCell не очень хорошая идея. Это может вызвать проблемы с производительностью. Но если вам нравится, вы можете попробовать вызвать метод layoutIfNeeded() для вашей ячейки, когда вы настраиваете его (особенно после установки представления изображения ячейки). Может быть, это поможет.