ios 检查 UITableViewCell 是否完全可见的最佳方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9831485/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 17:30:21  来源:igfitidea点击:

Best way to check if UITableViewCell is completely visible

iosuitableviewvisible

提问by RohinNZ

I have a UITableView with cells of different heights and I need to know when they are completelyvisible or not.

我有一个带有不同高度单元格的 UITableView,我需要知道它们何时完全可见。

At the moment I am looping through each cell in the list of visible cells to check if it is completely visible every time the view is scrolled . Is this the best approach?

目前,我正在循环查看可见单元格列表中的每个单元格,以检查每次滚动视图时它是否完全可见。这是最好的办法?

Here's my code:

这是我的代码:

- (void)scrollViewDidScroll:(UIScrollView *)aScrollView {

    CGPoint offset = aScrollView.contentOffset;
    CGRect bounds = aScrollView.bounds;    
    NSArray* cells = myTableView.visibleCells;

    for (MyCustomUITableViewCell* cell in cells) {

        if (cell.frame.origin.y > offset.y &&
            cell.frame.origin.y + cell.frame.size.height < offset.y + bounds.size.height) {

            [cell notifyCompletelyVisible];
        }
        else {

            [cell notifyNotCompletelyVisible];
        }
    }
}

Edit:

编辑:

Please note that *- (NSArray )visibleCellsreturns visible cells which are both completely visible and partly visible.

请注意 *- (NSArray )visibleCells返回完全可见和部分可见的可见单元格。

Edit 2:

编辑2:

This is the revised code after combining solutions from both lnafzigerand Vadim Yelagin:

这是结合lnafzigerVadim Yelagin 的解决方案后的修订代码:

- (void)scrollViewDidScroll:(UIScrollView *)aScrollView {
    NSArray* cells = myTableView.visibleCells;
    NSArray* indexPaths = myTableView.indexPathsForVisibleRows;

    NSUInteger cellCount = [cells count];

    if (cellCount == 0) return;

    // Check the visibility of the first cell
    [self checkVisibilityOfCell:[cells objectAtIndex:0] forIndexPath:[indexPaths objectAtIndex:0]];

    if (cellCount == 1) return;

    // Check the visibility of the last cell
    [self checkVisibilityOfCell:[cells lastObject] forIndexPath:[indexPaths lastObject]];

    if (cellCount == 2) return;

    // All of the rest of the cells are visible: Loop through the 2nd through n-1 cells
    for (NSUInteger i = 1; i < cellCount - 1; i++)
        [[cells objectAtIndex:i] notiVisibleWithIsCompletelyVisible:YES];
}

- (void)checkVisibilityOfCell:(MultiQuestionTableViewCell *)cell forIndexPath:(NSIndexPath *)indexPath {
    CGRect cellRect = [myTableView rectForRowAtIndexPath:indexPath];
    cellRect = [myTableView convertRect:cellRect toView:myTableView.superview];
    BOOL completelyVisible = CGRectContainsRect(myTableView.frame, cellRect);

    [cell notiVisibleWithIsCompletelyVisible:completelyVisible];
}

回答by Vadim Yelagin

You can get the rect of a cell with rectForRowAtIndexPath:method and compare it with tableview's bounds rect using CGRectContainsRectfunction.

您可以使用rectForRowAtIndexPath:方法获取单元格的矩形,并使用CGRectContainsRect函数将其与表格视图的边界矩形进行比较。

Note that this will not instantiate the cell if it is not visible, and thus will be rather fast.

请注意,如果它不可见,这将不会实例化单元格,因此会相当快。

Swift

迅速

let cellRect = tableView.rectForRowAtIndexPath(indexPath)
let completelyVisible = tableView.bounds.contains(cellRect)

Obj-C

对象-C

CGRect cellRect = [tableView rectForRowAtIndexPath:indexPath];
BOOL completelyVisible = CGRectContainsRect(tableView.bounds, cellRect);

Of course this will not regard the table view being clipped by a superview or obscured by another view.

当然,这不会考虑 table view 被 superview 剪辑或被另一个 view 遮挡。

回答by lnafziger

I would change it like this:

我会像这样改变它:

- (void)checkVisibilityOfCell:(MyCustomUITableViewCell *)cell inScrollView:(UIScrollView *)aScrollView {
    CGRect cellRect = [aScrollView convertRect:cell.frame toView:aScrollView.superview];

    if (CGRectContainsRect(aScrollView.frame, cellRect))
        [cell notifyCompletelyVisible];
    else
        [cell notifyNotCompletelyVisible];
}

