UITableViewCell이 완전히 보이는지 확인하는 가장 좋은 방법
높이가 다른 셀이있는 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 :
이것은 lnafziger 와 Vadim 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];
}
rectForRowAtIndexPath:
메서드 를 사용하여 셀의 사각형을 얻고 CGRectContainsRect
함수를 사용하여 tableview의 경계 사각형과 비교할 수 있습니다.
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
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.
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];
}
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];
}
}
}
}
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
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:
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)
}
}
- (BOOL)checkVisibilityOfCell{
if (tableView.contentSize.height <= tableView.frame.size.height) {
return YES;
} else{
return NO;
}
}
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)
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
}
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
}
}
Maybe for this issue better used next function from UITableViewDelegate
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath)
'developer tip' 카테고리의 다른 글
Python에서 numpy.random과 random.random의 차이점 (0) | 2020.09.10 |
---|---|
Node.js + Express : 경로 대 컨트롤러 (0) | 2020.09.10 |
저장되지 않은 변경 사항 감지 (0) | 2020.09.09 |
시간을 사용하지 않고 모든 고 루틴이 끝날 때까지 기다리는 방법. (0) | 2020.09.09 |
방정식에서 중괄호 옆에있는 두 개의 문 (0) | 2020.09.09 |