Skip to content

Instantly share code, notes, and snippets.

@marcuswestin
Created February 7, 2014 23:54
Show Gist options
  • Save marcuswestin/8874402 to your computer and use it in GitHub Desktop.
Save marcuswestin/8874402 to your computer and use it in GitHub Desktop.
Infinite UIScrollView with dynamically added/removed views
//
// 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
@callagga
Copy link

wondering if there is a Swift version?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment