有没有办法检测一个节的标题UITableView
当前是否浮动?我只想在浮动时将表格视图滚动到标题位置。
提前致谢!
如果该部分的第一个单元格不再可见,则标题将浮动。所以:
NSIndexPath *topCellPath = [[self.tableView indexPathsForVisibleRows] objectAtIndex:0];
if (topCellPath.row != 0)
{
// Header must be floating!
}
scrollToRowAtIndexPath:atScrollPosition:animated:
您可以通过滚动到索引路径和滚动位置来实现类似的效果UITableViewScrollPositionNone
- 如果该部分中的第一个单元格已经在屏幕上,则不会滚动。
添加@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
}
}
这行得通。
@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
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
}
该代码对我有用。
- (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;
}
您可以先存储节标题视图的原始矩形。
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
}
}