現在、各セルがフルスクリーンである水平ページングを行うコレクションビューがあります。私がしたいのは、コレクションビューが表示されたときに特定のインデックスで開始することです。
現在、私はscrollToItemAtIndexPath:atScrollPosition:animated:を使用しており、animatedをNOに設定していますが、特定のアイテムにスクロールする前に最初のインデックスを最初にロードします。また、このメソッドはViewDidAppearでしか使用できないため、最初のセルを表示してから、表示したいセルに点滅します。スクロールが完了するまでコレクションビューを非表示にすることでこれを非表示にしますが、理想的ではないようです。
私が説明した方法以外にこれを行うより良い方法はありますか?
ありがとう!
そこで、UICollectionViewDelegate
メソッドと1回限りのBool
を使用して、これを別の方法で解決しました。
スイフト2:
var onceOnly = false
internal func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
if !onceOnly {
let indexToScrollTo = NSIndexPath(forRow: row, inSection: section)
self.problemListCollectionView.scrollToItemAtIndexPath(indexToScrollTo, atScrollPosition: .Left, animated: false)
onceOnly = true
}
}
スウィフト3:
var onceOnly = false
internal func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if !onceOnly {
let indexToScrollTo = IndexPath(item: row, section: section)
self.problemListCollectionView.scrollToItem(at: indexToScrollTo, at: .left, animated: false)
onceOnly = true
}
}
このコードは、アニメーションが発生する前に実行されるため(実際にこの時点までロードされます)、viewDidAppear
を呼び出すよりも優れており、viewWillAppear
で成功しませんでした。
この問題を解決するために、 greenhouse 回答を部分的に使用しました。
/// Edit
var startIndex: Int! = 0
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
collectionView.setNeedsLayout()
collectionView.layoutIfNeeded()
collectionView.scrollToItemAtIndexPath(
NSIndexPath(forItem: 0, inSection: startIndex),
atScrollPosition: .None,
animated: false)
}
問題は、間違ったcollectionView
サイズにあるようです。レイアウトを設定した後、scrollToItemAtIndexPath
は必要な結果を生成します。
また、この問題はCollection View
はUIViewController
内で使用されます。
残念ながら、これらの既存の回答のすべてが、少なくとも部分的に間違っているか、尋ねられている正確な質問に答えていません。私は、これらの回答のいずれにも助けられなかった同僚とこの問題を解決しました。
必要なことは、アニメーションなしのコンテンツオフセットを正しいコンテンツオフセットに設定してから、リロードデータを呼び出すことだけです。 (または、まだ読み込まれていない場合はreloadData呼び出しをスキップします。)最初のセルを作成したくない場合は、viewDidLoadでこれを行う必要があります。
この答えは、コレクションビューが水平にスクロールし、セルのサイズがビューと同じサイズであると仮定していますが、垂直にスクロールしたい場合やセルが異なるサイズである場合、概念は同じです。また、CollectionViewに複数のセクションがある場合は、コンテンツオフセットを計算するためにもう少し計算する必要がありますが、概念は同じです。
func viewDidLoad() {
super.viewDidLoad()
let pageSize = self.view.bounds.size
let contentOffset = CGPoint(x: pageSize.width * self.items.count, y: 0)
self.collectionView.setContentOffset(contentOffset, animated: false)
}
Swift 3.0はテスト済みで動作します。
var onceOnly = false
internal func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if !onceOnly {
//set the row and section you need.
let indexToScrollTo = IndexPath(row: 1, section: indexPath.section)
self.fotmCollectionView.scrollToItem(at: indexToScrollTo, at: .left, animated: false)
onceOnly = true
}
}
これは私にとってはうまくいくようです:
- (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];
}
IndexPathを最初のVC=からDidSelectItemAtIndexPathメソッドのコレクションビューに渡します。コレクションビューのviewDidLoadで、メソッドscrollToItemAtIndexPath:atScrollPosition:animated:
Set animated
to NO
and atScrollPosition
to UICollectionViewScrollPositionNone
。このように:
[self.collectionView scrollToItemAtIndexPath:self.indexPathFromVC atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
他の人に触発されたシンプルなソリューション:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
DispatchQueue.main.async {
self.collectionView.scrollToItem(at: lastIndexPath, section: 0), at: .centeredHorizontally, animated: false)
}
}
コードをDispatchQueue.main.asyncブロック内に配置すると機能します。
ここに私のために働いたものがあります(UICollectionViewControllerクラスで):
private var didLayoutFlag: Bool = false
public override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let collectionView = self.collectionView {
if !self.didLayoutFlag {
collectionView.scrollToItemAtIndexPath(self.viewModel.initialIndexPath, atScrollPosition: .None, animated: false)
self.didLayoutFlag = true
}
}
}
ちょっと私はObjective Cで解決しました。これはあなたにとって役に立つと思います。 Objective CをSwiftにも変換できます。ここに私のコードがあります:
**私の場合、[オン]ボタンをクリックすると、特定のインデックス、つまり3が有効になります**
垂直用
- (IBAction)Click:(id *)sender {
NSInteger index=3;
CGFloat pageHeight = self.collectionView.frame.size.height;
CGPoint scrollTo = CGPointMake(0, pageHeight * index);
[self.collectionView setContentOffset:scrollTo animated:YES];
}
水平用
- (IBAction)Click:(id *)sender {
NSInteger index=3;
CGFloat pageWidth = self.collectionView.frame.size.width;
CGPoint scrollTo = CGPointMake(pageWidth * index, 0);
[self.collectionView setContentOffset:scrollTo animated:YES];
}
それがあなたに役立つことを願っています。
この同じ問題を抱えてここに来て、私の場合、この問題はストーリーボードのViewControllerが「フリーフォーム」サイズに設定されていることが原因であることがわかりました。
ストーリーボードのサイズが不明な場合、ビューが最初に読み込まれるときにviewWillLayoutSubviewsが呼び出されて正しいサイズが計算されると思います。 (ストーリーボードのviewControllerのサイズを「フリーフォーム」に設定したため、collectionView内の長いtableViewの多くのセルを表示/編集できるように非常に背の高いものにできました)。
私は、victor.vasilicaと温室のアプローチがre: 'scrollToRow'コマンドをviewWillLayoutSubviewsに入れることで問題を修正するために完全に機能することを発見しました。
ただし、ストーリーボードの「固定」サイズでVCを再度作成すると、問題はすぐになくなり、viewWillAppearから初期セルを設定できるようになりました。異なっていますが、これは私の状況で何が起こっているのかを理解するのに役立ち、私の答えがこの問題を他の人に知らせるのに役立つことを願っています。