ios UITableView 无限滚动
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10404116/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UITableView infinite scrolling
提问by adit
How do I do an infinite scrolling in a UITableView
? I know how to do it using a UIScrollView
, in which apple has demonstrated in one of the WWDC's video. I tried doing the following in tableView:cellForRowAtIndexPath:
:
如何在 a 中无限滚动UITableView
?我知道如何使用UIScrollView
,其中苹果在 WWDC 的视频之一中进行了演示。我尝试在以下内容中执行以下操作tableView:cellForRowAtIndexPath:
:
if (indexPath.row == [self.newsFeedData_ count] - 1)
{
[self.newsFeedData_ addObjectsFromArray:self.newsFeedData_];
[self.tableView reloadData];
}
but this fails. Any other idea?
但这失败了。还有其他想法吗?
回答by CodaFi
If you need to know when you hit the bottom of the UITableView, become it's delegate (because it is a subclass of UIScrollView), and use the -scrollViewDidScroll: delegate method to compare the table's content height and it's actual scroll position.
如果您需要知道何时到达 UITableView 底部,则成为它的委托(因为它是 UIScrollView 的子类),并使用 -scrollViewDidScroll: 委托方法来比较表格的内容高度和实际滚动位置。
EDIT (something like this):
编辑(类似这样):
- (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];
}
}
回答by Richard H Fung
You can support infinite scroll with pull to refresh at the top and/or scroll continuously at the bottom with a spinner wheel using:
您可以使用以下方法支持无限滚动以在顶部刷新和/或使用微调轮在底部连续滚动:
https://github.com/samvermette/SVPullToRefresh
https://github.com/samvermette/SVPullToRefresh
SVPullToRefresh
handles the logic when UITableView
reaches the bottom. A spinner is shown automatically and a callback block is fired. You add in your business logic to the callback block.
SVPullToRefresh
UITableView
到达底部时处理逻辑。自动显示微调器并触发回调块。您将业务逻辑添加到回调块中。
Here's an example:
下面是一个例子:
#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
}];
This project can be added to your project using CocoaPodsor directly compiled into your project.
这个项目可以使用CocoaPods添加到你的项目中,也可以直接编译到你的项目中。
回答by Oliver Pearmain
Here's a very quick and complete demo of an infinite scrolling UITableView I put together...
这是我放在一起的无限滚动 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
回答by Anup Kattel
'UITableView' is same as 'UIScrollView' in 'scrollViewDidScroll' method.
'UITableView' 与 'scrollViewDidScroll' 方法中的 'UIScrollView' 相同。
So, its easy to emulate infinite scrolling.
因此,很容易模拟无限滚动。
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)));
}
}
P.S. - I've used this code on one of my apps called NT Time Table (Lite). If you want the preview, you can check out the app: https://itunes.apple.com/au/app/nt-time-table-lite/id528213278?mt=8
PS - 我在我的一个名为 NT Time Table (Lite) 的应用程序中使用了此代码。如果您想要预览,可以查看应用程序:https: //itunes.apple.com/au/app/nt-time-table-lite/id528213278?mt=8
If your table can sometimes be too short, at the beginning of the above method you can add a if logic to exit the method when data count is say for example less than 9.
如果您的表有时太短,在上述方法的开头,您可以添加一个 if 逻辑以在数据计数小于 9 时退出该方法。
回答by zevarito
For me worked better scrollViewDidEndDragging:than scrollViewDidScroll:.
对我来说,scrollViewDidEndDragging:比scrollViewDidScroll:工作得更好。
The second approach will send you each position during scroll and cause, if you are fetching remote resources you will hit your endpoint several times, which is not good.
第二种方法会在滚动期间向您发送每个位置并导致,如果您正在获取远程资源,您将多次访问您的端点,这并不好。
Complete example based on @codafisolution with comments from @danielgomezricoabout how to calculate contentHeight:
基于@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];
}
}
回答by Domenico Vacchiano
Generally I override scrollViewDidEndDecelerating
and inside it I put my code to request more data.
Example:
通常我会覆盖scrollViewDidEndDecelerating
并在其中放置我的代码来请求更多数据。
例子:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
float endScrolling = scrollView.contentOffset.y + scrollView.frame.size.height;
if (endScrolling >= scrollView.contentSize.height){
//put here your code
}
}
Recently I uploaded on GitHub a subclass of UITableView, that implements the infinite scroll.
You can download it here:
https://github.com/alchimya/iOS-LazyTableView
最近在GitHub上上传了一个UITableView的子类,实现了无限滚动。
你可以在这里下载:https:
//github.com/alchimya/iOS-LazyTableView
回答by Shardul
rather than overriding we can do this optimally in layoutSubviews. Here's how I got it implemented. You can get to know more about the implementation here
我们可以在 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]];
}
}
}
}
}
回答by Yethin Dias
scrollviewDidScroll will call when you move through the rows in tableview
当您在 tableview 中的行中移动时,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.
}
}
look in the link for more details about indexPathForVisibleRows https://developer.apple.com/documentation/uikit/uitableview/1614885-indexpathsforvisiblerows
查看链接以了解有关 indexPathForVisibleRows https://developer.apple.com/documentation/uikit/uitableview/1614885-indexpathsforvisiblerows的更多详细信息
回答by Cornel Damian
One of the simple and that offered me everything i need is this class:
一个简单的并且为我提供了我需要的一切的是这个类:
https://github.com/jakemarsh/JMStatefulTableViewController
https://github.com/jakemarsh/JMStatefulTableViewController
You just need to subclass JMStatefulTableViewController and the it has 3 methods that you need to overwrite:
你只需要继承 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
- 在 init 上调用的一个,以获取初始数据
- statefulTableViewControllerWillBeginInitialLoading
- 用户拉动刷新时的一种
- statefulTableViewControllerWillBeginLoadingFromPullToRefresh
- 无限滚动时调用(下一页)
- statefulTableViewControllerWillBeginLoadingNextPage
This can be used from Cocoapodstoo.
这也可以从Cocoapods 中使用。