UITableViewCell이 완전히 보이는지 확인하는 가장 좋은 방법


100

높이가 다른 셀이있는 UITableView가 있으며 언제 완전히 표시 되는지 여부를 알아야 합니다.

현재 나는 보이는 셀 목록의 각 셀을 반복하여보기를 스크롤 할 때마다 완전히 보이는지 확인합니다. 이것이 최선의 접근 방식입니까?

내 코드는 다음과 같습니다.

- (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];
        }
    }
}

편집하다:

*-(NSArray ) visibleCells 는 완전히 표시되고 부분적으로 표시되는 표시 셀을 반환합니다.

편집 2 :

이것은 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] notifyCellVisibleWithIsCompletelyVisible: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 notifyCellVisibleWithIsCompletelyVisible:completelyVisible];
}

3
부수적으로, 이전의 모든 질문으로 이동하여 도움을 준 사람들의 답변을 수락해야합니다.
Baub

4
말해 주셔서 감사합니다! 나는 이미 그들에게 +1을 주었지만 설정된 수락 답변 기능에 대해 잊었습니다.
RohinNZ

귀하의 코드는 나에게 맞아 보이며 복잡하지만 작동합니다. 고장 나지 않은 것을 고치지 마세요, 어?
CodaFi

답변:


125

rectForRowAtIndexPath:메서드 를 사용하여 셀의 사각형을 얻고 CGRectContainsRect함수를 사용하여 tableview의 경계 사각형과 비교할 수 있습니다.

셀이 보이지 않으면 인스턴스화하지 않으므로 다소 빠릅니다.

빠른

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

Obj-C

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

물론 이것은 테이블 뷰가 수퍼 뷰에 의해 잘 리거나 다른 뷰에 의해 가려지는 것을 고려하지 않습니다.


감사합니다! 이 코드를 lnafziger의 솔루션과 결합했습니다.
RohinNZ 2012 년

11
두 번째 생각에 그것은 단지 될 수 있습니다CGRectContainsRect(tableView.bounds, [tableView rectForRowAtIndexPath:indexPath])
Vadim Yelagin

1
왜 내 cellRect의 origin.x = 0, origin.y = 0, width = 0, height = 0입니까? UI에서는 모두 0이 아니지만 자동 레이아웃을 사용하고 있습니다. 아이디어가 있습니까?
RainCast

7
Swift 3 :let completelyVisible = tableView.bounds.contains(tableView.rectForRow(at: indexPath))
cbartel

UICollectionView의 유사한 기능을 어떻게 처리 할 수 ​​있습니까?
Satyam

64

다음과 같이 변경합니다.

- (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];
}

if 문의 <및>는 <= 또는> =이어야합니다. 대답에서이 문제를 수정하겠습니다 ...
Aardvark

12

얼마나 많은 백분율이 표시되는지 확인하려면 다음과 같이 시도 할 수 있습니다.

-(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];
            }
        }
    }
}

테이블보기에 동영상이 포함 된 2 개의 셀이 표시 될 수있는 경우 (예 : iPad에서) 두 동영상 모두 위의 코드로 재생됩니다.?
Jerome

@Catalin 귀하의 솔루션을 시도했지만 내 tableview가 느려집니다. 스크롤 성능을 향상시킬 수있는 방법이 있습니까?
Rahul Vyas

@RahulVyas 죄송하지만 :(이 층 / 하위 레이어에 관하여 당신의 내면의 요소는 아마도 레이아웃이 조금을 최적화 할 수 있습니다 확인하지
CATALIN

5

문서에서 :

visibleCells 수신자에서 볼 수있는 테이블 셀을 반환합니다.

- (NSArray *)visibleCells

반환 값 UITableViewCell 개체를 포함하는 배열로, 각 개체는 수신 테이블보기에서 표시되는 셀을 나타냅니다.

iOS 2.0 이상에서 사용 가능합니다.

참조 – indexPathsForVisibleRows


4
내가 충분히 명확하지 않았을 수도 있습니다. 나는 완전히 보이는 세포에만 관심이 있습니다. -(NSArray *) visibleCells 및 indexPathsForVisibleRows는 모두 완전히 표시되고 부분적으로 표시되는 셀을 반환합니다. 내 코드에서 볼 수 있듯이 이미-(NSArray *) visibleCells를 사용하여 완전히 보이는 것을 찾습니다. 어쨌든 감사합니다.
RohinNZ 2012 년

4

contentInset도 고려하고 수퍼 뷰에 의존하고 싶지 않은 경우 (superview의 테이블 뷰 프레임은 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)
    }
}

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

0
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
}

0

스크롤 할 때마다 확인하고 싶다고해도

-(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
        }

}

0

이 문제에 대해 UITableViewDelegate의 다음 함수를 더 잘 사용했을 수 있습니다.

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

작동하지 않습니다. 문서에서tells the delegate that the specified cell was removed from the table.
anatoliy_v

0

아래 코드는 컬렉션 뷰의 레이아웃 속성을 통해 컬렉션 뷰 셀이 완전히 보이는지 확인할 수 있습니다.

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.