UICollectionView внутри UITableViewCell с UITableViewAutoDimesion - PullRequest
0 голосов
/ 20 сентября 2018

Я работаю над проектом, необходимо добавить UICollectionView (горизонтальное направление) внутри UITableViewCell.Высота UITableViewCell использует UITableViewAutoDimension, и каждый UITableViewCell имеет UIView (с рамкой для требований к дизайну) в качестве базового представления, а в UIView добавлен UIStackView в качестве контейнера, чтобы пропорционально заполнить UICollectionView с помощью двух других кнопок.вертикально.А затем для UICollectionViewCell я добавил в UIStackView заполнение пяти меток.

Теперь автоматическое расположение работает, если UITableViewDelegate назначает фиксированную высоту.Но это не работает с UITableViewAutoDimension.Я предполагаю, что фрейм UICollectionView не готов, пока UITableView рендерит свои ячейки.Таким образом, UITableViewAutoDimension вычисляет высоту UITableViewCell с высотой по умолчанию UICollectionView, которая равна нулю.

Так что, конечно, я искал, прежде чем выкинуть вопрос в Интернете, но никакие решения не помогли мне.Вот несколько ссылок, которые я пробовал.

UICollectionView внутри UITableViewCell - динамическая высота?

Создание UITableView со встроенным UICollectionView с использованием UITableViewAutomaticDimension

UICollectionView внутриUITableViewCell НЕ выполняет динамический размер правильно

У кого-нибудь есть такая же проблема?Если ссылки выше работали, пожалуйста, дайте мне знать, если я сделал это неправильно.Спасибо

--- Обновлено 23 сентября 2018 :

  • Визуализация макета: есть некоторые модификации пользовательского интерфейса, но это не меняетвопрос, с которым я сталкиваюсь.Надеюсь, что картина может помочь.

    enter image description here

  • Код: мой текущий код фактически не использует UIStackView в UITableViewCell и UITableView heightForRowAtIndex Iвернуть фиксированную высоту с 250.0.Однако UITableView не настроит высоту ячейки должным образом, если я верну UITableViewAutoDimension, как я уже упоминал в своем вопросе.

1.UITableViewController

class ViewController: UIViewController {

    private let tableView: UITableView = {
       let tableView = UITableView()
       tableView.translatesAutoresizingMaskIntoConstraints = false
       tableView.register(ViewControllerTableViewCell.self, forCellReuseIdentifier: ViewControllerTableViewCell.identifier)
       return tableView
    }()

    private lazy var viewModel: ViewControllerViewModel = {
        return ViewControllerViewModel(models: [
            Model(title: "TITLE", description: "SUBTITLE", currency: "USD", amount: 100, summary: "1% up"),
            Model(title: "TITLE", description: "SUBTITLE", currency: "USD", amount: 200, summary: "2% up"),
            Model(title: "TITLE", description: "SUBTITLE", currency: "USD", amount: 300, summary: "3% up"),
        ])
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.dataSource = self
        tableView.delegate = self

        view.addSubview(tableView)

        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: view.topAnchor),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

extension ViewController: UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return viewModel.numberOfSections
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return viewModel.numberOfRowsInSection
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: ViewControllerTableViewCell.identifier, for: indexPath) as! ViewControllerTableViewCell
        cell.configure(viewModel: viewModel.cellViewModel)
        return cell
    }
}

extension ViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 250.0
    }
}

2.UITableViewCell

class ViewControllerTableViewCell: UITableViewCell {

    static let identifier = "ViewControllerTableViewCell"

    private var viewModel: ViewControllerTableViewCellViewModel!

    private let borderView: UIView = {
        let view = UIView()
        view.translatesAutoresizingMaskIntoConstraints = false
        view.layer.borderColor = UIColor.black.cgColor
        view.layer.borderWidth = 1
        return view
    }()

    private let stackView: UIStackView = {
        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.distribution = .fillProportionally
        return stackView
    }()

    private let seperator: UIView = {
        let seperator = UIView()
        seperator.translatesAutoresizingMaskIntoConstraints = false
        seperator.backgroundColor = .lightGray
        return seperator
    }()

    private let actionButton: UIButton = {
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitle("Show business insight", for: .normal)
        button.setTitleColor(.black, for: .normal)
        return button
    }()

    private let pageControl: UIPageControl = {
        let pageControl = UIPageControl()
        pageControl.translatesAutoresizingMaskIntoConstraints = false
        pageControl.pageIndicatorTintColor = .lightGray
        pageControl.currentPageIndicatorTintColor = .black
        pageControl.hidesForSinglePage = true
        return pageControl
    }()

