Created
February 7, 2014 23:54
-
-
Save marcuswestin/8874402 to your computer and use it in GitHub Desktop.
Infinite UIScrollView with dynamically added/removed views
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// RootViewController.m | |
// ScrollTest | |
// | |
// Created by Marcus Westin on 2/7/14. | |
// Copyright (c) 2014 Marcus Westin. All rights reserved. | |
// | |
#import "RootViewController.h" | |
static CGFloat START_Y = 99999.0f; | |
static CGFloat MAX_Y = 9999999.0f; | |
@interface RootViewController () | |
@property UIScrollView* scrollView; | |
@property CGFloat topY; | |
@property CGFloat bottomY; | |
@property CGFloat lastY; | |
@property BOOL purged; | |
@end | |
@implementation RootViewController | |
- (id)init { | |
return [self initWithNibName:nil bundle:nil]; | |
} | |
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil | |
{ | |
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; | |
if (self) { | |
[self render]; | |
} | |
return self; | |
} | |
- (void)render { | |
_scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds]; | |
_scrollView.contentOffset = CGPointMake(0, START_Y); | |
_scrollView.contentSize = CGSizeMake(self.view.frame.size.width, MAX_Y); | |
[self.view addSubview:_scrollView]; | |
_topY = START_Y; | |
_bottomY = START_Y; | |
[self addNextViewDown]; | |
[self extendBottom]; | |
[self extendTop]; | |
_scrollView.delegate = self; | |
} | |
- (void)scrollViewDidScroll:(UIScrollView *)scrollView { | |
if (_lastY < scrollView.contentOffset.y) { | |
[self extendBottom]; | |
} else { | |
[self extendTop]; | |
} | |
_lastY = scrollView.contentOffset.y; | |
} | |
- (void)extendBottom { | |
CGFloat targetY = _scrollView.contentOffset.y + _scrollView.frame.size.height; | |
while (_bottomY < targetY) { | |
[self addNextViewDown]; | |
} | |
[self cleanTop]; | |
} | |
- (void)extendTop { | |
CGFloat targetY = _scrollView.contentOffset.y; | |
while (_topY > targetY) { | |
[self addNextViewUp]; | |
} | |
[self cleanBottom]; | |
} | |
- (void)cleanTop { | |
NSLog(@"CLEAN TOP"); | |
UIView* view; | |
CGFloat targetY = _scrollView.contentOffset.y; | |
while ((view = self.topView) && view.frame.origin.y + view.frame.size.height < targetY) { | |
[view removeFromSuperview]; | |
_topY += view.frame.size.height; | |
} | |
} | |
- (void)cleanBottom { | |
NSLog(@"CLEAN BOTTOM"); | |
UIView* view; | |
CGFloat targetY = _scrollView.contentOffset.y + _scrollView.frame.size.height; | |
while ((view = self.bottomView) && view.frame.origin.y > targetY) { | |
[view removeFromSuperview]; | |
_bottomY -= view.frame.size.height; | |
} | |
} | |
- (void)addNextViewUp { | |
CGFloat height = 40 + arc4random() % 40; | |
_topY -= height; | |
UIView* view = [self makeView:_topY height:height]; | |
[_scrollView insertSubview:view atIndex:0]; | |
} | |
- (void)addNextViewDown { | |
CGFloat height = 40 + arc4random() % 40; | |
UIView* view = [self makeView:_bottomY height:height]; | |
_bottomY += view.frame.size.height; | |
[_scrollView addSubview:view]; | |
} | |
- (UIView*)makeView:(CGFloat)y height:(CGFloat)height { | |
CGFloat hue = ( arc4random() % 256 / 256.0 ); // 0.0 to 1.0 | |
CGFloat saturation = ( arc4random() % 128 / 256.0 ) + 0.5; // 0.5 to 1.0, away from white | |
CGFloat brightness = ( arc4random() % 128 / 256.0 ) + 0.5; // 0.5 to 1.0, away from black | |
UIView* view = [[UIView alloc] initWithFrame:CGRectMake(0, y, _scrollView.frame.size.width, height)]; | |
view.backgroundColor = [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1]; | |
return view; | |
} | |
- (NSArray*)views { | |
if (!_purged) { | |
for (UIView* view in _scrollView.subviews) { | |
if ([view isKindOfClass:[UIImageView class]]) { | |
[view removeFromSuperview]; | |
} | |
} | |
_purged = YES; | |
} | |
return _scrollView.subviews ? _scrollView.subviews : @[]; | |
} | |
- (UIView*)topView { | |
return self.views.firstObject; | |
} | |
- (UIView*)bottomView { | |
return self.views.lastObject; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
wondering if there is a Swift version?