UITableView with one visible cell: determine which one is most visible

Given a UITableView with one visible cell at any given time, how can I determine which cell is most suitable when scrolling through a table?

I know that I can get an array of visible cells by doing this:

NSArray *paths = [tableView indexPathsForVisibleRows]; 

And then get the last cell (or the first or any other) by doing:

 UITableViewCell* cell = (UITableViewCell*)[tableView cellForRowAtIndexPath:[paths lastObject]]; 

But how can I compare all the visible cells and determine which one is most suitable?

+5
source share
5 answers

The algorithm differs depending on how many paths you return:

  • If there is only one path, then the most visible cell right there
  • If there are three or more paths, any of the cells in the middle (i.e. all cells except the first and last) are equally visible
  • If there are exactly two cells, find the position of the line that separates them in its parent view * and calculates two distances - from the top to the middle and from middle to lower. If the upper-middle is larger, then the upper cell is most noticeable. If the middle bottom is larger, then the second cell is more visible. Otherwise, two cells are equally visible.

* The midpoint position is the bottom of the second cell. The top and bottom positions are the top and bottom of the table.

+3
source

The following logic will bring you the most visible cell at the end of the scroll:

 -(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]; } 
+3
source

Fast solution based on @Sebyddd's answer:

 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) } 
+1
source

You can use the table rectForRowAtIndexPath: to get the frame of each visible cell, and then shift them (using CGRectOffset ) by -contentOffset.y to take into account scrolling, and then cross them with the bounds table view to find out how much each cell is visible inside the view tables.

0
source

In the logic below, you get a UITableViewCell that will be most visible or closed to the center in the UITableView every time the user stops scrolling. Hope this logic helps someone.

 - (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; } 
0
source

Source: https://habr.com/ru/post/1208779/


All Articles