    private let collectionView: UICollectionView = {
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: 200, height: 200), collectionViewLayout: layout)
        collectionView.isPagingEnabled = true
        collectionView.backgroundColor = .white
        collectionView.showsHorizontalScrollIndicator = false
        collectionView.translatesAutoresizingMaskIntoConstraints = false
        collectionView.register(ViewControllerCollectionViewCell.self, forCellWithReuseIdentifier: ViewControllerCollectionViewCell.identifier)
        return collectionView
    }()

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setUpConstraints()
        setUpUserInterface()
    }

    func configure(viewModel: ViewControllerTableViewCellViewModel) {
        self.viewModel = viewModel
        pageControl.numberOfPages = viewModel.items.count
        collectionView.reloadData()
    }

    @objc func pageControlValueChanged() {
        let indexPath = IndexPath(item: pageControl.currentPage, section: 0)
        collectionView.scrollToItem(at: indexPath, at: .left, animated: true)
    }

    private func setUpConstraints() {
        contentView.addSubview(borderView)
        borderView.addSubview(actionButton)
        borderView.addSubview(seperator)
        borderView.addSubview(pageControl)
        borderView.addSubview(collectionView)

        NSLayoutConstraint.activate([
            borderView.topAnchor.constraint(equalTo: topAnchor, constant: 10),
            borderView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20),
            borderView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20),
            borderView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10),
        ])

        NSLayoutConstraint.activate([
            actionButton.heightAnchor.constraint(greaterThanOrEqualToConstant: 44),
            actionButton.leadingAnchor.constraint(equalTo: borderView.leadingAnchor),
            actionButton.trailingAnchor.constraint(equalTo: borderView.trailingAnchor),
            actionButton.bottomAnchor.constraint(equalTo: borderView.bottomAnchor)
        ])

        NSLayoutConstraint.activate([
            seperator.heightAnchor.constraint(equalToConstant: 1),
            seperator.leadingAnchor.constraint(equalTo: borderView.leadingAnchor),
            seperator.trailingAnchor.constraint(equalTo: borderView.trailingAnchor),
            seperator.bottomAnchor.constraint(equalTo: actionButton.topAnchor)
        ])

        NSLayoutConstraint.activate([
            pageControl.heightAnchor.constraint(greaterThanOrEqualToConstant: 40),
            pageControl.leadingAnchor.constraint(equalTo: borderView.leadingAnchor),
            pageControl.trailingAnchor.constraint(equalTo: borderView.trailingAnchor),
            pageControl.bottomAnchor.constraint(equalTo: seperator.topAnchor)
        ])

        NSLayoutConstraint.activate([
            collectionView.topAnchor.constraint(equalTo: borderView.topAnchor),
            collectionView.leadingAnchor.constraint(equalTo: borderView.leadingAnchor),
            collectionView.trailingAnchor.constraint(equalTo: borderView.trailingAnchor),
            collectionView.bottomAnchor.constraint(equalTo: pageControl.topAnchor)
        ])
    }

    private func setUpUserInterface() {
        selectionStyle = .none
        collectionView.delegate   = self
        collectionView.dataSource = self
        pageControl.addTarget(self, action: #selector(pageControlValueChanged), for: .valueChanged)
    }
}

extension ViewControllerTableViewCell: UICollectionViewDataSource {
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return viewModel!.numberOfSections
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return viewModel!.numberOfRowsInSection
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ViewControllerCollectionViewCell.identifier, for: indexPath) as! ViewControllerCollectionViewCell
        let collectionCellViewModel = viewModel!.collectionCellViewModel(at: indexPath)
        cell.configure(viewModel: collectionCellViewModel)
        return cell
    }
}

extension ViewControllerTableViewCell: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        debugPrint("did select \(indexPath.row)")
    }

    func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        pageControl.currentPage = indexPath.row
    }
}

extension ViewControllerTableViewCell: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: collectionView.frame.width - 40.0, height: collectionView.frame.height)
    }

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        insetForSectionAt section: Int) -> UIEdgeInsets {
        return UIEdgeInsets(top: 0, left: 20.0, bottom: 0, right: 20.0)
    }

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 40.0
    }
}

3.UICollectionViewCell

class ViewControllerCollectionViewCell: UICollectionViewCell {

    override class var requiresConstraintBasedLayout: Bool {
        return true
    }

    static let identifier = "ViewControllerCollectionViewCell"

    private let stackView: UIStackView = {
        let stackView = UIStackView()
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .vertical
        stackView.distribution = .fillEqually
        return stackView
    }()

    private let titleLabel: UILabel = {
        let titleLabel = UILabel()
        titleLabel.textColor = .black
        titleLabel.font = UIFont.systemFont(ofSize: 20, weight: .bold)
        titleLabel.translatesAutoresizingMaskIntoConstraints = false
        return titleLabel
    }()

