【发布时间】:2010-11-16 04:49:59
【问题描述】:
UITableView 提供了indexPathsForVisibleRows 和visibleCells 方法,但是我怎样才能得到可见部分呢?
【问题讨论】:
标签: iphone ios objective-c uitableview
UITableView 提供了indexPathsForVisibleRows 和visibleCells 方法,但是我怎样才能得到可见部分呢?
【问题讨论】:
标签: iphone ios objective-c uitableview
或者真正简单的方法是利用 valueForKeyPath 和 NSSet 类:
NSSet *visibleSections = [NSSet setWithArray:[[self.tableView indexPathsForVisibleRows] valueForKey:@"section"]];
基本上,您会在可见行中获得一个节值数组,然后用它填充一个集合以删除重复项。
【讨论】:
@distinctUnionOfObjects,这样可以节省创建NSSet。这给出了:[[self.tableView indexPathsForVisibleRows] valueForKeyPath: @"@distinctUnionOfObjects.section"].
斯威夫特版本
if let visibleRows = tableView.indexPathsForVisibleRows {
let visibleSections = visibleRows.map({$0.section})
}
【讨论】:
let uniqueSections = Array(Set(visibleSections)).sorted(); //converting to set loses order, hence the sorting
UITableViews 使用 NSIndexPath 存储它们的单元格。因此,没有针对部分的对象。使用下面的代码,我们可以遍历表并使用可见部分的索引执行操作(我不确定你为什么想要可见部分,因为可见只意味着它们当前在屏幕上,但无论如何)。
for (NSIndexPath* i in [yourTableViewName indexPathsForVisibleRows])
{
NSUInteger sectionPath = [i indexAtPosition:0];
//custom code here, will run multiple times per section for each visible row in the group
}
【讨论】:
从可见行列表中提取部分:
NSArray *indexPathsForVisibleRows = [tableView indexPathsForVisibleRows];
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
for ( NSIndexPath *indexPath in indexPathsForVisibleRows ) {
[indexSet addIndex:indexPath.section];
}
NSLog(@"indexSet %@",indexSet);
// indexSet <NSMutableIndexSet: 0x11a5c190>[number of indexes: 5 (in 1 ranges), indexes: (9-13)]
或者:
NSArray *indexPathsForVisibleRows = [detailTableView indexPathsForVisibleRows];
NSMutableSet *sectionSet = [NSMutableSet set];
for ( NSIndexPath *indexPath in indexPathsForVisibleRows ) {
[sectionSet addObject:[NSNumber numberWithInt:indexPath.section]];
}
NSLog(@"sectionSet %@",sectionSet);
// sectionSet {(13, 11, 9, 10, 12 )}
【讨论】:
我已经找到了解决方案。
第一步,每个部分都会显示一个由- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section创建的UIView,并将其存储到数组中。
当 TableView 滚动时,我想释放不可见的部分视图,所以我需要知道哪个部分是可见的,下面的函数代码将为此检测,如果视图可见则释放它。
-(BOOL)isVisibleRect:(CGRect)rect containerView:(UIScrollView*)containerView
{
CGPoint point = containerView.contentOffset;
CGFloat zy = point.y ;
CGFloat py = rect.origin.y + rect.size.height;
if (py - zy <0) {
return FALSE;
}
CGRect screenRect = containerView.frame;
CGFloat by = screenRect.size.height + zy ;
if (rect.origin.y > by) {
return FALSE;
}
return TRUE;
}
(rect是UIView部分的框架;containerView是UITableView)
这样,我可以得到UITableView的可见部分,但我希望SDK可以直接为此提供API。
【讨论】:
在 UITableView 中获取可见部分的 2 步解决方案:
1) 将标题视图添加到 viewForHeaderInSection 中的可变数组中
2) 当tableview在scrollViewDidScroll滚动时更新数组
注意使用标签属性来保存节号
@property (nonatomic, strong, readwrite) NSMutableArray *headerArray;
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 40)];
headerView.backgroundColor = [UIColor greenColor];
headerView.tag = section;
[_headerArray addObject:headerView];
return headerView;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
[self updateHeaderArray];
NSLog(@"------------");
for (UIView *view in _headerArray) {
NSLog(@"visible section:%d", view.tag);
}
}
- (void)updateHeaderArray {
// remove invisible section headers
NSMutableArray *removeArray = [NSMutableArray array];
CGRect containerRect = CGRectMake(_tableView.contentOffset.x, _tableView.contentOffset.y,
_tableView.frame.size.width, _tableView.frame.size.height);
for (UIView *header in _headerArray) {
if (!CGRectIntersectsRect(header.frame, containerRect)) {
[removeArray addObject:header];
}
}
[_headerArray removeObjectsInArray:removeArray];
}
【讨论】:
使用 kvc 回答更简单整洁
NSArray *visibleSections = [self.tableView.indexPathsForVisibleRows valueForKey:@"section"];
这可能会给您一个包含重复值的数组,但您可以从那里进行管理。
【讨论】:
for (NSUInteger section = 0; section < self.tableView.numberOfSections; ++section) {
UIView *headerView = [self.tableView headerViewForSection:section];
if (headerView.window) {
NSLog(@"its visible");
}
}
【讨论】:
另一种解决方案,在节标题视图的标签中使用 1 位,就像那样
#define _TBL_TAG_SECTION(_TAG) ((_TAG)|(1<<30))
#define _TBL_TAG_CLEAR(_TAG) ((_TAG)&((1<<30)-1))
#define _TBL_TAG_IS_SECTION(_TAG) ((_TAG)>>30)
- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
// alloc header view
UIView *header = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
header.tag = _TBL_TAG_SECTION(section);
return header;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGRect r = CGRectMake(scrollView.contentOffset.x, scrollView.contentOffset.y,
CGRectGetWidth(scrollView.frame),
CGRectGetHeight(scrollView.frame));
for (UIView *v in [_tableView subviews]) {
if ( CGRectIntersectsRect(r, v.frame) ) {
if ( _TBL_TAG_IS_SECTION(v.tag) ) {
NSLog(@"visible section tag %d", _TBL_TAG_CLEAR(v.tag));
}
}
}
}
【讨论】:
self.sections.indices.forEach{ (i:Int) in
let section:UIView? = self.tableView(self, viewForHeaderInSection: i)
}
【讨论】:
Swift 4 和 Swift 5
我们可以执行以下操作,因为空白部分仍然可以有可见的标题视图:
extension UITableView {
var indexesOfVisibleSections: [Int] {
var indexes = [Int]()
(0 ..< numberOfSections).forEach {
let headerRect = (style == .plain ?
rect(forSection: $0) :
rectForHeader(inSection: $0))
// The "visible part" of the tableView is based on the
// content offset and the tableView's size.
let visiblePartOfTableView =
CGRect(x: contentOffset.x, y: contentOffset.y,
width: bounds.size.width, height: bounds.size.height)
if (visiblePartOfTableView.intersects(headerRect)) {
indexes.append($0)
}
}
return indexes
}
}
【讨论】:
你在 Swift 4 中试过这个吗?
let sections = tableView.indexPathsForVisibleRows?.map { $0.section } ?? []
for section in sections {
print(String(format: "%d", section))
}
【讨论】: