UICollectionView автоматична прокрутка до комірки на IndexPath


101

Перед завантаженням перегляду колекції користувач встановлює кількість зображення в масиві подання колекції. Усі комірки не вміщуються на екрані. У мене 30 екранів і лише 6 на екрані.

Питання: Як автоматично прокручувати до комірки з потрібним зображенням при завантаженні UICollectionView?

Відповіді:


90

Я виявив, що прокрутка viewWillAppearможе не працювати надійно, оскільки представлення колекції ще не закінчило її макет; ви можете прокрутити до неправильного елемента.

Я також виявив, що прокручування viewDidAppearпризведе до того, що миттєво буде видно некрольований вид.

І якщо ви прокручуєте кожен раз viewDidLayoutSubviews, користувач не зможе вручну прокручувати, оскільки деякі макети колекції викликають макет підперегляду кожного разу, коли ви прокручуєте.

Ось що я знайшов роботи надійно:

Мета C:

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    // If we haven't done the initial scroll, do it once.
    if (!self.initialScrollDone) {
        self.initialScrollDone = YES;

        [self.collectionView scrollToItemAtIndexPath:self.myInitialIndexPath
                                    atScrollPosition:UICollectionViewScrollPositionRight animated:NO];
    }
}

Швидкий:

 override func viewWillLayoutSubviews() {

    super.viewWillLayoutSubviews()

      if (!self.initialScrollDone) {

         self.initialScrollDone = true
         self.testNameCollectionView.scrollToItem(at:selectedIndexPath, at: .centeredHorizontally, animated: true)
    }

}

Гарна порада. Я наголошу на використанні initialScrollDoneпрапора, як це робив LenK, оскільки цей метод буде викликатись не один раз, і якщо ви будете викликати scrollToItemAtIndexPath: не раз здається, що колекціяVView може бути некерованою (iOS-симулятор iPhone 5 / iOS 8)
maz

1
Чудово працює в iOS8. Повинна бути прийнята відповідь.
Нік

5
Це не спрацювало для мене в iOS 8.3. Довелося зателефонувати [self.collectionView layoutIfNeeded];раніше, що також працює, коли ви робите це всередині viewDidLoad.
Брент Діллінгем

1
Це безумовно має бути прийнятою відповіддю. Відповідь, подана вище, дала мені спалах, коли перша клітина була показана, а потім оновлена ​​моєю новою коміркою, цей метод переходить безперешкодно.
simon_smiley

це також працює на iOS 9, а також не псує мою автоматичну компоновку.
Містер Zystem

168

Нова відредагована відповідь:

Додайте це до viewDidLayoutSubviews

SWIFT

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    let indexPath = IndexPath(item: 12, section: 0)
    self.collectionView.scrollToItem(at: indexPath, at: [.centeredVertically, .centeredHorizontally], animated: true)
}

Зазвичай .centerVerticallyце так

ObjC

-(void)viewDidLayoutSubviews {
   [super viewDidLayoutSubviews];
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:12 inSection:0];
   [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically | UICollectionViewScrollPositionCenteredHorizontally animated:NO];
}

Стара відповідь, що працює для старих iOS

Додайте це до viewWillAppear:

[self.view layoutIfNeeded];
[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO];

4
Саме це я і намагаюся використовувати. Я маю номер об’єкта в масиві, і я знаю ім'я цього об’єкта. Але не знаєте, як правильно поставити indexPath ... Будь-які ідеї?
AlexanderZ

4
Ви можете легко створити indexPath:[NSIndexPath indexPathForItem:numberOfTheObject inSection:sectionNumber]
boweidmann

3
Були деякі помилки. Але потім я поставив увесь згаданий код всередині (void) viewDidLayoutSubviews {} і тепер він працює добре. Дякую Богдану.
AlexanderZ

1
Як я можу «збільшити масштаб» у клітинку та показати її збільшеною?
фатухоку

9
Це не працює надійно на iOS 7.1 і може призвести до того, що представлення колекції з’явиться як чорний екран. Я також не хотів підтримувати такий стан, як рішення у viewDidLayoutSubviews нижче. Що я зробив, це просто виконано [self.view layoutIfNeeded] безпосередньо перед викликом прокруткиToItemAtIndexPath
Даніель Галаско,

15

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

viewDidAppear 
{
    [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES];
}

Коли я використовував viewWillAppear, прокрутка не працювала.


2
viewDidAppear має недолік у тому, що ви бачите перегляд / миготливий вигляд колекції, вигляд вже з'явився (як випливає з назви) ... Мені справді цікаво, чому Apple не спроектувала цей не такий незвичний вигляд у приємніший спосіб, спосіб viewDidLayoutSubviews - це трохи незручно
TheEye

12

це, здавалося, працює для мене, схоже на іншу відповідь, але має деякі чіткі відмінності:

- (void)viewDidLayoutSubviews
{     
   [self.collectionView layoutIfNeeded];
   NSArray *visibleItems = [self.collectionView indexPathsForVisibleItems];
   NSIndexPath *currentItem = [visibleItems objectAtIndex:0];
   NSIndexPath *nextItem = [NSIndexPath indexPathForItem:someInt inSection:currentItem.section];

   [self.collectionView scrollToItemAtIndexPath:nextItem atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
}

12

Швидкий:

your_CollectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: UICollectionViewScrollPosition.CenteredHorizontally, animated: true)

Швидкий 3

let indexPath = IndexPath(row: itemIndex, section: sectionIndex)

collectionView.scrollToItem(at: indexPath, at: UICollectionViewScrollPosition.right, animated: true)

Положення прокрутки:

UICollectionViewScrollPosition.CenteredHorizontally / UICollectionViewScrollPosition.CenteredVertically

9

Ви можете використовувати GCD для відправки прокрутки до наступної ітерації циклу основного запуску в viewDidLoad для досягнення цієї поведінки. Прокрутка буде виконуватися до того, як на екрані буде показано подання колекції, тому миготіння не буде.

- (void)viewDidLoad {
    dispatch_async (dispatch_get_main_queue (), ^{
        NSIndexPath *indexPath = YOUR_DESIRED_INDEXPATH;
        [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
    });
}

як пройти покажчик, коли позиція 3?
kemdo

5

Я рекомендую зробити це в collectionView: willDisplay:Тоді ви можете бути впевнені, що делегат представлення колекції щось доставляє. Ось мій приклад:

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    /// this is done to set the index on start to 1 to have at index 0 the last image to have a infinity loop
    if !didScrollToSecondIndex {
        self.scrollToItem(at: IndexPath(row: 1, section: 0), at: .left, animated: false)
        didScrollToSecondIndex = true
    }
}

1
Я виявив, що використання didEndDisplaying замість willDisplay було способом змусити це правильно працювати. willDisplay був у порядку, поки клітина була на екрані; однак, якщо комірка ще не була на екрані, цей метод не прокручував мене до неї. didEndDisplaying, хоча працював ідеально для цього випадку використання. Вдячний за те, що відповідь поставив мене на правильний шлях!
C6Silver

2

Як альтернатива згаданому вище. Дзвінок після завантаження даних:

Швидкий

collectionView.reloadData()
collectionView.layoutIfNeeded()
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: .right)

1

Усі відповіді тут - хаки. Я знайшов кращий спосіб прокручувати подання колекції десь після relaodData:
макет перегляду колекції підкласів, який макет ви використовуєте, метод переопределення PrepaLayout, після встановлення супервиклику встановити те, що колись потрібно компенсувати.
напр .: https://stackoverflow.com/a/34192787/1400119

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.