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)
    }

}

いいヒント。initialScrollDoneLenKが行ったようにフラグを使用することを強調します。このメソッドは複数回呼び出され、scrollToItemAtIndexPathを呼び出すと、collectionViewをスクロールできないように見えるようになるためです(iOSシミュレーターiPhone 5 / iOS 8)
maz

1
iOS8でうまく動作します。受け入れられる答えでなければなりません。
Nick

5
これはiOS 8.3では機能しませんでした。[self.collectionView layoutIfNeeded];前に呼び出す必要がありましたviewDidLoad。これは、内でこれを行うときにも機能します。
ブレントディリンガム、2015年

1
これは間違いなく受け入れられる答えになるはずです。上記の答えは、最初のセルが表示された後、新しいセルで更新され、このメソッドはシームレスに移行するので、私にフラッシュを与えました。
simon_smiley

これはiOS 9でも機能し、自動レイアウトを台無しにすることもありません。
Zystem氏、2015年

168

新しい、編集された回答:

これを追加 viewDidLayoutSubviews

迅速

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
セルを「拡大」して拡大表示するにはどうすればよいですか?
fatuhoku 2014

9
これはiOS 7.1では確実に動作せず、コレクションビューが黒い画面として表示される可能性があります。また、以下のviewDidLayoutSubviewsのソリューションのような状態を維持したくありませんでした。私が行ったことは、scrollToItemAtIndexPathを呼び出す直前に[self.view layoutIfNeeded]を実行するだけです
Daniel Galasko

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のときにindexpathを取得する方法
kemdo 2018年

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
willDisplayの代わりにdidEndDisplayingを使用することが、これを適切に機能させる方法であることがわかりました。セルが画面上にある限り、willDisplayは問題ありませんでした。ただし、セルがまだ画面上にない場合は、このメソッドでセルがスクロールされませんでした。ただし、didEndDisplayingはそのユースケースでは完全に機能しました。私を正しい道に導いてくれたあなたの答えに感謝します!
C6Silver 2018

2

上記の代替として。データ読み込み後に呼び出す:

迅速

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.