如何检索所有可见的表节标题视图

时间:2013-03-04 14:52:54

标签: ios objective-c uitableview

有没有办法让所有部分标题视图都可见?

类似于UITableView的visibleCells实例方法..

10 个答案:

答案 0 :(得分:14)

使用indexPathsForVisibleRows的问题是它不包含没有任何行的部分。要获得所有可见部分,包括空部分,您必须检查部分的矩形并将其与表格的contentOffset进行比较。

您还必须注意普通样式与浮动部分和没有浮动部分的分组样式之间的区别。

我制作了一个支持此计算的类别:

@interface UITableView (VisibleSections)

// Returns an array of NSNumbers of the current visible section indexes
- (NSArray *)indexesOfVisibleSections;
// Returns an array of UITableViewHeaderFooterView objects of the current visible section headers
- (NSArray *)visibleSections;

@end

@implementation UITableView (VisibleSections)

- (NSArray *)indexesOfVisibleSections {
    // Note: We can't just use indexPathsForVisibleRows, since it won't return index paths for empty sections.
    NSMutableArray *visibleSectionIndexes = [NSMutableArray arrayWithCapacity:self.numberOfSections];
    for (int i = 0; i < self.numberOfSections; i++) {
        CGRect headerRect;
        // In plain style, the section headers are floating on the top, so the section header is visible if any part of the section's rect is still visible.
        // In grouped style, the section headers are not floating, so the section header is only visible if it's actualy rect is visible.
        if (self.style == UITableViewStylePlain) {
            headerRect = [self rectForSection:i];
        } else {
            headerRect = [self rectForHeaderInSection:i];
        }
        // The "visible part" of the tableView is based on the content offset and the tableView's size.
        CGRect visiblePartOfTableView = CGRectMake(self.contentOffset.x, self.contentOffset.y, self.bounds.size.width, self.bounds.size.height);
        if (CGRectIntersectsRect(visiblePartOfTableView, headerRect)) {
            [visibleSectionIndexes addObject:@(i)];
        }
    }
    return visibleSectionIndexes;
}

- (NSArray *)visibleSections {
    NSMutableArray *visibleSects = [NSMutableArray arrayWithCapacity:self.numberOfSections];
    for (NSNumber *sectionIndex in self.indexesOfVisibleSections) {
        UITableViewHeaderFooterView *sectionHeader = [self headerViewForSection:sectionIndex.intValue];
        [visibleSects addObject:sectionHeader];
    }

    return visibleSects;
}

@end

答案 1 :(得分:9)

我真的很喜欢@ adamsiton的解决方案,最后我把它翻译成了swift。这就是,仅供参考。

我调用了文件UITableView + VisibleSections.swift

import UIKit

public extension UITableView {

    var indexesOfVisibleSections: [Int] {
        // Note: We can't just use indexPathsForVisibleRows, since it won't return index paths for empty sections.
        var visibleSectionIndexes = [Int]()

        for i in 0..<numberOfSections {
            var headerRect: CGRect?
            // In plain style, the section headers are floating on the top, so the section header is visible if any part of the section's rect is still visible.
            // In grouped style, the section headers are not floating, so the section header is only visible if it's actualy rect is visible.
            if (self.style == .plain) {
                headerRect = rect(forSection: i)
            } else {
                headerRect = rectForHeader(inSection: i)
            }
            if headerRect != nil {
                // The "visible part" of the tableView is based on the content offset and the tableView's size.
                let visiblePartOfTableView: CGRect = CGRect(x: contentOffset.x, y: contentOffset.y, width: bounds.size.width, height: bounds.size.height)
                if (visiblePartOfTableView.intersects(headerRect!)) {
                    visibleSectionIndexes.append(i)
                }
            }
        }
        return visibleSectionIndexes
    }

    var visibleSectionHeaders: [UITableViewHeaderFooterView] {
        var visibleSects = [UITableViewHeaderFooterView]()
        for sectionIndex in indexesOfVisibleSections {
            if let sectionHeader = headerView(forSection: sectionIndex) {
                visibleSects.append(sectionHeader)
            }
        }

        return visibleSects
    }
}

答案 2 :(得分:4)

对于普通样式表,您可以获得可见行。从那些,获得可见部分的集合。然后,从表中获取节标题视图。

NSArray *visibleRows = [self.tableView indexPathsForVisibleRows];
NSMutableIndexSet *sections = [[NSMutableIndexSet alloc] init];
for (NSIndexPath *indexPath in visibleRows) {
    [sections addIndex:indexPath.section];
}

NSMutableArray *headerViews = [NSMutableArray array];
[sections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
    UIView *view = [self.tableView headerViewForSection:idx];
    [headerViews addObject:view];
}];

注意:未经测试的代码 - 可能包含拼写错误。对于分组样式表,这不会100%有效。

答案 3 :(得分:2)

Benjamin Wheeler的解决方案是一个很棒的Swift解决方案。由于新的Swift语法,我在其中修复了一个问题,并修改了它以匹配默认UITableView实现提供的.visibleCells属性。

