IOS6の新機能を研究中に ICollectionView について質問がありました。
現在、フローレイアウトでテストし、スクロール方向を水平に設定し、スクロールとページングを有効にします。サイズをカスタムのセルとまったく同じに設定したので、一度に1つずつ表示できます。横にスクロールすると、ユーザーには他の既存のセルが表示されます。
完璧に機能します。
次に、作成したコレクションビューに IPageControl を追加して、表示されているセルとそこにあるセルの数を表示できるようにします。
ページコントロールの構築はかなり単純で、frameとnumberOfPagesが定義されていました。
質問のタイトルにあるように、私が抱えている問題は、どのセルが現在コレクションビューに表示されているかを取得する方法です。そのため、ページコントロールのcurrentPageを変更できます。
CellForItemAtIndexPathなどのデリゲートメソッドを試しましたが、セルを表示するのではなくロードするために作成されています。 didEndDisplayingCellは、セルが表示されなくなったときにトリガーします。これは、必要なものの反対のイベントです。
コレクションビューメソッドである-visibleCellsおよび-indexPathsForVisibleItemsが正しい選択であるように見えますが、別の問題にぶつかりました。それらをいつトリガーするか?
事前に感謝します。皆さんが私を理解できるように、私が十分に明確にしたことを願っています!
自分でUIScrollViewDelegate
として設定し、scrollViewDidEndDecelerating:
methodのように:
Objective-C
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
CGFloat pageWidth = self.collectionView.frame.size.width;
self.pageControl.currentPage = self.collectionView.contentOffset.x / pageWidth;
}
スイフト
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageWidth = self.collectionView.frame.size.width
pageControl.currentPage = Int(self.collectionView.contentOffset.x / pageWidth)
}
私もこれにしばらく苦労しましたが、UICollectionViewの親クラスをチェックアウトすることをお勧めしました。それらの1つはたまたま IScrollView であり、自分を IScrollViewDelegate として設定すると、scrollViewDidEndDeceleratingなどの非常に便利なメソッドにアクセスできます、UIPageControlを更新するのに最適な場所です。
スクロール位置ですぐにページ制御をより正確に更新するため、少し調整した計算と処理をお勧めします。
以下のソリューションは、任意のスクロールビューまたはそのサブクラス(UITableView UICollectionViewなど)で動作します
viewDidLoadメソッドでこれを書く
scrollView.delegate = self
次に、言語のコードを使用します。
スイフト3
func scrollViewDidScroll(_ scrollView: UIScrollView)
{
let pageWidth = scrollView.frame.width
pageControl.currentPage = Int((scrollView.contentOffset.x + pageWidth / 2) / pageWidth)
}
スイフト2:
func scrollViewDidScroll(scrollView: UIScrollView)
{
let pageWidth = CGRectGetWidth(scrollView.frame)
pageControl.currentPage = Int((scrollView.contentOffset.x + pageWidth / 2) / pageWidth)
}
客観的C
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat pageWidth = self.collectionView.frame.size.width;
self.pageControl.currentPage = (self.collectionView.contentOffset.x + pageWidth / 2) / pageWidth;
}
コードが少ない別のオプションは、表示可能なアイテムインデックスパスを使用し、ページコントロールを設定することです。
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
self.pageControl.currentPage = [[[self.collectionView indexPathsForVisibleItems] firstObject] row];
}
int pages = floor(ImageCollectionView.contentSize.width/ImageCollectionView.frame.size.width); [pageControl setNumberOfPages:pages];
ScrollView Delegateメソッドを追加し、
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
CGFloat pageWidth = ImageCollectionView.frame.size.width;
float currentPage = ImageCollectionView.contentOffset.x / pageWidth;
if (0.0f != fmodf(currentPage, 1.0f))
{
pageControl.currentPage = currentPage + 1;
}
else
{
pageControl.currentPage = currentPage;
}
NSLog(@"finishPage: %ld", (long)pageControl.currentPage);
}
私はこれが古いものであることを知っていますが、この種の機能を再度実装する必要があり、より完全な答えを与えるために少し追加する必要があります。
まず:scrollViewDidEndDecelerating
の使用は、ユーザーがドラッグ中に指を持ち上げた(よりフリックアクションに近い)ため、減速フェーズがあることを前提としています。ユーザーが指を離さずにドラッグすると、UIPageControl
はドラッグが開始される前の古いページを示します。代わりにscrollViewDidScroll
コールバックを使用するということは、ドラッグとフリックの後、およびドラッグとスクロール中の両方でビューが更新されるため、ユーザーの応答性と正確さが大幅に向上します。
2番目に:選択されたインデックスの計算にpagewidth
を使用する場合、すべてのセルの幅が同じであり、画面ごとに1つのセルがあると仮定します。 indexPathForItemAtPoint
でUICollectionView
メソッドを利用すると、さまざまなレイアウトとセルサイズで機能する、より弾力性のある結果が得られます。以下の実装では、フレームの中心がpagecontrol
で表される目的のセルであると想定しています。また、セル間スペースがある場合、スクロール中にselectedIndexがnilまたはオプションになる可能性があるため、pageControlで設定する前にこれをチェックしてアンラップする必要があります。
func scrollViewDidScroll(scrollView: UIScrollView) {
let contentOffset = scrollView.contentOffset
let centrePoint = CGPointMake(
contentOffset.x + CGRectGetMidX(scrollView.frame),
contentOffset.y + CGRectGetMidY(scrollView.frame)
)
if let index = self.collectionView.indexPathForItemAtPoint(centrePoint){
self.pageControl.currentPage = index.row
}
}
もう1つ-UIPageControl
のページ数を次のように設定します。
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
self.pageControl.numberOfPages = 20
return self.pageControl.numberOfPages
}
シンプルなスイフト
public func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
pageControl.currentPage = (collectionView.indexPathsForVisibleItems().first?.row)!
}
UIScrollViewDelegate
を実装している場合、UICollectionViewDelegate
はすでに実装されています