Как определить конец загрузки UITableView - PullRequest
131 голосов
/ 12 ноября 2010

Я хочу изменить смещение таблицы, когда загрузка закончится, и это смещение зависит от количества ячеек, загруженных в таблицу.

В любом случае на SDK знать, когда загрузка uitableview закончилась? Я не вижу ничего ни в делегате, ни в протоколах источника данных.

Я не могу использовать количество источников данных из-за загрузки только видимых ячеек.

Ответы [ 21 ]

215 голосов
/ 26 июля 2012

Улучшить до ответа @RichX: lastRow может быть как [tableView numberOfRowsInSection: 0] - 1, так и ((NSIndexPath*)[[tableView indexPathsForVisibleRows] lastObject]).row.Поэтому код будет:

-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([indexPath row] == ((NSIndexPath*)[[tableView indexPathsForVisibleRows] lastObject]).row){
        //end of loading
        //for example [activityIndicator stopAnimating];
    }
}

ОБНОВЛЕНИЕ: Что ж, комментарий @ htafoya верен.Если вы хотите, чтобы этот код обнаружил окончание загрузки всех данных из источника, это не так, но это не оригинальный вопрос.Этот код предназначен для обнаружения, когда отображаются все ячейки, которые должны быть видимыми.willDisplayCell: используется здесь для более плавного пользовательского интерфейса (одна ячейка обычно отображается быстро после вызова willDisplay:).Вы также можете попробовать это с tableView:didEndDisplayingCell:.

27 голосов
/ 24 мая 2011

Я всегда использую это очень простое решение:

-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if([indexPath row] == lastRow){
        //end of loading
        //for example [activityIndicator stopAnimating];
    }
}
21 голосов
/ 16 июня 2017

Версия Swift 3 & 4:

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if let lastVisibleIndexPath = tableView.indexPathsForVisibleRows?.last {
        if indexPath == lastVisibleIndexPath {
            // do here...
        }
    }
}
10 голосов
/ 01 мая 2013

Вот еще один вариант, который мне подходит. В методе делегата viewForFooter проверьте, является ли это последним разделом, и добавьте туда свой код. Этот подход пришёл в голову после осознания того, что willDisplayCell не учитывает нижние колонтитулы, если они у вас есть.

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section 
{
  // Perform some final layout updates
  if (section == ([tableView numberOfSections] - 1)) {
    [self tableViewWillFinishLoading:tableView];
  }

  // Return nil, or whatever view you were going to return for the footer
  return nil;
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
  // Return 0, or the height for your footer view
  return 0.0;
}

- (void)tableViewWillFinishLoading:(UITableView *)tableView
{
  NSLog(@"finished loading");
}

Я считаю, что этот подход работает лучше всего, если вы ищете конечную загрузку для всего UITableView, а не просто для видимых ячеек. В зависимости от ваших потребностей вам могут потребоваться только видимые ячейки, и в этом случае ответ folex является хорошим маршрутом.

10 голосов
/ 25 декабря 2015

Swift 2 решение:

// willDisplay function
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    let lastRowIndex = tableView.numberOfRowsInSection(0)
    if indexPath.row == lastRowIndex - 1 {
        fetchNewDataFromServer()
    }
}

// data fetcher function
func fetchNewDataFromServer() {
    if(!loading && !allDataFetched) {
        // call beginUpdates before multiple rows insert operation
        tableView.beginUpdates()
        // for loop
        // insertRowsAtIndexPaths
        tableView.endUpdates()
    }
}
9 голосов
/ 13 декабря 2014

Попробуйте эту магию:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // cancel the perform request if there is another section
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(tableViewDidLoadRows:) object:tableView];

    // create a perform request to call the didLoadRows method on the next event loop.
    [self performSelector:@selector(tableViewDidLoadRows:) withObject:tableView afterDelay:0];

    return self.objects.count;
}

// called after the rows in the last section is loaded
-(void)tableViewDidLoadRows:(UITableView*)tableView{
    // make the cell selected after all rows loaded
    if(self.selectedObject){
        NSInteger index = [self.objects indexOfObject:self.selectedObject];
        [tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0] animated:NO scrollPosition:UITableViewScrollPositionMiddle];
    }
}

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

8 голосов
/ 21 июля 2016

Для выбранной версии ответа в Swift 3:

var isLoadingTableView = true

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if tableData.count > 0 && isLoadingTableView {
        if let indexPathsForVisibleRows = tableView.indexPathsForVisibleRows, let lastIndexPath = indexPathsForVisibleRows.last, lastIndexPath.row == indexPath.row {
            isLoadingTableView = false
            //do something after table is done loading
        }
    }
}

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

6 голосов
/ 13 января 2011

Лучший подход, который я знаю, - это ответ Эрика по адресу: Получать уведомление, когда UITableView завершил запрашивать данные?

Обновление: чтобы это работало, я должен поместить эти вызовы в -tableView:cellForRowAtIndexPath:

[tableView beginUpdates];
[tableView endUpdates];
1 голос
/ 16 января 2017

вот как я это делаю в Swift 3

let threshold: CGFloat = 76.0 // threshold from bottom of tableView

internal func scrollViewDidScroll(_ scrollView: UIScrollView) {

    let contentOffset = scrollView.contentOffset.y
    let maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;

    if  (!isLoadingMore) &&  (maximumOffset - contentOffset <= threshold) {
        self.loadVideosList()
    }
}
1 голос
/ 27 октября 2016

Вот что я бы сделал.

  1. В вашем базовом классе (может быть rootVC BaseVc и т. Д.),

    A.Напишите протокол для отправки обратного вызова «DidFinishReloading».

    @protocol ReloadComplition <NSObject>
    @required
    - (void)didEndReloading:(UITableView *)tableView;
    @end
    

    B.Напишите универсальный метод для перезагрузки табличного представления.

    -(void)reloadTableView:(UITableView *)tableView withOwner:(UIViewController *)aViewController;
    
  2. В реализации метода базового класса вызовите reloadData с последующим делегатомMethod с задержкой.

    -(void)reloadTableView:(UITableView *)tableView withOwner:(UIViewController *)aViewController{
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [tableView reloadData];
            if(aViewController && [aViewController respondsToSelector:@selector(didEndReloading:)]){
                [aViewController performSelector:@selector(didEndReloading:) withObject:tableView afterDelay:0];
            }
        }];
    }
    
  3. Подтвердите протокол завершения перезагрузки во всех контроллерах представления, где требуется обратный вызов.

    -(void)didEndReloading:(UITableView *)tableView{
        //do your stuff.
    }
    

Ссылка: https://discussions.apple.com/thread/2598339?start=0&tstart=0

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...