2012-05-01 2 views
38

Как сделать бесконечную прокрутку в UITableView? Я знаю, как это сделать, используя UIScrollView, в котором Apple продемонстрировала в одном из видео WWDC. Я пробовал сделать следующее: tableView:cellForRowAtIndexPath::UITableView бесконечная прокрутка

if (indexPath.row == [self.newsFeedData_ count] - 1) 
{ 
    [self.newsFeedData_ addObjectsFromArray:self.newsFeedData_]; 
    [self.tableView reloadData]; 
} 

но это не удается. Любая другая идея?

+0

Если вы NSLog 'self.newsFeedData_' до и после вызова' [самоуправления .newsFeedData_ addObjectsFromArray: self.newsFeedData _]; 'это то же самое? (Возможно, начните с выведения '[self.newsFeedData_ count]' и посмотрите, увеличилось ли количество записей в массиве? – runmad

+0

Вот демо бесконечного UITableView в Swift: https://github.com/i-schuetz/ tableview_infinite – Ixx

+0

Я добавил [ответ здесь] (http://stackoverflow.com/a/42902171/882630), который использует таблицу UITableViewDelegate View (_: будет отображать: для строки в:) метод экземпляра очень просто. – lukkea

ответ

54

Если вам нужно знать, когда вы попадаете в нижнюю часть UITableView, станьте его делегатом (потому что это подкласс UIScrollView) и используйте метод -scrollViewDidScroll: delegate для сравнения высоты содержимого таблицы и фактической позиции прокрутки ,

EDIT (что-то вроде этого):

- (void)scrollViewDidScroll:(UIScrollView *)scrollView_ 
{ 
    CGFloat actualPosition = scrollView_.contentOffset.y; 
    CGFloat contentHeight = scrollView_.contentSize.height - (someArbitraryNumber); 
    if (actualPosition >= contentHeight) { 
     [self.newsFeedData_ addObjectsFromArray:self.newsFeedData_]; 
     [self.tableView reloadData]; 
    } 
} 
+0

Почему мой код выше не работает? – adit

+0

Хм ... может быть, ваш массив как-то пуст? – CodaFi

+0

нет, это не пусто, я дважды проверял – adit

12

'UITableView' такой же, как 'UIScrollView' в методе 'scrollViewDidScroll'.

Таким образом, его легко эмулировать бесконечную прокрутку.

  1. двойной массив так, чтобы голова и хвост соединяются вместе, чтобы эмулировать круглый стол

  2. использовать мой следующий код, чтобы пользователю переключаться между 1-й части удвоенного стола и 2-й части удвоенного стола, когда они, как правило для достижения начала или конца таблицы.

:

/* To emulate infinite scrolling... 

The table data was doubled to join the head and tail: (suppose table had 1,2,3,4) 
1 2 3 4|1 2 3 4 (actual data doubled) 
--------------- 
1 2 3 4 5 6 7 8 (visualising joined table in eight parts) 

When the user scrolls backwards to 1/8th of the joined table, user is actually at the 1/4th of actual data, so we scroll instantly (we take user) to the 5/8th of the joined table where the cells are exactly the same. 

Similarly, when user scrolls to 6/8th of the table, we will scroll back to 2/8th where the cells are same. (I'm using 6/8th when 7/8th sound more logical because 6/8th is good for small tables.) 

In simple words, when user reaches 1/4th of the first half of table, we scroll to 1/4th of the second half, when he reaches 2/4th of the second half of table, we scroll to the 2/4 of first half. This is done simply by subtracting OR adding half the length of the new/joined table. 
*/ 


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

    CGFloat currentOffsetX = scrollView_.contentOffset.x; 
    CGFloat currentOffSetY = scrollView_.contentOffset.y; 
    CGFloat contentHeight = scrollView_.contentSize.height; 

    if (currentOffSetY < (contentHeight/8.0)) { 
    scrollView_.contentOffset = CGPointMake(currentOffsetX,(currentOffSetY + (contentHeight/2))); 
    } 
    if (currentOffSetY > ((contentHeight * 6)/ 8.0)) { 
     scrollView_.contentOffset = CGPointMake(currentOffsetX,(currentOffSetY - (contentHeight/2))); 
    } 

} 

P.S. - Я использовал этот код в одном из моих приложений под названием NT Time Table (Lite). Если вы хотите просмотреть предварительный просмотр, вы можете проверить приложение: https://itunes.apple.com/au/app/nt-time-table-lite/id528213278?mt=8

Если ваша таблица иногда может быть слишком короткой, в начале вышеприведенного метода вы можете добавить логику if, чтобы выйти из метода, когда число данных указано для пример менее 9.

+0

Привет, не могли бы вы рассказать мне о расчетах «8.0» и «((contentHeight * 6)/8.0)»? Связано ли это с «no of rows» в tableview? Пожалуйста, дайте мне знать. –

+0

Нет, его нет. Это означает 6/8-й полной длины таблицы (а не только видимой области). Поэтому, когда пользователь достигает конца (6/8) таблицы, они берутся в первую часть данных (поскольку мы удвоили данные), где данные одинаковы. Аналогично, при прокрутке вверх до 1/8 таблицы, они переводятся во вторую часть таблицы, где данные одинаковы. –

1

, а не переопределение, мы можем сделать это оптимально в layoutSubviews. Вот как я его реализовал. Вы можете узнать больше о реализации here

- (void)layoutSubviews{ 
[super layoutSubviews]; 

if(self.delegateForViews){ 

    CGPoint contentOffset = self.contentOffset; 

    if([self.delegateForViews noOfViews]>numOfReusableViews){ 
     NSUInteger centerIndex=visibleViews.count/2; 
     NSUInteger noOfViews=[self.delegateForViews noOfViews]; 
     UIView *centerView=[visibleViews objectAtIndex:centerIndex]; 

     CGPoint centerViewOrigin=centerView.frame.origin; 
     CGSize centerViewSize=centerView.frame.size; 
     CGFloat offsetDifference=contentOffset.x-centerViewOrigin.x; 
     CGFloat offsetDifferenceAbs=fabs(contentOffset.x-centerViewOrigin.x); 

     if(offsetDifferenceAbs>=centerViewSize.width){ 

      if(offsetDifference<0){ 
       currentPosition--; 
      }else{ 
       currentPosition++; 
      } 

      self.contentOffset=centerViewOrigin; 

      currentPosition=[self getPosition:currentPosition noOfViews:noOfViews]; 

      [self.delegateForViews clearView:centerView]; 
      [self.delegateForViews setupView:centerView forPosition:currentPosition]; 

      for (int i=centerIndex-1; i>=0; i--) { 
       UIView* prevView=[visibleViews objectAtIndex:i]; 
       [self.delegateForViews clearView:prevView]; 
       [self.delegateForViews setupView:prevView forPosition: 
         [self getPosition:currentPosition-1 noOfViews:noOfViews]]; 
      } 

      for (int i=centerIndex+1; i<visibleViews.count; i++) { 
       UIView* nextView=[visibleViews objectAtIndex:i]; 
       [self.delegateForViews clearView:nextView]; 
       [self.delegateForViews setupView:nextView forPosition: 
         [self getPosition:currentPosition+1 noOfViews:noOfViews]]; 
      } 

     } 
    } 

} 

} 
16

Вот очень быстрый и полный демо бесконечной прокрутки UITableView я вместе взятые ...

@interface InfiniteScrollViewController() 

@property (nonatomic) NSMutableArray *tableViewData; 
@property (nonatomic) BOOL loadingMoreTableViewData; 

@end 

@implementation InfiniteScrollViewController 

- (void)viewDidLoad { 
    self.tableViewData = [[NSMutableArray alloc] init]; 
    [self addSomeMoreEntriesToTableView]; 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    return self.tableViewData.count + 1; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    static NSString *CellIdentifier = @"Cell"; 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 
    } 

    if (indexPath.row < self.tableViewData.count) { 
     cell.textLabel.text = [self.tableViewData objectAtIndex:indexPath.row]; 
    } else { 
     cell.textLabel.text = @"Loading more data..."; 

     // User has scrolled to the bottom of the list of available data so simulate loading some more if we aren't already 
     if (!self.loadingMoreTableViewData) { 
      self.loadingMoreTableViewData = YES; 
      [self performSelector:@selector(addSomeMoreEntriesToTableView) withObject:nil afterDelay:5.0f]; 
     } 
    } 

    return cell; 
} 

