Skip to content

Instantly share code, notes, and snippets.

@Shilo
Last active December 22, 2015 12:39
Show Gist options
  • Save Shilo/6474058 to your computer and use it in GitHub Desktop.
Save Shilo/6474058 to your computer and use it in GitHub Desktop.
A UIScrollView subclass that will allow a specified GLKViewController to continue rendering, while scrolling.
//
// XDGLScrollView.h
// A scroll view that will allow a specified GLKViewController to continue rendering, while scrolling.
//
// Created by Shilo White on 9/7/13.
// Copyright (c) 2013 XIDA Design & Technik. All rights reserved.
//
#import <UIKit/UIKit.h>
@class GLKViewController;
@interface XDGLScrollView : UIScrollView
@property (nonatomic, weak) GLKViewController *glkViewController;
@property (nonatomic, readonly) BOOL rendering;
@property (nonatomic, readonly) BOOL active;
@end
//
// XDGLScrollView.m
// A scroll view that will allow a specified GLKViewController to continue rendering, while scrolling.
//
// Created by Shilo White on 9/7/13.
// Copyright (c) 2013 XIDA Design & Technik. All rights reserved.
//
#import "XDGLScrollView.h"
#import <GLKit/GLKit.h>
#import <QuartzCore/QuartzCore.h>
#import <objc/runtime.h>
static NSMutableArray *sActiveScrollViews;
@interface GLKViewController (XDGLScrollView)
@property (nonatomic, weak) XDGLScrollView *_activeScrollView;
@end
@implementation GLKViewController (XDGLScrollView)
- (void)set_activeScrollView:(XDGLScrollView *)_activeScrollView
{
objc_setAssociatedObject(self, @selector(_activeScrollView), _activeScrollView, OBJC_ASSOCIATION_ASSIGN);
}
- (XDGLScrollView *)_activeScrollView
{
return objc_getAssociatedObject(self, @selector(_activeScrollView));
}
@end
@interface XDGLScrollView () <UIScrollViewDelegate>
@property (nonatomic, assign) BOOL rendering;
@property (nonatomic, assign) BOOL active;
+ (NSMutableArray *)activeScrollViews;
+ (void)addActiveScrollView:(XDGLScrollView *)scrollView;
+ (void)removeActiveScrollView:(XDGLScrollView *)scrollView;
+ (XDGLScrollView *)activeScrollViewWithGLKViewController:(GLKViewController *)glkViewController;
@end
@implementation XDGLScrollView {
id<UIScrollViewDelegate> __unsafe_unretained _delegate;
GLKViewController __weak *_glkViewController;
CADisplayLink *_displayLink;
BOOL _active;
}
@synthesize delegate = _delegate;
@synthesize glkViewController = _glkViewController;
@synthesize active = _active;
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame]))
{
[self setup];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super initWithCoder:aDecoder]))
{
[self setup];
}
return self;
}
- (id)init
{
if ((self = [super init]))
{
[self setup];
}
return self;
}
- (void)setup
{
super.delegate = self;
_glkViewController = nil;
_displayLink = nil;
_active = NO;
}
- (void)setRendering:(BOOL)rendering
{
if (rendering != self.rendering)
{
[_displayLink invalidate];
if (rendering)
{
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(render)];
_displayLink.frameInterval = (60/_glkViewController.preferredFramesPerSecond);
[_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
else
_displayLink = nil;
}
}
- (BOOL)rendering
{
return (_displayLink != nil);
}
- (void)setActive:(BOOL)active
{
if (active != _active)
{
_active = active;
if (_active)
[XDGLScrollView addActiveScrollView:self];
else
[XDGLScrollView removeActiveScrollView:self];
}
}
- (void)render
{
[_glkViewController performSelector:@selector(_updateAndDraw)];
}
+ (NSMutableArray *)activeScrollViews
{
if (!sActiveScrollViews)
sActiveScrollViews = [[NSMutableArray alloc] init];
return sActiveScrollViews;
}
+ (void)addActiveScrollView:(XDGLScrollView *)scrollView
{
GLKViewController *glkViewController = scrollView.glkViewController;
if (glkViewController && glkViewController._activeScrollView == nil)
{
glkViewController._activeScrollView = scrollView;
scrollView.rendering = YES;
}
[[self activeScrollViews] addObject:scrollView];
}
+ (void)removeActiveScrollView:(XDGLScrollView *)scrollView
{
[[self activeScrollViews] removeObject:scrollView];
GLKViewController *glkViewController = scrollView.glkViewController;
if (glkViewController._activeScrollView == scrollView)
{
scrollView.rendering = NO;
XDGLScrollView *activeScrollView = [self activeScrollViewWithGLKViewController:glkViewController];
glkViewController._activeScrollView = activeScrollView;
activeScrollView.rendering = YES;
}
}
+ (XDGLScrollView *)activeScrollViewWithGLKViewController:(GLKViewController *)glkViewController
{
for (XDGLScrollView *activeScrollView in sActiveScrollViews)
if (activeScrollView.glkViewController == glkViewController)
return activeScrollView;
return nil;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if ([_delegate respondsToSelector:@selector(scrollViewDidScroll:)])
[_delegate scrollViewDidScroll:scrollView];
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
self.active = YES;
if ([_delegate respondsToSelector:@selector(scrollViewWillBeginDragging:)])
[_delegate scrollViewWillBeginDragging:scrollView];
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
if ([_delegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)])
[_delegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if (!decelerate) self.active = NO;
if ([_delegate respondsToSelector:@selector(scrollViewDidEndDragging:willDecelerate:)])
[_delegate scrollViewDidEndDragging:scrollView willDecelerate:decelerate];
}
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
{
if ([_delegate respondsToSelector:@selector(scrollViewShouldScrollToTop:)])
return [_delegate scrollViewShouldScrollToTop:scrollView];
else
return YES;
}
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView
{
if ([_delegate respondsToSelector:@selector(scrollViewDidScrollToTop:)])
[_delegate scrollViewDidScrollToTop:scrollView];
}
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
if ([_delegate respondsToSelector:@selector(scrollViewWillBeginDecelerating:)])
[_delegate scrollViewWillBeginDecelerating:scrollView];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
self.active = NO;
if ([_delegate respondsToSelector:@selector(scrollViewDidEndDecelerating:)])
[_delegate scrollViewDidEndDecelerating:scrollView];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
if ([_delegate respondsToSelector:@selector(viewForZoomingInScrollView:)])
return [_delegate viewForZoomingInScrollView:scrollView];
else
return nil;
}
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view
{
if ([_delegate respondsToSelector:@selector(scrollViewWillBeginZooming:withView:)])
[_delegate scrollViewWillBeginZooming:scrollView withView:view];
}
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
if ([_delegate respondsToSelector:@selector(scrollViewDidEndZooming:withView:atScale:)])
[_delegate scrollViewDidEndZooming:scrollView withView:view atScale:scale];
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
if ([_delegate respondsToSelector:@selector(scrollViewDidZoom:)])
[_delegate scrollViewDidZoom:scrollView];
}
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
{
if ([_delegate respondsToSelector:@selector(scrollViewDidEndScrollingAnimation:)])
[_delegate scrollViewDidEndScrollingAnimation:scrollView];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment