UITableView无限滚动
如何在UITableView
进行无限滚动? 我知道如何使用UIScrollView
来做到这一点,苹果已经在WWDC的一个video中演示了这个video。 我试着在tableView:cellForRowAtIndexPath:
执行以下操作tableView:cellForRowAtIndexPath:
::
if (indexPath.row == [self.newsFeedData_ count] - 1) { [self.newsFeedData_ addObjectsFromArray:self.newsFeedData_]; [self.tableView reloadData]; }
但是这失败了。 任何其他的想法?
如果您需要知道何时触击了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]; } }
您可以支持无限滚动拉动刷新顶部和/或连续滚动底部的旋转轮使用:
https://github.com/samvermette/SVPullToRefresh
当UITableView
到达底部时, SVPullToRefresh
处理逻辑。 微调器自动显示,callback块被触发。 您将业务逻辑添加到callback块。
这是一个例子:
#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添加到您的项目中,或者直接编译到您的项目中。
下面是一个非常快速和完整的演示了一个无限的滚动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
“UITableView”与“scrollViewDidScroll”方法中的“UIScrollView”相同。
所以,它很容易模仿无限滚动。
-
加倍数组,使头部和尾部连在一起模拟圆形桌子
-
使用我的下面的代码,当他们倾向于到达表的开始或结束时,使用户在加倍表的第一部分和加倍表的第二部分之间进行切换。
:
/* 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))); } }
PS – 我在我的一个名为NT Time Table(Lite)的应用程序中使用了这个代码。 如果你想预览,你可以看看这个应用程序: https : //itunes.apple.com/au/app/nt-time-table-lite/id528213278?mt=8
如果你的表有时可能太短,在上面的方法的开始,你可以添加一个if逻辑来退出方法,当数据计数是说例如小于9。
对于我更好的scrollViewDidEndDragging:比scrollViewDidScroll:。
第二种方法会在滚动期间向您发送每个位置,并且如果您正在获取远程资源,则会多次触发您的端点,这是不好的。
基于@codafi解决scheme的完整示例,来自@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]; } }
通常我会重写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
而不是重写,我们可以在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]]; } } } } }
其中一个简单而且给我提供了我需要的所有东西就是这个类:
https://github.com/jakemarsh/JMStatefulTableViewController
你只需要JMStatefulTableViewController的子类,它有3个方法,你需要覆盖:
- 一个在init上调用,以获取初始数据
- statefulTableViewControllerWillBeginInitialLoading
- 一个当用户拉动刷新
- statefulTableViewControllerWillBeginLoadingFromPullToRefresh
- 一个当被称为无限滚动(下一页)
- statefulTableViewControllerWillBeginLoadingNextPage
这也可以从Cocoapods使用。