UICollectionView отсутствует логика выравнивания в горизонтальной прокрутки

у меня естьUICollectionView, который работает нормально, пока я не начну прокручивать. Вот несколько фотографий в первую очередь:

Как вы можете видеть этоотлично. Когда я начинаю прокручивать (включенная подкачка), первый из них выходит за экран:

Это проблема. Первоначально мой вид имеет 3 вида, и я хочу прокрутить и показать только 3 вида. Но поскольку он прокручивается (включена подкачка страниц), он скрывает немного первого представления и показывает немного следующего первого представления со следующей страницы.

А вот видео, потому что этоСложно объяснить:Видео проблемы (Dropbox)

Вот фотография моегоUICollectionView настройки:

Это'будет здорово, если кто-то может помочь!

 Alexander19 февр. 2013 г., 15:49
Может быть, мой похожий вопрос и этоОтвет может помочь вам! Для меня это решило проблему с прокруткой:stackoverflow.com/questions/14651464/...
 onmyway13330 сент. 2015 г., 12:53
Просто установитеmin spacing до 0

Ответы на вопрос(16)

что у меня есть решение этой проблемы. Но я не буду, если этоэто лучшее.

UICollectionViewFlowLayout содержит свойство под названиемsectionInset, Таким образом, вы можете установить раздел Inset так, как вам нужно, и сделать 1 страницу равной одному разделу. Поэтому ваша прокрутка должна автоматически вписываться в страницы (= разделы)

когда пытался заставить горизонтальный пейджинг работать с сеткой ячеек 3 х 3 с разделами вставками и ячейками. межстрочный интервал.

Ответ для меня (после попытки многих предложений - включая создание подклассов UICollectionViewFlowLayout и различных решений для делегатов UIScrollView) был прост. Я просто использовал разделы в UICollectionView, разбив свой набор данных на разделы по 9 элементов (или меньше) и используя методы источника данных numberOfSectionsInCollectionView и numberOfItemsInSection UICollectionView.

UICollectionView 'Горизонтальный пейджинг теперь работает прекрасно. Я рекомендую такой подход всем, кто в данный момент рвет себе волосы по похожему сценарию.

https://stackoverflow.com/a/27242179/440168 но проще.

Вы должны разместитьUIScrollView вышеUICollectionView и дать им равные размеры:

@property (nonatomic, weak) IBOutlet UICollectionView *collectionView;
@property (nonatomic, weak) IBOutlet UIScrollView *scrollView;

Затем настройтеcontentInset представления коллекции, например:

CGFloat inset = self.view.bounds.size.width*2/9;
self.collectionView.contentInset = UIEdgeInsetsMake(0, inset, 0, inset);

А такжеcontentSize просмотра прокрутки:

self.scrollView.contentSize = CGSizeMake(self.placesCollectionView.bounds.size.width*[self.collectionView numberOfItemsInSection:0],0);

Не забудьте установить делегат вида прокрутки:

self.scrollView.delegate = self;

И реализовать главное волшебство:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (scrollView == self.scrollView) {
        CGFloat inset = self.view.bounds.size.width*2/9;
        CGFloat scale = (self.placesCollectionView.bounds.size.width-2*inset)/scrollView.bounds.size.width;
        self.collectionView.contentOffset = CGPointMake(scrollView.contentOffset.x*scale - inset, 0);
    }
}
 k06a13 июн. 2015 г., 16:51
@iamdavidlam Да, похоже, мое решение не поддерживает касание содержимого ячеек коллекции. Я использую это по-другому. Два вида коллекции с их кадрами один рядом (под) другой.
 iamdavidlam13 июн. 2015 г., 16:45
привет, просто чтобы проверить, когда ты сказал "Вы должны поместить UIScrollView над UICollectionView и дать им равные размеры: " , вы действительно имеете в виду superView.addSubview (collectionView) superView.addSubview (scrollView), верно? не scrollView.addSubview (collectionView)

с которой я столкнулся, и я разместил свое решение в другом сообщении, поэтому яЯ опубликую это снова здесь.

Я нашел решение для этого, и это включало создание подкласса UICollectionViewFlowLayout.