- (void)scrollViewDidScroll:(UIScrollView *)aScrollView { 
    NSArray* cells = myTableView.visibleCells;

    NSUInteger cellCount = [cells count];
    if (cellCount == 0)
        return;

    // Check the visibility of the first cell
    [self checkVisibilityOfCell:[cells firstObject] inScrollView:aScrollView];
    if (cellCount == 1)
        return;

    // Check the visibility of the last cell
    [self checkVisibilityOfCell:[cells lastObject] inScrollView:aScrollView];
    if (cellCount == 2)
        return;

    // All of the rest of the cells are visible: Loop through the 2nd through n-1 cells
    for (NSUInteger i = 1; i < cellCount - 1; i++)
        [[cells objectAtIndex:i] notifyCompletelyVisible];
}

回答by Catalin

You can try something like this to see how much percentage is visible:

您可以尝试这样的操作,看看有多少百分比是可见的:

-(void)scrollViewDidScroll:(UIScrollView *)sender
{
    [self checkWhichVideoToEnable];
}

-(void)checkWhichVideoToEnable
{
    for(UITableViewCell *cell in [tblMessages visibleCells])
    {
        if([cell isKindOfClass:[VideoMessageCell class]])
        {
            NSIndexPath *indexPath = [tblMessages indexPathForCell:cell];
            CGRect cellRect = [tblMessages rectForRowAtIndexPath:indexPath];
            UIView *superview = tblMessages.superview;

            CGRect convertedRect=[tblMessages convertRect:cellRect toView:superview];
            CGRect intersect = CGRectIntersection(tblMessages.frame, convertedRect);
            float visibleHeight = CGRectGetHeight(intersect);

            if(visibleHeight>VIDEO_CELL_SIZE*0.6) // only if 60% of the cell is visible
            {
                // unmute the video if we can see at least half of the cell
                [((VideoMessageCell*)cell) muteVideo:!btnMuteVideos.selected];
            }
            else
            {
                // mute the other video cells that are not visible
                [((VideoMessageCell*)cell) muteVideo:YES];
            }
        }
    }
}

回答by CodaFi

From the docs:

从文档:

visibleCells Returns the table cells that are visible in the receiver.

- (NSArray *)visibleCells

Return Value An array containing UITableViewCell objects, each representing a visible cell in the receiving table view.

Availability Available in iOS 2.0 and later.

See Also – indexPathsForVisibleRows

visibleCells 返回在接收器中可见的表格单元格。

- (NSArray *)visibleCells

返回值 一个包含 UITableViewCell 对象的数组,每个对象代表接收表视图中的一个可见单元格。

可用性 在 iOS 2.0 及更高版本中可用。

另请参阅 – indexPathsForVisibleRows

回答by Kukosk

If you also want to take the contentInset into account, and don't want to rely on a superview (the table view frame in superview could be something else than 0,0), here's my solution:

如果您还想考虑 contentInset,并且不想依赖超级视图(超级视图中的表视图框架可能不是 0,0),这是我的解决方案:

extension UITableView {

    public var boundsWithoutInset: CGRect {
        var boundsWithoutInset = bounds
        boundsWithoutInset.origin.y += contentInset.top
        boundsWithoutInset.size.height -= contentInset.top + contentInset.bottom
        return boundsWithoutInset
    }

    public func isRowCompletelyVisible(at indexPath: IndexPath) -> Bool {
        let rect = rectForRow(at: indexPath)
        return boundsWithoutInset.contains(rect)
    }
}

回答by Naresh Jain

- (BOOL)checkVisibilityOfCell{
    if (tableView.contentSize.height <= tableView.frame.size.height) {
        return YES;
    } else{
        return NO;
    }
}

回答by iRestMyCaseYourHonor

Even if you said you want to check it every time you scrolled, you can also use

即使你说你每次滚动时都要检查它,你也可以使用

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
       CGRect cellRect = [tableView convertRect:cell.frame toView:tableView.superview];
       if (CGRectContainsRect(tableView.frame, cellRect)){
            //Do things in case cell is fully displayed
        }

}

回答by Artyom

Maybe for this issue better used next function from UITableViewDelegate

也许对于这个问题更好地使用 UITableViewDelegate 的下一个函数

func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath)

回答by Andy Poes

UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:indexPath];
CGRect frame = cell.frame;
if (CGRectContainsRect(CGRectOffset(self.collectionView.frame, self.collectionView.contentOffset.x, self.collectionView.contentOffset.y), frame))
{
    // is on screen
}

回答by fahlout

The code below will let you check if a collection view cell is completely visible through the layout attributes of the collection view.

下面的代码将让您通过集合视图的布局属性检查集合视图单元格是否完全可见。

guard let cellRect = collectionView.layoutAttributesForItem(at: indexPath)?.frame else { return } let isCellCompletelyVisible = collectionView.bounds.contains(cellRect)

guard let cellRect = collectionView.layoutAttributesForItem(at: indexPath)?.frame else { return } let isCellCompletelyVisible = collectionView.bounds.contains(cellRect)