What is the best way to implement a cyclic UITableView where instead of showing white space when the user scrolls up to the table\'s bounds, it simply wraps round cyclically
UITableView is same as UIScrollView in scrollViewDidScroll method.
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.)
Thus, 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
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.
You cant make cyclic table . suppose you return a large number of rows from numberOfRowsInSection method(finite number) then also table having a upper end and of cource you cant return infinite for number of rows thats why it having down end. so it cant look like round table.
you can do it for a finite number also you can repeat rows but this is not possible to make cyclic tableView.
I have made a cyclic tableView based on UIScrollView. And based on this tableView, I re-implement UIPickerView. You might be interested in this class DLTableView
.
https://github.com/danleechina/DLPickerView
I have seen this behavior a couple of times but not in a UITableView it was a UIPickerView. The code is quite simple and probably convertible to a UITableView....
The code for ciclic UIPickerView
RollerViewController.h
@interface RollerViewController : UIViewController <UIPickerViewDelegate>{
UIPickerView *picker;
}
@end
RollerViewController.m
#import "RollerViewController.h"
@implementation RollerViewController
#define MAX_ROLL 100
#define ROWS_COUNT 10
#pragma mark -
#pragma mark Helpers
- (void) infinitePickerViewDidSelectRow:(NSInteger)row inComponent:(NSInteger)component{
NSUInteger base10 = (MAX_ROLL/2) - (MAX_ROLL/2)%ROWS_COUNT;
[picker selectRow:row%ROWS_COUNT+base10 inComponent:component animated:FALSE];
}
#pragma mark -
#pragma mark UIPickerView dataSource delegate methods
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {
return 3;
}
- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {
return MAX_ROLL;
}
- (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component{
return (CGFloat)40;
}
- (void)pickerView:(UIPickerView *)thePickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
[self infinitePickerViewDidSelectRow:row inComponent:component];
}
- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component{
return (CGFloat) 50;
}
- (UIView *)pickerView:(UIPickerView *)thePickerView viewForRow:(NSInteger)row
forComponent:(NSInteger)component reusingView:(UIView *)rview {
UILabel *retval = (UILabel *)rview;
if (!retval) {
retval= [[[UILabel alloc] initWithFrame:CGRectMake(5,5,40,30) ] autorelease];
}
retval.text = [NSString stringWithFormat:@"%d", row%ROWS_COUNT];
retval.font = [UIFont systemFontOfSize:25];
retval.textAlignment = UITextAlignmentCenter;
retval.backgroundColor = [UIColor clearColor];
return retval;
}
#pragma mark overides
- (void)viewDidLoad {
[super viewDidLoad];
picker = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 0, 320, 280)];
picker.delegate = self;
[self.view addSubview:picker];
}
- (void) viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self infinitePickerViewDidSelectRow:arc4random()%MAX_ROLL inComponent:0];
[self infinitePickerViewDidSelectRow:arc4random()%MAX_ROLL inComponent:1];
[self infinitePickerViewDidSelectRow:arc4random()%MAX_ROLL inComponent:2];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)dealloc {
[picker release];
[super dealloc];
}
@end
Yes, it is possible to make a cyclic UITableView. You simply pass a really large number as the number of rows and then for each row the table view requests, you pass it the row_number % number_of_rows, so you are always iterating within your data even if the row number is ridiculously large.
You can see an example here: http://dev.doukasd.com/2011/04/infinite-scrolling-dial-control-for-ios/
Basically it's like UIPickerView implemented with a UITableView.