Размер моего CollectionViewCell составляет 302 X 457, и я установил минимальный межстрочный интервал равным 18 (9 пикселей для каждой ячейки)

Когда вы выходите из этого класса, есть несколько методов, которые нужно переопределить. Один из них является

(CGSize) collectionViewContentSize

В этом методе мне нужно было сложить общую ширину того, что было в UICollectionView. Это включает в себя ([источник данных] * widthOfCollectionViewCell) + ([количество источников данных] * 18)

Вот мои пользовательские методы UICollectionViewFlowLayout ....

-(id)init
{
    if((self = [super init])){

       self.itemSize = CGSizeMake(302, 457);
       self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10);
       self.minimumInteritemSpacing = 0.0f;
       self.minimumLineSpacing = 18.0f;
       [self setScrollDirection:UICollectionViewScrollDirectionHorizontal];
   }
    return self;
}



-(CGSize)collectionViewContentSize{
   return CGSizeMake((numCellsCount * 302)+(numCellsCount * 18), 457);
}

Это сработало для меня, поэтому я надеюсь, что кто-то еще найдет это полезным!

Я постараюсь, чтобы ты тоже это понял.

Если вы посмотрите внимательно, то увидите, что эта проблема возникает только постепенно, а не только на первом пролистывании страницы.

Если я правильно понимаю, в настоящее время в вашем приложении каждый элемент UICollectionView - это те закругленные прямоугольники, которые мы видим, и у вас есть некоторое смещение / поле между ними, которое является постоянным. Это то, что вызывает проблему.

Вместо этого вам нужно создать элемент UICollectionView, который составляет 1/3 ширины всего представления, а затем добавить в него округленное изображение. Чтобы сослаться на изображение, зеленый цвет должен быть вашим UICollectionViewItem, а не черным.

Если вы используете макет потока по умолчанию для вашего UICollectionView и НЕ хотите, чтобы между каждой ячейкой было свободное пространство, вы можете установить для его свойства miniumumLineSpacing значение 0 через:

((UICollectionViewFlowLayout *) self.collectionView.collectionViewLayout).minimumLineSpacing = 0;

Решение из следующей статьи элегантно и просто. Основная идея заключается в создании scrollView поверх вашего collectionView с передачей всех значений contentOffset.

http://b2cloud.com.au/tutorial/uiscrollview-paging-size/

Следует сказать, реализуя этот метод:

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;

Я не'добиться плавной анимации, как этопроисходит с pagingEnabled = YES.

 morcutt19 янв. 2016 г., 19:21
@ Может, этот комментарий очень старый, но UICollectionView является подклассом UIScrollView, поэтому этот метод должен быть доступен.
Решение Вопроса

что Flow Layout не предназначен для поддержки подкачки страниц. Чтобы добиться эффекта пейджинга, вам придется пожертвовать пространством между клетками. И тщательно рассчитать рамку ячеек и сделать так, чтобы ее можно было разделить на рамки просмотра коллекции без остатков. Я объясню причину.

Сказать следующее расположение - это то, что вы хотели.

Обратите внимание, что самое левое поле (зеленое) не является частью интервала между ячейками. Это определяется вкладкой раздела макета потока. Поскольку макет потока не делаетt поддерживает разнородное значение расстояния. Это не тривиальная задача.

Поэтому после установки интервалов и вставок. Следующий макет - это то, что вы получите.

После прокрутки до следующей страницы. Ваши клетки явно не выровнены, как вы ожидали.

Задание интервала между ячейками 0 может решить эту проблему. Тем не менее, он ограничивает ваш дизайн, если вы хотите иметь дополнительное поле на странице, особенно если поле отличается от интервала между ячейками. Также требуется, чтобы рамка просмотра делилась на рамку ячейки. Иногда бывает неприятно, если ваша рамка обзора не зафиксирована (учитывая случай поворота).

