我是第一次在我的 iPad 应用程序中使用 UICollectionView
。我已设置 UICollectionView
使其大小和单元格大小相同,这意味着一次只显示一次单元格。
问题: 现在,当用户滚动 UICollectionView
时,我需要知道哪个单元格可见,我必须在更改时更新其他 UI 元素。我没有找到任何委托方法。我怎样才能做到这一点?
代码:
[self.mainImageCollection setTag:MAIN_IMAGE_COLLECTION_VIEW];
[self.mainImageCollection registerClass:[InspirationMainImageCollectionCell class] forCellWithReuseIdentifier:@"cellIdentifier"];
[self.mainImageFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[self.mainImageFlowLayout setMinimumInteritemSpacing:0.0f];
[self.mainImageFlowLayout setMinimumLineSpacing:0.0f];
self.mainImageFlowLayout.minimumLineSpacing = 0;
[self.mainImageCollection setPagingEnabled:YES];
[self.mainImageCollection setShowsHorizontalScrollIndicator:NO];
[self.mainImageCollection setCollectionViewLayout:self.mainImageFlowLayout];
我试过的:
由于 UICollectionView
符合 UIScrollView
,当用户滚动以 UIScrollViewDelegate
方法结束时,我得到了
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
但是在上面的函数中,我怎样才能获得 UICollectionView
的当前可见单元格索引?
indexPathsForVisibleItems
可能适用于大多数情况,但有时它会返回一个包含多个索引路径的数组,并且很难找出您想要的那个。在这些情况下,您可以执行以下操作:
CGRect visibleRect = (CGRect){.origin = self.collectionView.contentOffset, .size = self.collectionView.bounds.size};
CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect));
NSIndexPath *visibleIndexPath = [self.collectionView indexPathForItemAtPoint:visiblePoint];
当您的集合视图中的每个项目占据整个屏幕时,这尤其有效。
斯威夫特版本
let visibleRect = CGRect(origin: collectionView.contentOffset, size: collectionView.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
let visibleIndexPath = collectionView.indexPathForItem(at: visiblePoint)
方法 [collectionView visibleCells] 为您提供所需的所有 visibleCells 数组。当你想得到它时使用它
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
for (UICollectionViewCell *cell in [self.mainImageCollection visibleCells]) {
NSIndexPath *indexPath = [self.mainImageCollection indexPathForCell:cell];
NSLog(@"%@",indexPath);
}
}
更新到 Swift 5:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
for cell in yourCollectionView.visibleCells {
let indexPath = yourCollectionView.indexPath(for: cell)
print(indexPath)
}
}
scrollViewDidScroll:
委托方法会在任何滚动完成时提供滚动视图更新(此处可能是更好的选择)。与仅在滚动视图“[从大滚动] 停止时调用的 scrollViewDidEndDecelerating:
委托方法相反(请参阅 UIScrollView 标题)。
..DidScroll
被多次调用,即使在短滚动期间也是如此。可能是也可能不是一件好事,这取决于一个人想要做什么。
斯威夫特 5:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
var visibleRect = CGRect()
visibleRect.origin = collectionView.contentOffset
visibleRect.size = collectionView.bounds.size
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
guard let indexPath = collectionView.indexPathForItem(at: visiblePoint) else { return }
print(indexPath)
}
Swift 2.2 中结合的工作答案:
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
var visibleRect = CGRect()
visibleRect.origin = self.collectionView.contentOffset
visibleRect.size = self.collectionView.bounds.size
let visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect))
let visibleIndexPath: NSIndexPath = self.collectionView.indexPathForItemAtPoint(visiblePoint)
guard let indexPath = visibleIndexPath else { return }
print(indexPath)
}
为了完整起见,这是最终为我工作的方法。这是@Anthony 和@iAn 方法的组合。
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
CGRect visibleRect = (CGRect){.origin = self.collectionView.contentOffset, .size = self.collectionView.bounds.size};
CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect));
NSIndexPath *visibleIndexPath = [self.collectionView indexPathForItemAtPoint:visiblePoint];
NSLog(@"%@",visibleIndexPath);
}
UICollectionView 当前可见单元格索引:Swift 3、4 和 5+
var visibleCurrentCellIndexPath: IndexPath? {
for cell in self.collectionView.visibleCells {
let indexPath = self.collectionView.indexPath(for: cell)
return indexPath
}
return nil
}
作为扩展:
extension UICollectionView {
var visibleCurrentCellIndexPath: IndexPath? {
for cell in self.visibleCells {
let indexPath = self.indexPath(for: cell)
return indexPath
}
return nil
}
}
用法:
if let indexPath = collectionView.visibleCurrentCellIndexPath {
/// do something
}
最好使用 UICollectionViewDelegate 方法:(Swift 3)
// Called before the cell is displayed
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
print(indexPath.row)
}
// Called when the cell is displayed
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
print(indexPath.row)
}
didEndDisplaying
,来自文档:告诉委托指定的单元格已从集合视图中删除。使用此方法来检测何时从集合视图中删除了单元格,而不是监视视图本身以查看它何时消失。 所以我认为在显示单元格时不会调用 didEndDisplaying
。
只是想为其他人添加:由于某种原因,当我使用 pagingEnabled 滚动到 collectionView 中的上一个单元格时,我没有得到用户可见的单元格。
所以我在 dispatch_async 中插入代码给它一些“空气”,这对我有用。
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
dispatch_async(dispatch_get_main_queue(), ^{
UICollectionViewCell * visibleCell= [[self.collectionView visibleCells] objectAtIndex:0];
[visibleCell doSomthing];
});
}
DispatchQueue.main.async {
当呼叫从 func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
之类的东西发起时
willDisplay cell
发起的刷新调用。我认为在我的情况下,UIKit 中的某个问题与此答案完全相同。
斯威夫特 3.0
最简单的解决方案,它将为您提供可见单元格的 indexPath ..
yourCollectionView.indexPathsForVisibleItems
将返回 indexpath 的数组。
只需像这样从数组中取出第一个对象。
yourCollectionView.indexPathsForVisibleItems.first
我想它也应该适用于 Objective-C。
对于 Swift 3.0
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let visibleRect = CGRect(origin: colView.contentOffset, size: colView.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
let indexPath = colView.indexPathForItem(at: visiblePoint)
}
将@Anthony 的答案转换为 Swift 3.0 对我来说非常有效:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
var visibleRect = CGRect()
visibleRect.origin = yourCollectionView.contentOffset
visibleRect.size = yourCollectionView.bounds.size
let visiblePoint = CGPoint(x: CGFloat(visibleRect.midX), y: CGFloat(visibleRect.midY))
let visibleIndexPath: IndexPath? = yourCollectionView.indexPathForItem(at: visiblePoint)
print("Visible cell's index is : \(visibleIndexPath?.row)!")
}
您可以使用 scrollViewDidEndDecelerating
: 为此
//@property (strong, nonatomic) IBOutlet UICollectionView *collectionView;
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
for (UICollectionViewCell *cell in [self.collectionView visibleCells]) {
NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell];
NSUInteger lastIndex = [indexPath indexAtPosition:[indexPath length] - 1];
NSLog(@"visible cell value %d",lastIndex);
}
}
在这个线程中,如果单元格采用全屏模式,有很多解决方案可以正常工作,但它们使用可见矩形的集合视图边界和中点但是有一个简单的解决方案可以解决这个问题
DispatchQueue.main.async {
let visibleCell = self.collImages.visibleCells.first
print(self.collImages.indexPath(for: visibleCell))
}
这样,您可以获得可见单元格的 indexPath。我添加了 DispatchQueue,因为当您快速滑动时,如果在短时间内显示下一个单元格,那么在没有 dispactchQueue 的情况下,您将获得短暂显示单元格的 indexPath,而不是屏幕上显示的单元格。
这是一个老问题,但就我而言......
- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView {
_m_offsetIdx = [m_cv indexPathForCell:m_cv.visibleCells.firstObject].row;
}
- (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
_m_offsetIdx = [m_cv indexPathForCell:m_cv.visibleCells.lastObject].row;
}
还要检查这个片段
let isCellVisible = collectionView.visibleCells.map { collectionView.indexPath(for: $0) }.contains(inspectingIndexPath)
试试这个,它有效。 (例如,在下面的示例中,我有 3 个单元格。)
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
let visibleRect = CGRect(origin: self.collectionView.contentOffset, size: self.collectionView.bounds.size)
let visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect))
let visibleIndexPath = self.collectionView.indexPathForItemAtPoint(visiblePoint)
if let v = visibleIndexPath {
switch v.item {
case 0: setImageDescription()
break
case 1: setImageConditions()
break
case 2: setImageResults()
break
default: break
}
}
斯威夫特 3 和斯威夫特 4:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
var visibleRect = CGRect()
visibleRect.origin = collectionView.contentOffset
visibleRect.size = collectionView.bounds.size
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
guard let indexPath = collectionView.indexPathForItem(at: visiblePoint) else { return }
print(indexPath[1])
}
如果您想显示实际数字,则可以添加 +1
不定期副业成功案例分享
visibleIndexPath
有时会为零,所以if (visibleIndexPath) == nil { let cells = collectionView.visibleCells() let visibleIndexPath = collectionView.indexPathForCell(cells[0] as! UICollectionViewCell)! as NSIndexPath }