19

有没有办法获得所有可见的节标题视图?

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

4

10 回答 10

20

使用 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
于 2014-05-08T09:37:09.317 回答
12

我真的很喜欢@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
    }
}
于 2015-06-24T14:55:26.823 回答
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% 起作用。

于 2013-03-04T15:00:25.357 回答
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
    }
}
于 2015-09-11T23:37:25.503 回答
2

一个UITableView扩展,它为您提供visibleHeaderViews基于 @OhadM 的答案 ( https://stackoverflow.com/a/45525595/5058116 ),但它会检查潜在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

    }

}
于 2018-09-12T00:51:13.990 回答
1

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

于 2013-03-04T15:19:46.183 回答
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;
于 2015-12-31T20:50:40.673 回答
1

快速查看UITableView文档为我们提供了indexPathsForVisibleRows并将其与 map 结合为我们提供了我们需要的数组:

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

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

于 2017-08-05T19:18:28.027 回答
0

Swift 4+ 干净简单,没有重复:

extension UITableView {

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

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

}
于 2018-11-16T09:04:02.153 回答
0

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

然而,有一个问题:你的标题视图必须继承UITableViewHeaderFooterView它才能工作(无论如何他们应该在技术上,但是除了这个之外的所有东西都可以工作,即使他们没有,所以你很容易错过这个。)

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

for section in 0 ..< tableView.numberOfSections {
    guard let header = tableView.headerView(forSection: section) as? CustomHeaderView else { continue }
    header.update(...)
}
于 2019-11-26T09:58:40.500 回答