【问题标题】:UITableView with one visible cell: determine which is most visible带有一个可见单元格的 UITableView:确定哪个最可见
【发布时间】:2014-12-11 03:43:58
【问题描述】:

在任何给定时间给定一个带有单个可见单元格的 UITableView,我如何确定滚动表格视图时哪个单元格在视图中?

我知道我可以通过这样做获得一组可见单元格:

NSArray *paths = [tableView indexPathsForVisibleRows];

然后通过执行以下操作获取最后一个单元格(或第一个单元格,或其他):

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

但是我如何比较所有可见的单元格并确定它们中的哪一个最显眼?

【问题讨论】:

    标签: ios objective-c uitableview


    【解决方案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)")
            
                    }
            

            【讨论】:

              猜你喜欢
              • 2018-02-22
              • 1970-01-01
              • 1970-01-01
              • 2018-11-22
              • 1970-01-01
              • 1970-01-01
              • 2017-08-05
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多