UITableView бесконечная прокрутка
Как сделать бесконечную прокрутку в UITableView
? Я знаю, как это сделать, используя UIScrollView
, в котором Apple продемонстрировала в одном из видео WWDC. Я попытался сделать следующее в tableView:cellForRowAtIndexPath:
:
if (indexPath.row == [self.newsFeedData_ count] - 1)
{
[self.newsFeedData_ addObjectsFromArray:self.newsFeedData_];
[self.tableView reloadData];
}
но это не удается. Любая другая идея?
Ответы
Ответ 1
Если вам нужно знать, когда вы попадете в нижнюю часть 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];
}
}
Ответ 2
Вы можете поддерживать бесконечную прокрутку с вытягиванием для обновления вверху и/или непрерывно прокручивать снизу с помощью вращающегося колеса, используя:
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 или напрямую скомпилирован в ваш проект.
Ответ 3
Здесь очень быстрая и полная демонстрация бесконечного прокрутки 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
Ответ 4
"UITableView" аналогичен "UIScrollView" в методе "scrollViewDidScroll".
Таким образом, его легко эмулировать бесконечную прокрутку.
-
удваивайте массив так, чтобы голова и хвост были соединены вместе, чтобы эмулировать круговую таблицу
-
используйте мой следующий код, чтобы пользователь переключался между 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.
Ответ 5
Для меня лучше работать 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];
}
}
Ответ 6
Как правило, я переопределяю 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
Ответ 7
а не переопределять, мы можем сделать это оптимально в layoutSubviews.
Вот как я его реализовал. Вы можете узнать больше о реализации здесь
- (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]];
}
}
}
}
}
Ответ 8
Один из простых и предложил мне все, что мне нужно, это класс:
https://github.com/jakemarsh/JMStatefulTableViewController
Вам просто нужно подклассифицировать JMStatefulTableViewController, и у него есть 3 метода, которые необходимо перезаписать:
- тот, который вызывается в init, чтобы получить исходные данные
- statefulTableViewControllerWillBeginInitialLoading
- один, когда пользователь пытается обновить
- statefulTableViewControllerWillBeginLoadingFromPullToRefresh
- один, когда вызывается для бесконечного прокрутки (следующая страница)
- statefulTableViewControllerWillBeginLoadingNextPage
Это можно использовать и из Cocoapods.
Ответ 9
scrollviewDidScroll будет вызываться при перемещении по строкам в табличном представлении
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//check for the visible rows
let indexpath = self.tableView.indexPathsForVisibleRows?.last
//check if the visible row last is equal to the total number of counts
if(indexpath?.last == self.listCount){
//code for adding data to the tableview and reload the table view.
}
}
для получения более подробной информации о indexPathForVisibleRows перейдите по ссылке https://developer.apple.com/documentation/uikit/uitableview/1614885-indexpathsforvisiblerows.