Реальным решением является создание подкласса UICollectionViewFlowLayout и переопределение следующих методов
- (CGSize)collectionViewContentSize
{
    // Only support single section for now.
    // Only support Horizontal scroll 
    NSUInteger count = [self.collectionView.dataSource collectionView:self.collectionView
                                               numberOfItemsInSection:0];

    CGSize canvasSize = self.collectionView.frame.size;
    CGSize contentSize = canvasSize;
    if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal)
    {
        NSUInteger rowCount = (canvasSize.height - self.itemSize.height) / (self.itemSize.height + self.minimumInteritemSpacing) + 1;
        NSUInteger columnCount = (canvasSize.width - self.itemSize.width) / (self.itemSize.width + self.minimumLineSpacing) + 1;
        NSUInteger page = ceilf((CGFloat)count / (CGFloat)(rowCount * columnCount));
        contentSize.width = page * canvasSize.width;
    }

    return contentSize;
}


- (CGRect)frameForItemAtIndexPath:(NSIndexPath *)indexPath
{
    CGSize canvasSize = self.collectionView.frame.size;

    NSUInteger rowCount = (canvasSize.height - self.itemSize.height) / (self.itemSize.height + self.minimumInteritemSpacing) + 1;
    NSUInteger columnCount = (canvasSize.width - self.itemSize.width) / (self.itemSize.width + self.minimumLineSpacing) + 1;

    CGFloat pageMarginX = (canvasSize.width - columnCount * self.itemSize.width - (columnCount > 1 ? (columnCount - 1) * self.minimumLineSpacing : 0)) / 2.0f;
    CGFloat pageMarginY = (canvasSize.height - rowCount * self.itemSize.height - (rowCount > 1 ? (rowCount - 1) * self.minimumInteritemSpacing : 0)) / 2.0f;

    NSUInteger page = indexPath.row / (rowCount * columnCount);
    NSUInteger remainder = indexPath.row - page * (rowCount * columnCount);
    NSUInteger row = remainder / columnCount;
    NSUInteger column = remainder - row * columnCount;

    CGRect cellFrame = CGRectZero;
    cellFrame.origin.x = pageMarginX + column * (self.itemSize.width + self.minimumLineSpacing);
    cellFrame.origin.y = pageMarginY + row * (self.itemSize.height + self.minimumInteritemSpacing);
    cellFrame.size.width = self.itemSize.width;
    cellFrame.size.height = self.itemSize.height;

    if (self.scrollDirection == UICollectionViewScrollDirectionHorizontal)
    {
        cellFrame.origin.x += page * canvasSize.width;
    }

    return cellFrame;
}

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewLayoutAttributes * attr = [super layoutAttributesForItemAtIndexPath:indexPath];
    attr.frame = [self frameForItemAtIndexPath:indexPath];
    return attr;
}

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSArray * originAttrs = [super layoutAttributesForElementsInRect:rect];
    NSMutableArray * attrs = [NSMutableArray array];

    [originAttrs enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes * attr, NSUInteger idx, BOOL *stop) {
        NSIndexPath * idxPath = attr.indexPath;
        CGRect itemFrame = [self frameForItemAtIndexPath:idxPath];
        if (CGRectIntersectsRect(itemFrame, rect))
        {
            attr = [self layoutAttributesForItemAtIndexPath:idxPath];
            [attrs addObject:attr];
        }
    }];

    return attrs;
}

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

Кроме того, если вы неу меня миллионы клеток. Кэширование этих UICollectionViewLayoutAttributes может быть хорошей идеей.

 nikolsky26 апр. 2016 г., 06:59
Я думаю это'Сложное решение
 Rob Keniger27 нояб. 2013 г., 07:53
Это отличный ответ и единственный, который идеально подходит для меня. Благодарю.
 Jordan Montel19 мар. 2014 г., 10:48
Действительно хороший ответ. Для меня, сделать интервал между ячейками 0 решить мою проблему. Спасибо
 Sam19 июн. 2014 г., 00:55
Примечание: этот подход используетUICollectionViewFlowLayoutitemSize собственность, а неcollectionView:layout:sizeForItemAtIndexPath:
 Robert Mao29 апр. 2014 г., 06:33
Этот ответ плюс ответ ниже является полным ответом на этот вопрос. - (CGPoint) targetContentOffsetForProposedContentOffset: (CGPoint) предложилContentOffset withScrollingVelocity: (CGPoint) скорость
 Shobhit C15 мар. 2017 г., 06:13
