Как динамически ограничить просмотр содержимого ячейки внутри вложенных представлений?

#ios #autolayout #uicollectionviewcell

#iOS #автоматическое описание #uicollectionviewcell

Вопрос:

В conentView collectionCell я хочу ограничить вертикальный вложенный просмотр разной высотой в соответствии с разными значениями, но проблема в том, что высота неожиданно изменяется, когда содержимое прокручивается с экрана, затем прокручивается обратно на экран:

Начальная и правильная высота представления:
введите описание изображения здесь

Прокрутите экран, затем назад (высота просмотра изменяется по неизвестной причине):
введите описание изображения здесь

Ниже приведен код макета:

     let contentView = cell.contentView
    let row = indexPath.row
    
    //calculate view height: relativeHeight value
    let cellHeight = cell.frame.height
    var relativeHeight = 0.6 * cellHeight
    
    let values = [112.0, 116.0, 86.0, 95.0, 67.0, 76.0, 34.0, 43.0, 24.0, 35.0, 47.0, 66.0, 66.0, 57.0, 36.0, 64.0, 23.0, 22.0, 23.0, 22.0, 22.0, 22.0, 20.0, 23.0]
    
    let Δvalue = values.max()! - values.min()!
    
    let value = values[row]
    if Δvalue != 0 {
        let different = value - values.min()!
        let ratio = CGFloat(different / Δvalue)
        relativeHeight = ratio * relativeHeight
    }
    
    if contentView.subviews.count == 0 {
        //time label
        let timeLabel = UILabel()
        timeLabel.tag = 3
        timeLabel.textColor = self.textColor
        timeLabel.font = UIFont.boldSystemFont(ofSize: 13)
        contentView.addSubview(timeLabel)
        
        timeLabel.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            timeLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -4),
            timeLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor)
        ])
        
        //vertical view 
        let valueView = UIView()
        valueView.tag = 1
        valueView.backgroundColor = UIColor.systemBlue.withAlphaComponent(0.382) //1-0.618
        
        contentView.addSubview(valueView)
        
        valueView.translatesAutoresizingMaskIntoConstraints = false
        //valueView.constraints.forEach{ $0.isActive = false }
        
        NSLayoutConstraint.activate([
            valueView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            valueView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            valueView.bottomAnchor.constraint(equalTo: timeLabel.topAnchor, constant: -4),
            valueView.heightAnchor.constraint(equalToConstant: relativeHeight)
        ])
        
        //value label
        let valueLabel = UILabel()
        valueLabel.tag = 2
        valueLabel.textColor = self.textColor
        valueLabel.font = UIFont.systemFont(ofSize: 12)
        contentView.addSubview(valueLabel)
        
        valueLabel.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            valueLabel.bottomAnchor.constraint(equalTo: valueView.topAnchor, constant: -4),
            valueLabel.centerXAnchor.constraint(equalTo: valueView.centerXAnchor)
        ])
        
    }
  

Как я могу решить такую проблему с ограничениями макета?

Заранее большое спасибо!

Комментарии:

1. valueView.heightAnchor.constraint(equalToConstant: relativeHeight) как вы вычисляете relativeHeight ? Также есть какая-либо особая причина для деактивации ограничений перед добавлением их в оператор valueView.constraints.forEach{ $0.isActive = false } , сохраняете ли вы ссылку на valueView в ячейке? есть ли шанс не создавать его, если есть существующий valueView ?

2. Пожалуйста, ознакомьтесь с дополнением к вычислению относительной высоты. Я подумал, что, возможно, конфликт ограничений вызвал изменение высоты представления, поэтому я сначала пытаюсь деактивировать, а затем активировать. Каждая ячейка имеет свой собственный или независимый valueView, он не хранит ссылку, которая может использоваться другой ячейкой.

3. расчет для relativeHeight мне кажется, что все в порядке, поскольку вы выделяете новый экземпляр valueView каждый раз, когда выполняется код, я думаю, в этом нет необходимости valueView.constraints.forEach{ $0.isActive = false } . ОДИН БОЛЬШОЙ ВОПРОС, когда и где выполняется этот код? Это cellForRow(:indexPath) или какой-либо другой метод жизненного цикла UITableViewCell ? Таким образом будет сложно отлаживать, можете ли вы создать один пример проекта с проблемой и поделиться им на github, это будет здорово проверить дальше.

4. Это в cellForRow (:indexPath) . Пожалуйста, загрузите код по адресу » github.com/steve880925/CollectionView-Bug »

Ответ №1:

Я думаю, проблема заключалась в том, что не было ссылки на valueView или heightConstraint , которую вы пытаетесь установить после выделения, проверки contentView.subviews.count == 0 . Способ, которым вы готовите иерархию представлений для UICollectionViewCell , может вообще не быть хорошей практикой. При удалении из очереди повторно используемого представления необходимо учитывать все условия для установки динамических значений. Здесь не было никакого обработчика, если contentView.subviews.count == 0 сбой.

Исправление было выполнено с использованием подкласса UICollectionViewCell для абстрагирования всех связанных с представлением задач внутри CollectionViewCell: UICollectionViewCell . Я добавил одно свойство valueViewHeightConst с начальным значением ограничения 0.0. Я устанавливаю точное значение после вычисления значения высоты для установки.

Также представлен один механизм кэширования, где вам не нужно вычислять relativeHeight каждый раз, когда ячейка удаляется из очереди.

Пожалуйста, проверьте окончательный проект наhttps://github.com/sauvikapple/StackoverflowAnsToQ63743769.

Вот результат

введите описание изображения здесь