5

有没有办法检测一个节的标题UITableView当前是否浮动?我只想在浮动时将表格视图滚动到标题位置。

提前致谢!

4

6 回答 6

7

如果该部分的第一个单元格不再可见,则标题将浮动。所以:

NSIndexPath *topCellPath = [[self.tableView indexPathsForVisibleRows] objectAtIndex:0];
if (topCellPath.row != 0)
{
    // Header must be floating!
}

scrollToRowAtIndexPath:atScrollPosition:animated:您可以通过滚动到索引路径和滚动位置来实现类似的效果UITableViewScrollPositionNone- 如果该部分中的第一个单元格已经在屏幕上,则不会滚动。

于 2012-06-26T14:18:40.197 回答
1

添加@robdashnash 答案的快速端口

extension UITableView
{
     func isFloatingSectionHeader( view:UITableViewHeaderFooterView )->Bool
     {
          if let section = section( for:view )
          {
              return isFloatingHeaderInSection( section:section )
          }
          return false
      }

     func isFloatingHeaderInSection( section:Int )->Bool
     {
         let frame = rectForHeader( inSection:section )
         let y = contentInset.top + contentOffset.y
         return y > frame.origin.y
     }

     func section( for view:UITableViewHeaderFooterView )->Int?
     {
         for i in stride( from:0, to:numberOfSections, by:1 )
         {
             let a = convert( CGPoint.zero, from:headerView( forSection:i ) )
             let b = convert( CGPoint.zero, from:view )
             if a.y == b.y
             {
                 return i
             }
         }
         return nil
     }
 }
于 2017-06-15T18:26:25.650 回答
1

这行得通。

@implementation UITableView (rrn_extensions)

-(BOOL)rrn_isFloatingSectionHeaderView:(UITableViewHeaderFooterView *)view {
    NSNumber *section = [self rrn_sectionForHeaderFooterView:view];
    return [self rrn_isFloatingHeaderInSection:section.integerValue];
}

-(BOOL)rrn_isFloatingHeaderInSection:(NSInteger)section {
    CGRect frame = [self rectForHeaderInSection:section];
    CGFloat y = self.contentInset.top + self.contentOffset.y;
    return y > frame.origin.y;
}

-(NSNumber *)rrn_sectionForHeaderFooterView:(UITableViewHeaderFooterView *)view {
    for (NSInteger i = 0; i < [self numberOfSections]; i++) {
        CGPoint a = [self convertPoint:CGPointZero fromView:[self headerViewForSection:i]];
        CGPoint b = [self convertPoint:CGPointZero fromView:view];
        if (a.y == b.y) {
            return @(i);
        }
    }
    return nil;
}

@end
于 2016-10-07T12:31:18.120 回答
1

iOS 11.0+ solution for UITableViews as well as UICollectionViews

In both cases, use the scrollViewDidScroll method. You can use the currentHeader property to store current header displayed at the top. HEIGHT_OF_HEADER_VIEW is a value you should specify yourself.

For UITableView

private var currentHeader: UITableViewHeaderFooterView? {
    willSet {
        // Handle `old` header
    } didSet {
        // Hanlde `new` header
    }
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let point = CGPoint(x: 0, y: HEIGHT_OF_HEADER_VIEW + tableView.contentOffset.y + tableView.adjustedContentInset.top)
    guard let path = tableView.indexPathForRow(at: point) else {
        return
    }

    let section = path.section
    let rect = tableView.rectForHeader(inSection: section)
    let converted = tableView.convert(rect, to: tableView.superview)
    let safeAreaInset = tableView.safeAreaInsets.top

    // Adding 1 offset because of large titles that sometimes cause slighly wrong converted values
    guard converted.origin.y <= safeAreaInset,
        let header = tableView.headerView(forSection: section) else {
        return
    }
    currentHeader = header
}

For UICollectionView

private var currentHeader: UICollectionReusableView? {
    willSet {
        // Handle `old` header
    } didSet {
        // Handle `new` header
    }
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let x = (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.sectionInset.left ?? 0
    let point = CGPoint(x: x, y: HEIGHT_OF_HEADER_VIEW + collectionView.contentOffset.y + collectionView.adjustedContentInset.top)

    guard let path = collectionView.indexPathForItem(at: point),
        let rect = collectionView.layoutAttributesForSupplementaryElement(ofKind: UICollectionView.elementKindSectionHeader, at: IndexPath(row: 0, section: path.section))?.frame else {
        return
    }

    let converted = collectionView.convert(rect, to: collectionView.superview)
    let safeAreaInset = collectionView.safeAreaInsets.top

    guard converted.origin.y <= safeAreaInset,
        let header = collectionView.supplementaryView(forElementKind: UICollectionView.elementKindSectionHeader, at: IndexPath(row: 0, section: path.section)) else {
        return
    }
    currentHeader = header
}
于 2020-06-01T12:53:54.833 回答
0

该代码对我有用。

- (BOOL)isSection0HeaderSticky {
    CGRect originalFrame = [self.listTableView rectForHeaderInSection:0];

    UIView *section0 = [self.listTableView headerViewForSection:0];

    if (originalFrame.origin.y < section0.frame.origin.y) {
        return  YES;
    }
    return NO;
}
于 2017-04-16T11:56:36.030 回答
0

您可以先存储节标题视图的原始矩形。

 headerView.originalPoint = [tableView rectForHeaderInSection:section].origin;

并将scrollViewDidScroll:scrollView消息发送到标题。

在您的标题视图中

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
   BOOL isFloating = self.frame.origin.y > self.originalPoint.y;
   if (isFloating) {
       //DO what you want
   }
}
于 2016-05-18T02:00:21.293 回答