Лучший способ проверить, является ли 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];
}
}
}
Edit:
Обратите внимание, что * - (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];
}
Ответы
Ответ 1
Я бы изменил его следующим образом:
- (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];
}
Ответ 2
Вы можете получить прямоугольник ячейки с помощью rectForRowAtIndexPath:
и сравнить его с ограничениями tableview bounds с помощью CGRectContainsRect
.
Обратите внимание, что это не будет создавать экземпляр ячейки, если она не видна, и, следовательно, будет довольно быстрой.
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);
Конечно, это не будет означать, что представление таблицы обрезается надстройкой или закрывается другим видом.
Ответ 3
Вы можете попробовать что-то подобное, чтобы увидеть, сколько процентов видно:
-(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];
}
}
}
}
Ответ 4
Из документов:
visibleCells Возвращает ячейки таблицы, которые видны в ресивере.
- (NSArray *)visibleCells
Возвращаемое значение Массив, содержащий объекты UITableViewCell, каждый представляя видимую ячейку в получение табличного представления.
Доступность Доступна в iOS 2.0 и более поздних версиях.
См. также - indexPathsForVisibleRows
Ответ 5
- (BOOL)checkVisibilityOfCell{
if (tableView.contentSize.height <= tableView.frame.size.height) {
return YES;
} else{
return NO;
}
}
Ответ 6
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
}
Ответ 7
Даже если вы сказали, что хотите проверять его каждый раз, когда вы прокручиваете, вы также можете использовать
-(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
}
}