extension UITableView {

    /// The table section headers that are visible in the table view. (read-only)
    ///
    /// The value of this property is an array containing UITableViewHeaderFooterView objects, each representing a visible cell in the table view.
    ///
    /// Derived From: [http://stackoverflow.com/a/31029960/5191100](http://stackoverflow.com/a/31029960/5191100)
    var visibleSectionHeaders: [UITableViewHeaderFooterView] {
        get {
            var visibleSects = [UITableViewHeaderFooterView]()

            for sectionIndex in indexesOfVisibleSections() {
                if let sectionHeader = self.headerViewForSection(sectionIndex) {
                    visibleSects.append(sectionHeader)
                }
            }

            return visibleSects
        }
    }

    private func indexesOfVisibleSections() -> Array<Int> {
        // Note: We can't just use indexPathsForVisibleRows, since it won't return index paths for empty sections.
        var visibleSectionIndexes = Array<Int>()

        for (var i = 0; i < self.numberOfSections; i++) {
            var headerRect: CGRect?
            // In plain style, the section headers are floating on the top,
            // so the section header is visible if any part of the section's rect is still visible.
            // In grouped style, the section headers are not floating,
            // so the section header is only visible if it's actual rect is visible.
            if (self.style == .Plain) {
                headerRect = self.rectForSection(i)
            } else {
                headerRect = self.rectForHeaderInSection(i)
            }

            if headerRect != nil {
                // The "visible part" of the tableView is based on the content offset and the tableView's size.
                let visiblePartOfTableView: CGRect = CGRect(
                    x: self.contentOffset.x,
                    y: self.contentOffset.y,
                    width: self.bounds.size.width,
                    height: self.bounds.size.height
                )

                if (visiblePartOfTableView.intersects(headerRect!)) {
                    visibleSectionIndexes.append(i)
                }
            }
        }

        return visibleSectionIndexes
    }
}

答案 4 :(得分:1)

在这种情况下,我认为您将cell.tag设置为indexPath.section中的当前部分(cellForRowAtIndexPath)并使用您所描述的visibleCells方法并{{1 }}

答案 5 :(得分:1)

获取当前可见的部分,你可以通过检查当前的可见单元索引路径部分来获取它,因此该函数可以返回到可见部分

- (NSArray *)indexesOfVisibleSections {

    NSMutableArray *visibleSections = [NSMutableArray array];

    for (UITableViewCell * cell in [self.tableView visibleCells]) {
        if (![visibleSections containsObject:[NSNumber numberWithInteger:[self.tableView indexPathForCell:cell].section]]) {
            [visibleSections addObject:[NSNumber numberWithInteger:[self.tableView indexPathForCell:cell].section]];
        }
    }

    return visibleSections;
}

要访问剖面视图,您可以使用

- (UITableViewHeaderFooterView *)headerViewForSection:(NSInteger)section;

答案 6 :(得分:1)

快速查看UITableView文档为我们提供了indexPathsForVisibleRows,并将其与地图相结合,为我们提供了所需的数组:

tableView.indexPathsForVisibleRows.map{ tableView.headerView(forSection: $0.section) }

map返回我们可见的header-in-section数组。

答案 7 :(得分:1)

一个UITableView扩展名,它基于@OhadM答案(https://stackoverflow.com/a/45525595/5058116)为您提供visibleHeaderViews,但可以检查潜在的nil值。

extension UITableView {

    /// The section header views that are visible in the table view.
    var visibleHeaderViews: [UITableViewHeaderFooterView] {

        var headerViews = [UITableViewHeaderFooterView]()

        guard let indexPaths = indexPathsForVisibleRows else { return headerViews }

        for indexPath in indexPaths {
            if let headerView = headerView(forSection: indexPath.section) {
                headerViews.append(headerView)
            }
        }

        return headerViews

    }

}

答案 8 :(得分:0)

快速4 + 干净简单,没有重复之处:

extension UITableView {

    var visibleHeaderViews: [UITableViewHeaderFooterView] {
        guard let visibleSectionsIndexPaths = indexPathsForVisibleRows?.compactMap({ $0.section }) else { return [] }

        return Set(visibleSectionsIndexPaths).compactMap { headerView(forSection: $0) }
    }

}

答案 9 :(得分:0)

所有这些答案都变得过于复杂。您需要做的就是循环调用headerView(forSection:)。对于不可见的标题视图,它将返回nil。

但是,有一个陷阱:您的标头视图必须继承自UITableViewHeaderFooterView(从技术上来说,它们应该仍然起作用,但是除此以外的所有方法都可以起作用,即使它们不起作用) t,这样您就可以轻松地错过这个。)

一旦您的类正确继承,您就可以这样做:

for section in 0 ..< tableView.numberOfSections {
    guard let header = tableView.headerView(forSection: section) as? CustomHeaderView else { continue }
    header.update(...)
}