    private let descriptionLabel: UILabel = {
        let descriptionLabel = UILabel()
        descriptionLabel.textAlignment = .right
        descriptionLabel.textColor = .black
        descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
        return descriptionLabel
    }()

    private let amountLabel: UILabel = {
        let amountLabel = UILabel()
        amountLabel.textColor = .black
        amountLabel.textAlignment = .right
        amountLabel.translatesAutoresizingMaskIntoConstraints = false
        return amountLabel
    }()

    private let summaryLabel: UILabel = {
        let summaryLabel = UILabel()
        summaryLabel.textColor = .black
        summaryLabel.textAlignment = .right
        summaryLabel.translatesAutoresizingMaskIntoConstraints = false
        return summaryLabel
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        contentView.addSubview(stackView)
        stackView.addArrangedSubview(titleLabel)
        stackView.addArrangedSubview(descriptionLabel)
        stackView.addArrangedSubview(amountLabel)
        stackView.addArrangedSubview(summaryLabel)

        NSLayoutConstraint.activate([
            stackView.topAnchor.constraint(equalTo: topAnchor),
            stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
            stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
            stackView.bottomAnchor.constraint(equalTo: bottomAnchor)
        ])
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func configure(viewModel: CollectionCellViewModel) {
        titleLabel.text = viewModel.title
        descriptionLabel.text = viewModel.description
        amountLabel.text = viewModel.amount.localizedCurrencyString(with: viewModel.currency)
        summaryLabel.text = viewModel.summary
    }
}

1 Ответ

0 голосов
/ 22 сентября 2018

Чтобы включить ячейки табличного представления с самоопределением размера, необходимо установить для свойства rowHeight табличного представления значение UITableViewAutomaticDimension.Вы также должны присвоить значение свойству оценкам RowHeight, также вам нужна непрерывная цепочка ограничений и представлений, чтобы заполнить представление содержимого ячейки.

Подробнее: https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithSelf-SizingTableViewCells.html#//apple_ref/doc/uid/TP40010853-CH25-SW1

Таким образом, в этом случае UIView с рамкой динамически определяет высоту ячейки табличного представления, вы должны сообщить системе, какова высота этого UIView, вы можете ограничить этопросмотреть края UIStackView (верхний, нижний, ведущий, задний) и использовать UIStackView внутренняя высота содержимого в качестве высоты UIView (с рамкой).

Проблема в внутренней высоте содержимого UIStackView и в свойстве распределения.UIStackView может автоматически оценивать высоту для двух кнопок UIB (в зависимости от размера текста, стиля шрифта и размера шрифта), но UICollectionView не имеет внутренней высоты содержимого, а поскольку ваш UIStackview заполняется пропорционально, UIStackView устанавливает высоту0.0 для UICollectionView, так что это выглядит примерно так:

Заполнить пропорционально UIStackView

Но если вы измените свойство распределения UIStackView для одинакового заполнения, у вас будет что-тонапример:

Равномерно заполнить UIStackView

Если вы хотите, чтобы UICollectionView определял свой собственный размер и заполнял UIStackView пропорционально, вам нужно установить ограничение высоты для UICollectionView.А затем обновите ограничение на основе высоты содержимого UICollectionViewCell.

Ваш код выглядит хорошо, вам нужно только внести незначительные изменения. Вот решение (обновлено 25.09.2008):

 private func setUpConstraints() {
    contentView.addSubview(borderView)
    borderView.addSubview(actionButton)
    borderView.addSubview(seperator)
    borderView.addSubview(pageControl)
    borderView.addSubview(collectionView)

    NSLayoutConstraint.activate([
        borderView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10), // ---  >. Use cell content view anchors
        borderView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20), // ---  >. Use cell content view anchors
        borderView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20), // ---  >. Use cell content view anchors
        borderView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10), // ---  >. Use cell content view anchors
        ])


    //other constraints....

    NSLayoutConstraint.activate([
        collectionView.topAnchor.constraint(equalTo: borderView.topAnchor),
        collectionView.leadingAnchor.constraint(equalTo: borderView.leadingAnchor),
        collectionView.trailingAnchor.constraint(equalTo: borderView.trailingAnchor),
        collectionView.bottomAnchor.constraint(equalTo: pageControl.topAnchor),

    collectionView.heightAnchor.constraint(equalToConstant: 200) // ---> System needs to know height, add this constraint to collection view.
        ])
}

Также не забудьте установить для tableView rowHeight значение UITableView.automaticDimension и дать системе приблизительную высоту строки с помощью: tableView.estimatedRowHeight.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...