Спас мой день. Этот метод является ключевым. func collectionView (_ collectionView: UICollectionView, макет collectionViewLayout: UICollectionViewLayout ,imumInteritemSpacingForSectionAt раздел: Int) -> CGFloat {return 0}

но я только что поиграл с этой проблемой и обнаружил, что причина дрейфамежстрочный интервал, Если вы хотитеUICollectionView / FlowLayout чтобы страница с точным кратным ширины вашей ячейки, вы должны установить:

UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout *)collectionView.collectionViewLayout;
flowLayout.minimumLineSpacing = 0.0;

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

В моем случае я экспериментировал с пейджингом слева направо, по одной ячейке за раз, без промежутков между ячейками. Каждый поворот страницы вносил незначительный сдвиг из желаемой позиции, и он, казалось, накапливался линейно.~ 10.0 очков за ход, Я реализовал10,0 значение по умолчаниюminimumLineSpacing в макете потока. Когда я установил его0.0без смещения, когда я установил его на половине ширины границ, каждая страница дрейфовала лишнюю половину границ.

ИзменениеminimumInteritemSpacing имелнет эффекта.

редактировать - из документации дляUICollectionViewFlowLayout:

@property (неатомный) CGFloatimumLineSpacing;

обсуждение

...

Для сетки с вертикальной прокруткой это значение представляет минимальный интервал между последовательными строками.Для горизонтально прокручиваемой сетки это значение представляет минимальный интервал между последовательными столбцами. Этот интервал не применяется к пробелу между заголовком и первой строкой или между последней строкой и нижним колонтитулом.

Значение по умолчанию этого свойства 10.0.

 SeanT25 февр. 2014 г., 20:58
Спасибо за это, у меня возникла та же проблема, когда я перелистывал страницу вправо, каждая страница становилась примерно на 10 пикселей дальше вправо. Это исправило это, и я никогда бы не подумал, что причиной будет межстрочный интервал.
 Shaked Sayag18 дек. 2016 г., 09:24
Спасибо!! Это можно сделать и в IB, в инспекторе размеров схемы потока.

@devdavid был замечен на flowLayout..

Это также можно сделать в редакторе макета, установив для параметра Min Spacing for Lines значение 0:

ширина в '320 + расстояние между», а затем установите разрешение страницы на да. это будет прокручивать320 + расстояние между» на каждый раз. я думаю это потому, что включение страницы будет прокручивать представлениеширина, а не экранширина s.

ный механизм горизонтальной прокрутки / пейджинга с пользовательской шириной / смещением страницы, например так:

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
    float pageWidth = 210;

    float currentOffset = scrollView.contentOffset.x;
    float targetOffset = targetContentOffset->x;
    float newTargetOffset = 0;

    if (targetOffset > currentOffset)
        newTargetOffset = ceilf(currentOffset / pageWidth) * pageWidth;
    else
        newTargetOffset = floorf(currentOffset / pageWidth) * pageWidth;

    if (newTargetOffset < 0)
        newTargetOffset = 0;
    else if (newTargetOffset > scrollView.contentSize.width)
        newTargetOffset = scrollView.contentSize.width;

    targetContentOffset->x = currentOffset;
    [scrollView setContentOffset:CGPointMake(newTargetOffset, 0) animated:YES];
}
 ClockWise26 нояб. 2015 г., 10:26
У меня тоже сработало, но это не такт очень гладко ... кто-нибудь есть идеи о том, как сделать его более гладким?
 chazzwozzer24 мар. 2014 г., 04:38
Это решение сработало для меня. Хотя анимация подкачки не такая плавная, как при обычной подкачке. Моя установка немного отличается. У меня есть два раздела, первый раздел имеет две ячейки, второй имеет одну ячейку. Сборник "Ширина s составляет 320 пикселей, но каждая ячейка имеет длину всего 216 пикселей без пробелов между каждой ячейкой и разделом. У меня есть содержимое вставки в моем представлении коллекции, так что ячейки всегда находятся в центре экрана, даже первая и последняя.

что все ячейки были равны 0, а их ширина и высота были точно такими же, как уUICollectionViewПейджинг былне правильно.

