带有一个可见单元格的 UITableView:确定哪个最可见
Posted
技术标签:
【中文标题】带有一个可见单元格的 UITableView:确定哪个最可见【英文标题】:UITableView with one visible cell: determine which is most visible 【发布时间】:2014-12-11 03:43:58 【问题描述】:在任何给定时间给定一个带有单个可见单元格的 UITableView,我如何确定滚动表格视图时哪个单元格最在视图中?
我知道我可以通过这样做获得一组可见单元格:
NSArray *paths = [tableView indexPathsForVisibleRows];
然后通过执行以下操作获取最后一个单元格(或第一个单元格,或其他):
UITableViewCell* cell = (UITableViewCell*)[tableView cellForRowAtIndexPath:[paths lastObject]];
但是我如何比较所有可见的单元格并确定它们中的哪一个最显眼?
【问题讨论】:
【参考方案1】:以下逻辑将使您在滚动结束时获得最明显的单元格:
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
CGRect visibleRect = (CGRect).origin = self.tableView.contentOffset, .size = self.tableView.bounds.size;
CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect));
NSIndexPath *visibleIndexPath = [self.tableView indexPathForRowAtPoint:visiblePoint];
【讨论】:
【参考方案2】:算法因返回的路径数而异:
如果只有一条路径,那就是那里最明显的单元格 如果存在三个或更多路径,则中间的任何单元格(即除第一个和最后一个单元格之外的所有单元格)都同样可见 如果恰好有两个单元格,则在其父视图中找到分隔这两个单元格的位置*,并计算两个距离 - 上到中和中到下。如果顶部到中间较大,则顶部单元格最明显。如果中间到底部更大,则第二个单元格更明显。否则,这两个单元格同样可见。* 中点位置是第二个单元格的底部。顶部和底部位置是表格视图的顶部和底部。
【讨论】:
这实际上可能是最有意义的,因为如果释放触摸时只能看到一个单元格,那么滚动时最多应该看到两个。【参考方案3】:基于@Sebyddd 答案的 Swift 解决方案:
func scrollViewDidEndDecelerating(scrollView: UIScrollView)
scrollToMostVisibleCell()
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool)
if !decelerate
scrollToMostVisibleCell()
func scrollToMostVisibleCell()
let visibleRect = CGRect(origin: tableView.contentOffset, size: tableView.bounds.size)
let visiblePoint = CGPoint(x: CGRectGetMidX(visibleRect), y: CGRectGetMidY(visibleRect))
let visibleIndexPath: NSIndexPath = tableView.indexPathForRowAtPoint(visiblePoint)!
tableView.scrollToRowAtIndexPath(visibleIndexPath, atScrollPosition: .Top, animated: true)
【讨论】:
【参考方案4】:您可以使用表格视图的rectForRowAtIndexPath:
获取每个可见单元格的框架,然后将它们(使用CGRectOffset
)偏移-contentOffset.y
以考虑滚动,然后将它们与表格视图的bounds
相交以找出每个单元格在表格视图中可见的程度。
【讨论】:
【参考方案5】:每当用户停止滚动时,以下逻辑将为您提供在 UITableView 中最明显或最靠近中心的 UITableViewCell。希望这个逻辑对某人有所帮助。
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
if (!decelerate)
if (isScrollingStart)
isScrollingStart=NO;
isScrollingEnd=YES;
[self scrollingStopped];
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
if (isScrollingStart)
isScrollingStart=NO;
isScrollingEnd=YES;
[self scrollingStopped];
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
isScrollingStart=YES;
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
isScrollingStart=YES;
-(void)scrollingStopped
NSMutableArray* arrVideoCells=[NSMutableArray array];
NSLog(@"Scrolling stopped");
NSArray* arrVisibleCells=[self.tableTimeline visibleCells];
for (TimeLineCell* cell in arrVisibleCells)
if ([cell isKindOfClass:[TimeLineCellMediaVideo class]])
[arrVideoCells addObject:cell];
TimeLineCellMediaVideo* videoCell=[self getCellNearCenterOfScreen:arrVideoCells];
-(TimeLineCellMediaVideo*)getCellNearCenterOfScreen:(NSMutableArray*)arrCells
TimeLineCellMediaVideo* closetCellToCenter;
CGRect filterCGRect;
for (TimeLineCellMediaVideo* videoCell in arrCells)
if (arrCells.count==1)
closetCellToCenter= videoCell;
NSIndexPath* cellIndexPath=[self.tableTimeline indexPathForCell:videoCell];
CGRect rect = [self.tableTimeline convertRect:[self.tableTimeline rectForRowAtIndexPath:cellIndexPath] toView:[self.tableTimeline superview]];
if (closetCellToCenter)
CGRect intersect = CGRectIntersection(self.tableTimeline.frame, filterCGRect);
float visibleHeightFilterCell = CGRectGetHeight(intersect);
intersect = CGRectIntersection(self.tableTimeline.frame, rect);
float visibleHeightCurrentCell = CGRectGetHeight(intersect);
if (visibleHeightCurrentCell>visibleHeightFilterCell)
filterCGRect=rect;
closetCellToCenter= videoCell;
else
closetCellToCenter=videoCell;
filterCGRect=rect;
return closetCellToCenter;
【讨论】:
【参考方案6】:我执行以下操作来找到大多数可见单元格的 indexPath 并且它工作正常。
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView)
guard let tableView = scrollView as? UITableView else
return
let visibleHeights = tableView.visibleCells.compactMap cell -> (indexPath: IndexPath, visibleHeight: CGFloat)? in
guard let indexPath = tableView.indexPath(for: cell) else
return nil
let cellRect = tableView.rectForRow(at: indexPath)
let superView = tableView.superview
let convertedRect = tableView.convert(cellRect, to: superView)
let intersection = tableView.frame.intersection(convertedRect)
let visibleHeight = intersection.height
return (indexPath, visibleHeight)
guard let maxVisibleIndexPath = visibleHeights.max(by: $0.visibleHeight < $1.visibleHeight )?.indexPath else
return
print("maxVisibleIndexPath: \(maxVisibleIndexPath)")
【讨论】:
以上是关于带有一个可见单元格的 UITableView:确定哪个最可见的主要内容,如果未能解决你的问题,请参考以下文章
带有包含自定义单元格的 UITableView 的 UISearchBar => 空白单元格
UITableView 仅加载在设备上可见的自定义单元格,并在添加更多单元格时崩溃
带有 WKWebView 单元格的滚动 UICollectionView 的 UITableView