Вопрос по objective-c, ios, iphone, ipad – UITableView бесконечная прокрутка

39

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

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

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

Вот демонстрация бесконечного UITableView в Swift:github.com/i-schuetz/tableview_infinite Ixx
Я добавилan answer here в котором очень просто используется метод экземпляра таблицы UITableViewDelegate & View (_: & # x200B; will & # x200B; Display: & # x200B; for & # x200B; Row & # x200B; At: & # x200B;). lukkea
Если вы NSLogself.newsFeedData_ до и после звонка[self.newsFeedData_ addObjectsFromArray:self.newsFeedData_]; выход такой же? (Может быть, начать с вывода[self.newsFeedData_ count] и посмотреть, увеличилось ли количество записей в массиве? runmad

Ваш Ответ

8   ответов
0

https://github.com/jakemarsh/JMStatefulTableViewController

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

one that is called on init, to get the initial data statefulTableViewControllerWillBeginInitialLoading one when the user pull to refresh statefulTableViewControllerWillBeginLoadingFromPullToRefresh one when is called for the infinite scroll (next page) statefulTableViewControllerWillBeginLoadingNextPage

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

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 или напрямую скомпилирован в ваш проект.

1

s. Вот как я это реализовал. Вы можете узнать больше о реализацииВот

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

        }
    }

}

}
17

iew, которую я собрал ...

@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
Спасибо! Я попробую это утром, слишком устал сейчас ~ обновлю :)
Этот метод прекрасно работает с UICollectionViews.
Возможно, вам лучше использовать метод делегата- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath, Таким образом, вы можете избежать необходимости пользователяperformSelector
[self.tableView reloadData] может вызвать мерцание страницы. Я знаю, что могу использовать [self.tableView beginUpdates] и [self.tableView endUpdates], но не уверен, как правильно его использовать.
Да, в моем «addSomeMOreEntriesToTableView» вместо вызова reloadData вы должны создать массив NSIndexPath, затем вызвать beginUpdates, затем insertrowAtIndexPaths: withRowAnimations: (передавая массив indexPaths) и, наконец, endUpdates.
12

UITableView ; такой же, как «UIScrollView» в «scrollViewDidScroll» метод.

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

double the array so that head and tail are joined together to emulate circular table

use my following code to make user switch between 1st part of doubled table and 2nd part of doubled table when they tend to reach the start or the end of the table.

:

/* 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)));
    }

}

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

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

Здравствуйте, подскажите, пожалуйста, расчет для "8.0". и & quot; ((contentHeight * 6) / 8.0) & quot ;? Относится ли это к «количеству строк»? в виде таблицы? Пожалуйста, дайте мне знать.
Нет, это не так. Это означает 6/8 от полной длины стола (не только видимая область). Таким образом, когда пользователь достигает конца (6/8) таблицы, он переносится в первую часть данных (как мы удвоили данные), где данные совпадают. Аналогичным образом, при прокрутке вверх до 1/8 таблицы они переносятся во вторую часть таблицы, где данные совпадают.
55

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

РЕДАКТИРОВАТЬ (что-то вроде этого):

- (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];
     }
}
почему мой код выше не работает? adit
Если кому-то интересно,someArbitraryNumber показанная оказалась для меня высотой экрана
Я использовал какsomeArbitraryNumber tableView.frame.size.height
хм ... может ли быть так, что ваш массив как-то пуст?
нет, это не пусто, я дважды проверил adit
4

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

Похожие вопросы