То, что я заметил, звучит как ошибка в этой версии (UICollectionView, iOS 6): я мог видеть это, если бы работал сUICollectionView с шириной = 310px или выше и высотой = 538px у меня были проблемы. Однако, если я уменьшу ширину, скажем, до 300 пикселей (той же высоты), все получится отлично!

Надеюсь, это поможет в будущем!

UICollectionViewFlowLayout

Если это так, добавив-(CGPoint) targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity поможет вам рассчитать, где прокрутка должна остановиться.

Это может работать (NB: UNTESTED!):

-(CGPoint) targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset
                             withScrollingVelocity:(CGPoint)velocity
{
  CGFloat offsetAdjustment = MAXFLOAT;
  CGFloat targetX = proposedContentOffset.x + self.minimumInteritemSpacing + self.sectionInset.left;

  CGRect targetRect = CGRectMake(proposedContentOffset.x, 0.0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);

  NSArray *array = [super layoutAttributesForElementsInRect:targetRect];
  for(UICollectionViewLayoutAttributes *layoutAttributes in array) {

    if(layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
      CGFloat itemX = layoutAttributes.frame.origin.x;

      if (ABS(itemX - targetX) < ABS(offsetAdjustment)) {
        offsetAdjustment = itemX - targetX;
      }
    }
  }

  return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y);
}
 Audun Kjelstrup13 нояб. 2012 г., 16:35
Отредактированный ответ, добавленный пример кода
 Michael Gaylord09 дек. 2015 г., 15:20
Мы внедрили и протестировали это, и это работает, за исключением одного небольшого изменения: вы должны убедиться, чтоproposedContentOffset.x + offsetAdjustment не является отрицательным, иначе первый элемент в собрании выигралт центр правильно.
 Devfly13 нояб. 2012 г., 15:28
Есть идеи, как мне сделать это с моим кодом?
 Devfly13 нояб. 2012 г., 20:43
Попробовал, и этоС другой стороны, но проблема сохраняется! Спасибо за ответ, а есть еще идеи?

UICollectionViewШирина s должна быть точным умножением ширины ячейки + левый и правый вкладыши. В вашем примере, если ширина ячейки равна 96, тоUICollectionViewширина должна быть(96 + 5 + 5) * 3 = 318, Или, если вы хотите сохранить UICollectionView 's 320 ширина, ваш размер ячейки должен быть.320 / 3 - 5 - 5 = 96.666

Если это не поможет, вашUICollectionViewШирина s может отличаться от указанной в xib-файле при запуске приложения. Чтобы проверить это - добавьтеNSLog заявление для распечатки представления "Размер s во время выполнения:

NSLog(@"%@", NSStringFromCGRect(uiContentViewController.view.frame));
 Devfly18 нояб. 2012 г., 15:12
Несмотря на то, что ширина моей коллекции равна 318, она все равно делает то же самое.
 gardenofwine18 нояб. 2012 г., 16:11
Из видео, которое вы разместили, похоже, что вы размещаетеUICollectionView внутри большего контейнера (пейзаж iPhone?). Возможно, этот контейнер изменяет размерUICollectionView? ВашUICollectionView имеет маску авторазмераUIViewAutoresizingFlexibleWidth, и он изменит размер, чтобы заполнить ширину контейнера. Можете ли вы вставить код, который вы используете, или иерархию представления из файла XIB?

что этот вопрос старый, но для тех, кто случайно наткнулся на это.

Все, что вам нужно сделать, чтобы исправить это, установить MinimumInterItemSpacing на 0 и уменьшить содержимое.кадр.

 H K27 авг. 2015 г., 01:38
^ это сработало для меня
 nr501 сент. 2017 г., 10:38
Это победилоработать, если я хочу, чтобы какая-то часть следующей ячейки была видна? Это будет работать только в том случае, если ширина ячейки совпадает с шириной коллекции, верно?
 Gaurav01 окт. 2013 г., 13:48
[flowLayout setMinimumInteritemSpacing: 0.0f]; [flowLayout setMinimumLineSpacing: -0.92f] Это работает для меня.

Ваш ответ на вопрос