- (void)addSomeMoreEntriesToTableView { 
    int loopTill = self.tableViewData.count + 20; 
    while (self.tableViewData.count < loopTill) { 
     [self.tableViewData addObject:[NSString stringWithFormat:@"%i", self.tableViewData.count]]; 
    }; 
    self.loadingMoreTableViewData = NO; 
    [self.tableView reloadData]; 
} 

@end 
+1

[self.tableView reloadData] может вызвать мерцание страницы. Я знаю, что могу использовать [self.tableView beginUpdates] и [self.tableView endUpdates], но не уверен, как правильно его использовать .. – trillions

+1

Да, в моем методе addSomeMOreEntriesToTableView вместо вызова reloadData вы должны создать массив из NSIndexPath, а затем вызвать beginUpdates, за которым следует insertrowAtIndexPaths: withRowAnimations: (передача массива indexPaths) и, наконец, endUpdates. –

+0

спасибо! Я попробую это утром, слишком устал сейчас ~ обновится :) – trillions

18

Вы можете поддержать бесконечный свиток с тягой к обновить в верхней и/или непрерывной прокрутки в нижней части с вращаемой колеса с помощью:

https://github.com/samvermette/SVPullToRefresh

SVPullToRefresh обрабатывает логику, когда UITableView достигает дна. Прямоугольник отображается автоматически и загорается блок обратного вызова. Вы добавляете свою бизнес-логику в блок обратного вызова.

