簡體   English   中英

iOS6 UICollectionView 和 UIPageControl - 如何獲取可見單元格?

[英]iOS6 UICollectionView and UIPageControl - How to get visible cell?

在學習 iOS6 新功能時,我有一個關於UICollectionView的問題。
我目前正在使用 Flow 布局和滾動方向設置為水平、滾動和分頁來測試它。 我已將其大小設置為與我自定義的單元格完全相同,因此它可以一次顯示一個,並且通過將其向側面滾動,用戶將看到其他現有單元格。

它完美地工作。

現在我想將UIPageControl添加到我創建的集合視圖中,以便它可以顯示哪個單元格可見以及有多少個單元格。

構建頁面控件相當簡單,frame 和 numberOfPages 已定義。

正如問題標題所標記的,我遇到的問題是如何獲取當前在集合視圖中可見的單元格,以便它可以更改頁面控件的 currentPage。

我試過委托方法,比如 cellForItemAtIndexPath,但它是用來加載單元格的,而不是顯示它們。 didEndDisplayingCell 在單元格不再顯示時觸發,這是我需要的相反事件。

看起來集合視圖方法 -visibleCells 和 -indexPathsForVisibleItems 是我的正確選擇,但我遇到了另一個問題。 什么時候觸發它們?

在此先感謝,希望我說得足夠清楚,以便你們能理解我!

您必須將自己設置為UIScrollViewDelegate並實現scrollViewDidEndDecelerating:方法,如下所示:

目標-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 的父類。 其中之一恰好是UIScrollView ,如果您將自己設置為UIScrollViewDelegate ,您就可以訪問非常有用的方法,例如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];
}
  1. PageControl放在您的視圖中或由代碼設置。
  2. 設置UIScrollViewDelegate
  3. Collectionview -> cellForItemAtIndexPath (Method) 中添加以下代碼來計算頁數,

int pages =floor(ImageCollectionView.contentSize.width/ImageCollectionView.frame.size.width); [pageControl setNumberOfPages:pages];

添加ScrollView 委托方法,

pragma mark - UIScrollVewDelegate 用於 UIPageControl

- (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回調意味着視圖在拖動和輕彈之后以及在拖動和滾動期間都會更新,因此對用戶來說感覺更加靈敏和准確。

其次:依托pagewidth ,用於計算所選索引假定所有單元具有相同的寬度,並且有每屏一個小區。 取的優點indexPathForItemAtPoint上方法UICollectionView給出了一個更有彈性的結果,這將對於不同的布局和小區大小工作。 下面的實現假設框架的中心是要在pagecontrol表示的所需單元格。 此外,如果在滾動期間有單元格間距,則 selectedIndex 可能為零或可選,因此需要在設置 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
   }
 }

還有一件事 - 使用以下內容設置UIPageControl上的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)!
}

如果你實現了UICollectionViewDelegate就已經實現了UIScrollViewDelegate

如果使用scrollViewDidScroll ,則應手動更新頁面控件以 ⚠️避免點擊頁面控件時出現閃爍的點

設置UIPageControl

let pageControl = UIPageControl()
pageControl.pageIndicatorTintColor = .label
pageControl.defersCurrentPageDisplay = true // Opt-out from automatic display
pageControl.numberOfPages = viewModel.items.count
pageControl.addTarget(self, action: #selector(pageControlValueChanged), for: .valueChanged)

實施操作(使用下面的擴展)。

@objc func pageControlValueChanged(_ sender: UIPageControl) {
    collectionView.scroll(to: sender.currentPage)
}

在每次滾動時手動更新UIPageControl

extension ViewController: UIScrollViewDelegate {
        
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        pageControl.currentPage = collectionView.currentPage
        pageControl.updateCurrentPageDisplay() // Display only here
    }
}

UICollectionView擴展。

extension CGRect {
    
    var middle: CGPoint {
        CGPoint(x: midX, y: midY)
    }
}

extension UICollectionView {
    
    var visibleArea: CGRect {
        CGRect(origin: contentOffset, size: bounds.size)
    }
    
    var currentPage: Int {
        indexPathForItem(at: visibleArea.middle)?.row ?? 0
    }
    
    func scroll(to page: Int) {
        scrollToItem(
            at: IndexPath(row: page, section: 0),
            at: .centeredHorizontally,
            animated: true
        )
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM