UICollectionView автоматически увеличивает высоту
Как правильно изменить размер UICollectionView так, чтобы он полностью отображал его содержимое? Я пробовал много вещей, включая настройку его фрейма, вызов reloadData
и недействительность макета:
self.collectionView.contentSize = CGSizeMake(300, 2000);
self.collectionView.frame = CGRectMake(0, 0, 300, 2000);
[self.collectionView reloadData];
[self.collectionView.collectionViewLayout invalidateLayout];
но ничто из этого не имеет никакого эффекта. После нажатия кнопки я все еще вижу начальный вид, например:
![collection view only showing part of the content after frame resize]()
У меня есть небольшая демонстрационная программа, где у меня есть источник данных, производящий 100 элементов. В Interface Builder я первоначально устанавливал размер UICollectionView на небольшое значение, чтобы не все элементы соответствовали, после чего я нажимаю кнопку, после которой выполняется код выше. Я ожидаю, что UICollectionView теперь покажет все элементы, но это не так.
EDIT: Демо-программу можно найти на https://github.com/mjdemilliano/TestUICollectionView.
EDIT2: Я заметил, что обновление кадра в какой-то момент теряется, потому что если я снова нажму кнопку, текущий кадр вернется к старому значению. После добавления некоторых операторов журнала в обработчик событий кнопки вывод журнала:
before: frame = {{0, 58}, {320, 331}}, contentSize = {320, 1190}
update button pressed
after: frame = {{0, 0}, {300, 2000}}, contentSize = {300, 2000}
before: frame = {{0, 58}, {320, 331}}, contentSize = {320, 1190}
update button pressed
after: frame = {{0, 0}, {300, 2000}}, contentSize = {300, 2000}
Я не понимаю, почему изменение кадра не сохраняется, что его меняет.
В какой-то момент я заменю жестко заданные значения на значения, полученные из макета потока, но я хотел бы это исключить и сохранить мой пример как можно более простым.
Контекст: то, что я хочу сделать в конечном итоге, следующее: у меня есть прокручиваемое представление с различными элементами управления, такими как метки и образы, и представление коллекции с динамическим контентом. Я хочу прокрутить все это, а не только просмотр коллекции, поэтому я не использую собственные средства просмотра прокрутки, которые отлично работают.
Ответы
Ответ 1
Я решил это в конечном итоге, исправив все ошибки Auto Layout, установив высоту представления коллекции с помощью ограничения. Затем, когда я знаю, что содержимое изменилось, я обновляю значение ограничения, используя значение collectionView.contentSize.height
:
self.verticalLayoutConstraint.constant = self.collectionView.contentSize.height;
Затем представление коллекции изменяется правильно, и оно хорошо ведет себя в общем прокрутке. Я обновил тестовый проект GitHub с изменениями.
Для меня, сделав это, обновив ограничение вручную, вместо того, чтобы рассказать iOS: "сделать высоту кадра в представлении коллекции настолько большим, насколько это необходимо" мне не кажется правильным, но это лучшее, что я придумал до сих пор. Пожалуйста, напишите лучший ответ, если он у вас есть.
Ответ 2
Здесь моя реализация в Swift 3:
override func sizeThatFits(_ size: CGSize) -> CGSize {
if (self.superview != nil) {
self.superview?.layoutIfNeeded()
}
return collectionView.contentSize
}
Ответ 3
UICollectionViewFlowLayout *flowLayout;
flowLayout = [[UICollectionViewFlowLayout alloc]init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];
[flowLayout setMinimumInteritemSpacing:0.0f];
[flowLayout setMinimumLineSpacing:0.0f];
[self.collectionView setPagingEnabled:NO];
[flowLayout setItemSize:CGSizeMake(322.0, 148.0)]; //important to leave no white space between the images
[self.collectionView setCollectionViewLayout:flowLayout];
Я обнаружил, что автозапуск в раскадровке не слишком помогает. Правильная настройка для UICollectionViewFlowLayout для вашей коллекцииView - настоящая помощь. Если вы измените размер элемента с помощью setItemSize, вы можете получить желаемый результат.
Ответ 4
Здесь можно связать высоту CollectionView с ее внутренним размером.
Я использовал его для правильного размера CollectionView внутри CellView TableView (с динамической высотой ячеек). и он отлично работает.
Сначала добавьте это в подкласс UICollectionView:
override var intrinsicContentSize: CGSize {
get {
return self.contentSize
}
}
Затем вызовите layoutIfNeeded() после перезагрузки данных:
reloadData()
layoutIfNeeded()
Ответ 5
Самый простой метод, который я нашел, это переопределить sizeThatFits:
методы как есть:
- (CGSize)sizeThatFits:(CGSize)size
{
if( self.superview )
[self.superview layoutIfNeeded]; // to force evaluate the real layout
return self.collectionViewLayout.collectionViewContentSize;
}
Ответ 6
Вы можете попробовать мой пользовательский класс AGCollectionView
- Назначьте ограничение высоты collectionView, используя раскадровку или программно.
- Назначьте этот класс вашему UICollectionView
.
class AGCollectionView: UICollectionView {
fileprivate var heightConstraint: NSLayoutConstraint!
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
self.associateConstraints()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.associateConstraints()
}
override open func layoutSubviews() {
super.layoutSubviews()
if self.heightConstraint != nil {
self.heightConstraint.constant = floor(self.contentSize.height)
}
else{
self.sizeToFit()
print("Set a heightConstraint set size to fit content")
}
}
func associateConstraints() {
// iterate through height constraints and identify
for constraint: NSLayoutConstraint in constraints {
if constraint.firstAttribute == .height {
if constraint.relation == .equal {
heightConstraint = constraint
}
}
}
}
}
Ответ 7
Для меня это еще проще, я думаю
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
//add following code line after adding cells, before Return
...........
.........
scrollView.contentSize = = collectionView.contentSize;
//now scrollView size is equal to collectionView size. No matter how small or big it is.
return cell;
}