Objective c iOS6 UICollectionView和UIPageControl-如何获取可见单元格?
在研究iOS6的新功能时,我遇到了一个问题。Objective c iOS6 UICollectionView和UIPageControl-如何获取可见单元格?,objective-c,ios,ios6,Objective C,Ios,Ios6,在研究iOS6的新功能时,我遇到了一个问题。 我目前正在使用Flow layout和滚动方向设置为水平、滚动和分页功能对其进行测试。我已经将它的大小设置为与我的自定义单元格完全相同,因此它可以一次显示一个单元格,通过横向滚动,用户可以看到其他现有单元格 它工作得很好 现在我想在我创建的集合视图中添加和,这样它就可以显示哪个单元格是可见的,以及有多少个单元格 构建页面控件非常简单,定义了框架和页面数 我遇到的问题,如问题标题所示,是如何获取集合视图中当前可见的单元格,以便它可以更改页面控件的cur
我目前正在使用Flow layout和滚动方向设置为水平、滚动和分页功能对其进行测试。我已经将它的大小设置为与我的自定义单元格完全相同,因此它可以一次显示一个单元格,通过横向滚动,用户可以看到其他现有单元格 它工作得很好 现在我想在我创建的集合视图中添加和,这样它就可以显示哪个单元格是可见的,以及有多少个单元格 构建页面控件非常简单,定义了框架和页面数 我遇到的问题,如问题标题所示,是如何获取集合视图中当前可见的单元格,以便它可以更改页面控件的currentPage
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
self.pageControl.currentPage = [[[self.collectionView indexPathsForVisibleItems] firstObject] row];
}
我尝试过委托方法,比如cellForItemAtIndexPath,但它是用来加载单元格的,而不是显示它们。didEndDisplayingCell在一个单元格不再显示时触发,这与我需要的相反
对于我来说,-visibleCells和-indexPathsForVisibleItems(集合视图方法)似乎是正确的选择,但我遇到了另一个问题。什么时候触发它们
提前谢谢,希望我说得够清楚,让你们能理解我 我也为此挣扎了一段时间,然后有人建议我查看UICollectionView的父类。其中一个恰好是,如果您将自己设置为,您可以访问非常有用的方法,例如ScrollViewDiEndDecelling,这是更新UIPageControl的好地方。您必须将自己设置为
UIScrollViewDelegate
并实现ScrollViewDiEndDecelling:
方法,如下:
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
}
}
目标-C
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
CGFloat pageWidth = self.collectionView.frame.size.width;
self.pageControl.currentPage = self.collectionView.contentOffset.x / pageWidth;
}
Swift
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageWidth = self.collectionView.frame.size.width
pageControl.currentPage = Int(self.collectionView.contentOffset.x / pageWidth)
}
我会推荐一个小调整的计算和处理,因为它将更新页面控制立即在任何滚动位置与更好的准确性 下面的解决方案适用于任何滚动视图或it子类(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)
}
Swift 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];
}
简捷
public func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
pageControl.currentPage = (collectionView.indexPathsForVisibleItems().first?.row)!
}
如果您实现了
UICollectionViewDelegate
,则已经实现了uicrollViewDelegate
,我知道这是一个旧的,但我只需要再次实现这种功能,并添加一些内容,以提供更完整的答案
首先:使用ScrollViewDiEndDecreating
假设用户在拖动时抬起手指(更像是轻弹动作),因此存在减速阶段。如果用户在不抬起手指的情况下拖动,则UIPageControl
仍将指示拖动开始前的旧页面。相反,使用scrollViewDidScroll
回调意味着视图在拖动和轻弹之后以及拖动和滚动期间都会更新,因此用户感觉它的响应性和准确性更高
其次:依靠pagewidth
计算所选索引时,假设所有单元格的宽度相同,并且每个屏幕有一个单元格。利用UICollectionView
上的indexPathForItemAtPoint
方法,可以获得更具弹性的结果,适用于不同的布局和单元格大小。下面的实现假设帧的中心是要在页面控件中表示的所需单元格。此外,如果存在单元格间距,则在滚动期间,selectedIndex可能为零或可选,因此在页面控件上进行设置之前,需要检查并取消包装
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
上的页数:
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
self.pageControl.numberOfPages = 20
return self.pageControl.numberOfPages
}
如果使用scrollViewDidScroll
,则应手动更新页面控件以⚠️ 点击页面控件时,避免闪烁的点
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
self.pageControl.currentPage = [[[self.collectionView indexPathsForVisibleItems] firstObject] row];
}
设置ui页面控件
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)
执行操作(使用下面的扩展)
在每个滚动条上手动更新ui页面控件
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
)
}
}
无需为CollectionView创建IVAR:-(void)ScrollViewDiEndDecelling:(UIScrollView*)scrollView{CGFloat pageWidth=\u tutorialCollectionViewFrame.size.width;\u pageControl.currentPage=scrollView.contentOffset.x/pageWidth;}
是的正确答案…:func ScrollViewDiEndDecelling(scrollView:UIScrollView){let pageWidth:CGFloat=self.collectionView.frame.size.width self.pageControl.currentPage=Int(self.collectionView.contentOffset.x/pageWidth)}我发现改用scrollViewDidScroll会更流畅,因为理论上你可以在不更新pageControl的情况下左右滚动,直到它停止减速为止。我的代码如下所示:func scrollViewDidScroll(scrollView:UIScrollView){let page=Int(round(self.collectionView.contentOffset.x/self.collectionView.frame.size.width))如果self.pageControl.currentPage!=page{self.pageControl.currentPage=page}我向UIViewController添加了委托b