Подтвердить что ты не робот

Программно прокрутите до дополнительного вида в UICollectionView

Я использую UICollectionView для отображения фотографий в разделах. Каждый раздел имеет дополнительное представление в виде заголовка и поставляется с помощью метода: viewForSupplementaryElementOfKind.

У меня есть скруббер сбоку, который позволяет пользователю перейти от раздела к разделу. На данный момент я прокручиваю первый элемент в разделе с помощью scrollToItemAtIndexPath:atScrollPosition:animated:, но я действительно хочу прокрутить коллекцию, чтобы заголовок этого раздела находился в верхней части экрана, а не в первой ячейке. Я не вижу очевидного метода для этого. У кого-нибудь из вас есть работа?

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

Спасибо.

4b9b3361

Ответ 1

Вы не можете использовать scrollToItemAtIndexPath:atScrollPosition:animated для этого.

Надеемся, что в будущем они добавят новый метод, например scrollToSupplementaryElementOfKind:atIndexPath:, но , единственный способ - напрямую манипулировать contentOffset.

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

NSIndexPath *indexPath = ... // indexPath of your header, item must be 0

CGFloat offsetY = [collectionView layoutAttributesForSupplementaryElementOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath].frame.origin.y;

CGFloat contentInsetY = self.contentInset.top;
CGFloat sectionInsetY = ((UICollectionViewFlowLayout *)collectionView.collectionViewLayout).sectionInset.top;

[collectionView setContentOffset:CGPointMake(collectionView.contentOffset.x, offsetY - contentInsetY - sectionInsetY) animated:YES];

Обратите внимание, что если у вас есть ненулевой contentInset (как в iOS 7, когда прокрутки отображаются ниже баров), вы должны вычесть его из offsetY, как показано. То же самое для sectionInset.

Update:

В коде предполагается, что макет находится в подготовленном состоянии "valid", потому что он использует его для вычисления смещения. Макет подготовлен, когда представление коллекции представляет его содержимое.

Вызов [_collectionView.collectionViewLayout prepareLayout] перед кодом выше может помочь, когда вам нужно прокрутить представление коллекции, которое еще не представлено (из viewDidLoad say). Вызов layoutIfNeeded (как @Vrasidas, предложенный в комментариях) должен работать, потому что он также подготавливает макет.

Ответ 2

Решение в Swift,

let section: = 0 // Top
if let cv = self.collectionView {

    cv.layoutIfNeeded()

    let indexPath = NSIndexPath(forItem: 1, inSection: section)
    if let attributes =  cv.layoutAttributesForSupplementaryElementOfKind(UICollectionElementKindSectionHeader, atIndexPath: indexPath) {

        let topOfHeader = CGPointMake(0, attributes.frame.origin.y - cv.contentInset.top)
        cv.setContentOffset(topOfHeader, animated:true)
    }
}

Реквизит для Gene De Lisa: http://www.rockhoppertech.com/blog/scroll-to-uicollectionview-header/

Ответ 3

// scroll to selected index
NSIndexPath* cellIndexPath = [NSIndexPath indexPathForItem:0 inSection:sectionIndex];
UICollectionViewLayoutAttributes* attr = [self.collectionView.collectionViewLayout layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:cellIndexPath];
UIEdgeInsets insets = self.collectionView.scrollIndicatorInsets;

CGRect rect = attr.frame;
rect.size = self.collectionView.frame.size;
rect.size.height -= insets.top + insets.bottom;
CGFloat offset = (rect.origin.y + rect.size.height) - self.collectionView.contentSize.height;
if ( offset > 0.0 ) rect = CGRectOffset(rect, 0, -offset);

[self.collectionView scrollRectToVisible:rect animated:YES];

Ответ 4

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

В этом случае вам нужно взять вышеописанные методы и немного их отрегулировать. Например:

UICollectionView *cv = self.collectionView;
CGFloat contentInsetY = cv.contentInset.top;
CGFloat offsetY = [cv layoutAttributesForItemAtIndexPath:ip].frame.origin.y;
CGFloat sectionHeight =
[cv layoutAttributesForSupplementaryElementOfKind:UICollectionElementKindSectionHeader atIndexPath:ip].frame.size.height;
[cv setContentOffset:CGPointMake(cv.contentOffset.x, offsetY - contentInsetY - sectionHeight) animated:YES];

Теперь вы в основном прокручиваете первую строку своего раздела до видимой, меньше высоты заголовка раздела. Это поместит заголовок раздела сверху, где вы хотите его с закрепленными заголовками, чтобы направление прокрутки больше не имело значения. Я не тестировал секционные вставки.