Вот пример:

#import "UIScrollView+SVInfiniteScrolling.h" 

// ... 

[tableView addInfiniteScrollingWithActionHandler:^{ 
    // append data to data source, insert new cells at the end of table view 
    // call [tableView.infiniteScrollingView stopAnimating] when done 
}]; 

Этот проект может быть добавлен в ваш проект с использованием CocoaPods или непосредственно компилируется в ваш проект.

0

Одним из простых и предложил мне все, что нужно это класс:

https://github.com/jakemarsh/JMStatefulTableViewController

Вам просто нужно подкласс JMStatefulTableViewController и имеет 3 метода, которые нужно перезаписать:

  • тот, который вызывается по init, для получения исходных данных
    • statefulTableViewControllerWillBeginInitialLoading
  • один, когда тянуть пользователю обновить
    • statefulTableViewControllerWillBeginLoadingFromPullToRefresh
  • один, когда вызывается для бесконечной прокрутки (следующая страница)
    • statefulTableViewControllerWillBeginLoadingNextPage

Это может использоваться и от Cocoapods.

3

Обычно я переопределяю scrollViewDidEndDecelerating и внутри него я поместил свой код, чтобы запросить больше данных.
Пример:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{ 

    float endScrolling = scrollView.contentOffset.y + scrollView.frame.size.height; 

    if (endScrolling >= scrollView.contentSize.height){ 
     //put here your code 

    } 
} 

Недавно я загрузил на GitHub подкласс UITableView, который реализует бесконечный свиток.
Вы можете скачать его здесь:
https://github.com/alchimya/iOS-LazyTableView

3

Для меня работал лучше scrollViewDidEndDragging: чем scrollViewDidScroll:.

Второй подход пошлет вам каждую позицию во время прокрутки и вызовет, если вы извлекаете удаленные ресурсы, вы будете поражать свою конечную точку несколько раз, что не очень хорошо.

Полный пример, основанный на @codafi раствора с комментариями от @danielgomezrico о том, как рассчитать contentHeight:

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView 
        willDecelerate:(BOOL)decelerate { 
    CGFloat actualPosition = scrollView.contentOffset.y; 
    CGFloat contentHeight = scrollView.contentSize.height - (self.tableView.frame.size.height); 
    if (actualPosition >= contentHeight) { 
     // fetch resources 
     [self.tableView reloadData]; 
    } 
} 
Смежные вопросы