以下是我的所有代码:
ViewController.m
#import "ViewController.h"
#import "LTInfiniteScrollView.h"
@interface ViewController ()<LTInfiniteScrollViewDelegate,LTInfiniteScrollViewDataSource>
@property (nonatomic,strong) LTInfiniteScrollView* scrollView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSMutableArray *timeArray=[[NSMutableArray alloc] init];
[timeArray addObject:@"5m"];
[timeArray addObject:@"10m"];
[timeArray addObject:@"15m"];
[timeArray addObject:@"30m"];
[timeArray addObject:@"45m"];
[timeArray addObject:@"60m"];
[timeArray addObject:@"90m"];
[timeArray addObject:@"120m"];
[timeArray addObject:@"240m"];
_timeArray=[timeArray mutableCopy];
NSLog(@"TIME_ARRAY:%@",_timeArray);
self.scrollView = [[LTInfiniteScrollView alloc]initWithFrame:CGRectMake(0, 300, CGRectGetWidth(self.view.bounds), 200)];
[self.scrollView setBackgroundColor:[UIColor redColor]];
[self.view addSubview:self.scrollView];
//self.scrollView.delegate = self;
self.scrollView.dataSource = self;
[self.scrollView reloadData];
}
- (IBAction)reload:(id)sender {
self.scrollView.delegate = nil;
[self.scrollView reloadData];
}
- (IBAction)reloadWithFancyEffect:(id)sender {
self.scrollView.delegate = self;
[self.scrollView reloadData];
}
-(int) totalViewCount
{
return _timeArray.count;
}
-(int) visibleViewCount
{
return 5;
}
-(UIView*) viewAtIndex:(int)index reusingView:(UIView *)view;
{
if(view){
((UILabel*)view).text = [_timeArray objectAtIndex:index];
return view;
}
UILabel *aView = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 64, 64)];
aView.backgroundColor = [UIColor blackColor];
aView.layer.cornerRadius = 64 / 2;
aView.layer.masksToBounds = YES;
aView.backgroundColor = [UIColor colorWithRed:0/255.0 green:175/255.0 blue:240/255.0 alpha:1];
aView.textColor = [UIColor whiteColor];
aView.textAlignment = NSTextAlignmentCenter;
NSLog(@"INDEX_CALLED:%d",index);
aView.text = [_timeArray objectAtIndex:index];
return aView;
}
-(void) updateView:(UIView*) view withDistanceToCenter:(CGFloat)distance scrollDirection:(ScrollDirection)direction
{
CGFloat percent = distance/CGRectGetWidth(self.view.bounds)*5;
if(view.tag == 1){
NSLog(@"%f",percent);
}
CATransform3D transform = CATransform3DIdentity;
// scale
CGFloat scale = 1.6 - 0.3*fabs(percent);
transform = CATransform3DScale(transform, scale, scale, scale);
// translate
CGFloat translate = 16 * percent;
transform = CATransform3DTranslate(transform,translate, 0, 0);
// rotate
if(fabs(percent)<1){
CGFloat angle = M_PI * percent;
transform.m34 = 1.0/-600;
transform = CATransform3DRotate(transform, angle , 0.0f, 1.0f, 0.0f);
}
view.layer.transform = transform;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
LTInfiniteScrollView.m
#import "LTInfiniteScrollView.h"
@interface LTInfiniteScrollView()<UIScrollViewDelegate>
@property CGSize viewSize;
@property(nonatomic,strong) UIScrollView *scrollView;
@property(nonatomic,strong) NSMutableArray* views;
@property(nonatomic) int visibleViewCount;
@property(nonatomic) int totalViewCount;
@property(nonatomic) CGFloat preContentOffsetX;
@property(nonatomic) CGFloat totalWidth;
@property int currentIndex;
@property BOOL dragging;
@property ScrollDirection scrollDirection;
@end
@implementation LTInfiniteScrollView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
-(void) setup
{
self.scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))];
self.scrollView.showsHorizontalScrollIndicator = NO;
self.scrollView.delegate = self;
[self addSubview: self.scrollView];
}
-(void) reloadData
{
for(UIView* view in self.views){
[view removeFromSuperview];
}
self.visibleViewCount = [self.dataSource visibleViewCount];
self.totalViewCount = [self.dataSource totalViewCount];
CGFloat viewWidth = CGRectGetWidth(self.bounds)/self.visibleViewCount;
CGFloat viewHeight = CGRectGetHeight(self.bounds);
self.viewSize = CGSizeMake(viewWidth, viewHeight);
self.totalWidth = viewWidth*self.totalViewCount;
self.scrollView.contentSize=CGSizeMake(self.totalWidth, CGRectGetHeight(self.bounds));
self.views = [NSMutableArray array];
int begin = -ceil(self.visibleViewCount/2.0f);
int end = ceil(self.visibleViewCount/2.0f);
self.currentIndex = 0;
self.scrollView.contentOffset = CGPointMake(self.totalWidth/2-CGRectGetWidth(self.bounds)/2, 0);
CGFloat currentCenter = [self currentCenter].x;
for(int i = begin; i<=end;i++){
UIView* view = [self.dataSource viewAtIndex:i reusingView:nil];
view.center = [self centerForViewAtIndex:i];
view.tag = i;
[self.views addObject:view];
[self.scrollView addSubview:view];
[self.delegate updateView:view withDistanceToCenter:(view.center.x - currentCenter) scrollDirection:self.scrollDirection];
}
}
-(CGPoint) centerForViewAtIndex:(int) index
{
CGFloat y = CGRectGetMidY(self.bounds);
CGFloat x = self.totalWidth/2 + index*self.viewSize.width;
// NSLog(@"view center:%f at index:%d",x,index);
return CGPointMake(x, y);
}
-(void) scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat offset = [self currentCenter].x - self.totalWidth/2 ;
self.currentIndex = ceil((offset- self.viewSize.width/2)/self.viewSize.width);
// NSLog(@"--------------------------------");
for (UIView* view in self.views) {
if([self viewCanBeQueuedForReuse:view]){
int indexNeeded;
int indexOfViewToReuse = (int)view.tag;
if(indexOfViewToReuse < self.currentIndex){
indexNeeded = indexOfViewToReuse + self.visibleViewCount + 2;
}else{
indexNeeded = indexOfViewToReuse - (self.visibleViewCount + 2);
}
//NSLog(@"index:%d indexNeeded:%d",indexOfViewToReuse,indexNeeded);
[view removeFromSuperview];
UIView* viewNeeded = [self.dataSource viewAtIndex:indexNeeded reusingView:view];
viewNeeded.center = [self centerForViewAtIndex:indexNeeded];
[self.scrollView addSubview:viewNeeded];
viewNeeded.tag = indexNeeded;
};
CGFloat currentCenter = [self currentCenter].x;
[self.delegate updateView:view withDistanceToCenter:(view.center.x - currentCenter) scrollDirection:self.scrollDirection];
}
if(self.dragging){
if(self.scrollView.contentOffset.x > self.preContentOffsetX){
self.scrollDirection = ScrollDirectionLeft;
}else{
self.scrollDirection = ScrollDirectionRight;
}
}
self.preContentOffsetX = self.scrollView.contentOffset.x;
}
-(CGPoint) currentCenter
{
CGFloat x = self.scrollView.contentOffset.x + CGRectGetWidth(self.bounds)/2.0f;
CGFloat y = self.scrollView.contentOffset.y;
return CGPointMake(x, y);
}
-(BOOL) viewCanBeQueuedForReuse:(UIView*) view
{
CGFloat distanceToCenter = [self currentCenter].x - view.center.x;
CGFloat threshold = (ceil(self.visibleViewCount/2.0f))*self.viewSize.width + self.viewSize.width/2.0f;
if(self.scrollDirection == ScrollDirectionLeft){
if(distanceToCenter <0){
return NO;
}
}else{
if(distanceToCenter >0){
return NO;
}
}
if(fabs(distanceToCenter)> threshold){
return YES;
}
return NO;
}
-(void) scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
self.dragging = YES;
}
-(void) scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
self.dragging = NO;
[self.scrollView setContentOffset:[self contentOffsetForIndex:self.currentIndex] animated:YES];
}
-(void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self.scrollView setContentOffset:[self contentOffsetForIndex:self.currentIndex] animated:YES];
}
-(CGPoint) contentOffsetForIndex:(int) index
{
CGFloat x = self.totalWidth/2 + index*self.viewSize.width - CGRectGetWidth(self.bounds)/2;
return CGPointMake(x, 0);
}
@end
这里有误解我的错误:
2016-01-24 23:08:13.335 LTInfiniteScrollView[21385:2910198] TIME_ARRAY:(
5m,
10m,
15m,
30m,
45m,
60m,
90m,
120m,
240m
)
2016-01-24 23:08:13.356 LTInfiniteScrollView[21385:2910198] INDEX_CALLED:-3
2016-01-24 23:08:13.359 LTInfiniteScrollView[21385:2910198] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 18446744073709551613 beyond bounds [0 .. 8]'
*** First throw call stack:
(
0 CoreFoundation 0x00000001018e5f45 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010135ddeb objc_exception_throw + 48
2 CoreFoundation 0x00000001017c99e4 -[__NSArrayM objectAtIndex:] + 212
3 LTInfiniteScrollView 0x0000000100e504e4 -[ViewController viewAtIndex:reusingView:] + 852
4 LTInfiniteScrollView 0x0000000100e518e4 -[LTInfiniteScrollView reloadData] + 2340
5 LTInfiniteScrollView 0x0000000100e4ff09 -[ViewController viewDidAppear:] + 1193
6 UIKit 0x0000000102288f3d -[UIViewController _setViewAppearState:isAnimating:] + 830
7 UIKit 0x000000010228bd1a __64-[UIViewController viewDidMoveToWindow:shouldAppearOrDisappear:]_block_invoke + 42
8 UIKit 0x0000000102289fc6 -[UIViewController _executeAfterAppearanceBlock] + 86
9 UIKit 0x00000001020fd01a _runAfterCACommitDeferredBlocks + 633
10 UIKit 0x00000001021100b6 _cleanUpAfterCAFlushAndRunDeferredBlocks + 95
11 CoreFoundation 0x0000000101811ffc __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
12 CoreFoundation 0x0000000101807c85 __CFRunLoopDoBlocks + 341
13 CoreFoundation 0x00000001018073e2 __CFRunLoopRun + 850
14 CoreFoundation 0x0000000101806e08 CFRunLoopRunSpecific + 488
15 GraphicsServices 0x0000000105c9fad2 GSEventRunModal + 161
16 UIKit 0x00000001020f1031 UIApplicationMain + 171
17 LTInfiniteScrollView 0x0000000100e4f9ef main + 111
18 libdyld.dylib 0x000000010447292d start + 1
19 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
答案 0 :(得分:-1)
我认为你的问题存在于这一行:
UIView* view = [self.dataSource viewAtIndex:i reusingView:nil];
查看错误,似乎该行的最后一行不是iOS SDK或本机Objective-C库的一部分。它看起来像你正在寻找-3
的索引,它不被识别为无符号整数,因此它被视为一个真正的,非常大的价值,并且在你的外面数据源数组边界。我建议您每次使用objectAtIndex:
时添加一项检查,以确保您要查找的索引至少在数组范围内。