Skip to content
Browse files

Cleaned house, added blocks instead of targets.

  • Loading branch information...
1 parent cc0d760 commit fde84cd9e515903747eae3e67f29aff7ffaf72dc @alexzielenski alexzielenski committed Apr 5, 2012
View
24 ScrollToRefresh.xcodeproj/project.pbxproj
@@ -17,7 +17,6 @@
FA121D851472FB9300FED3BA /* EQSTRClipView.m in Sources */ = {isa = PBXBuildFile; fileRef = FA121D841472FB9300FED3BA /* EQSTRClipView.m */; };
FA121D87147303B400FED3BA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA121D86147303B400FED3BA /* QuartzCore.framework */; };
FA121D89147303EC00FED3BA /* arrow.png in Resources */ = {isa = PBXBuildFile; fileRef = FA121D88147303EC00FED3BA /* arrow.png */; };
- FA121D951473074D00FED3BA /* YRKSpinningProgressIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = FA121D941473074D00FED3BA /* YRKSpinningProgressIndicator.m */; };
FA121D97147318BD00FED3BA /* README.markdown in Resources */ = {isa = PBXBuildFile; fileRef = FA121D96147318BD00FED3BA /* README.markdown */; };
/* End PBXBuildFile section */
@@ -41,8 +40,6 @@
FA121D841472FB9300FED3BA /* EQSTRClipView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = EQSTRClipView.m; path = src/EQSTRClipView.m; sourceTree = "<group>"; };
FA121D86147303B400FED3BA /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
FA121D88147303EC00FED3BA /* arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = arrow.png; sourceTree = "<group>"; };
- FA121D931473074D00FED3BA /* YRKSpinningProgressIndicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YRKSpinningProgressIndicator.h; sourceTree = "<group>"; };
- FA121D941473074D00FED3BA /* YRKSpinningProgressIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YRKSpinningProgressIndicator.m; sourceTree = "<group>"; };
FA121D96147318BD00FED3BA /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.markdown; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
@@ -103,7 +100,6 @@
FA121D721472FB2B00FED3BA /* EQSTRAppDelegate.m */,
FA121D7F1472FB5C00FED3BA /* ScrollToRefresh */,
FA121D741472FB2B00FED3BA /* MainMenu.xib */,
- FA121D8A147306C100FED3BA /* 3rd Party */,
FA121D661472FB2B00FED3BA /* Supporting Files */,
);
path = ScrollToRefresh;
@@ -134,24 +130,6 @@
name = ScrollToRefresh;
sourceTree = "<group>";
};
- FA121D8A147306C100FED3BA /* 3rd Party */ = {
- isa = PBXGroup;
- children = (
- FA121D921473074D00FED3BA /* YRKSpinningProgressIndicator */,
- );
- name = "3rd Party";
- path = "src/3rd Party";
- sourceTree = "<group>";
- };
- FA121D921473074D00FED3BA /* YRKSpinningProgressIndicator */ = {
- isa = PBXGroup;
- children = (
- FA121D931473074D00FED3BA /* YRKSpinningProgressIndicator.h */,
- FA121D941473074D00FED3BA /* YRKSpinningProgressIndicator.m */,
- );
- path = YRKSpinningProgressIndicator;
- sourceTree = "<group>";
- };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -222,7 +200,6 @@
FA121D731472FB2B00FED3BA /* EQSTRAppDelegate.m in Sources */,
FA121D7E1472FB5800FED3BA /* EQSTRScrollView.m in Sources */,
FA121D851472FB9300FED3BA /* EQSTRClipView.m in Sources */,
- FA121D951473074D00FED3BA /* YRKSpinningProgressIndicator.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -342,6 +319,7 @@
FA121D7B1472FB2B00FED3BA /* Release */,
);
defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
View
10 ScrollToRefresh/src/EQSTRClipView.m
@@ -30,11 +30,11 @@ @implementation EQSTRClipView
- (NSPoint)constrainScrollPoint:(NSPoint)proposedNewOrigin { // this method determines the "elastic" of the scroll view or how high it can scroll without resistence.
NSPoint constrained = [super constrainScrollPoint:proposedNewOrigin];
CGFloat scrollValue = proposedNewOrigin.y; // this is the y value where the top of the document view is
- BOOL over = scrollValue<=self.minimumScroll;
+ BOOL over = scrollValue <= self.minimumScroll;
- if (self.isRefreshing&&scrollValue<=0) { // if we are refreshing
+ if (self.isRefreshing && scrollValue <= 0) { // if we are refreshing
if (over) // and if we are scrolled above the refresh view
- proposedNewOrigin.y = 0-self.headerView.frame.size.height; // constrain us to the refresh view
+ proposedNewOrigin.y = 0 - self.headerView.frame.size.height; // constrain us to the refresh view
return NSMakePoint(constrained.x, proposedNewOrigin.y);
}
return constrained;
@@ -45,8 +45,8 @@ - (BOOL)isFlipped {
- (NSRect)documentRect { //this is to make scrolling feel more normal so that the spinner is within the scrolled area
NSRect sup = [super documentRect];
if (self.isRefreshing) {
- sup.size.height+=self.headerView.frame.size.height;
- sup.origin.y-=self.headerView.frame.size.height;
+ sup.size.height += self.headerView.frame.size.height;
+ sup.origin.y -= self.headerView.frame.size.height;
}
return sup;
}
View
23 ScrollToRefresh/src/EQSTRScrollView.h
@@ -24,31 +24,16 @@
#import <AppKit/AppKit.h>
-@interface EQSTRScrollView : NSScrollView {
- BOOL isRefreshing;
- BOOL overHeaderView;
-
- NSView *refreshHeader;
- NSView *refreshArrow;
- NSProgressIndicator *refreshSpinner;
-
- id target;
- SEL selector;
-}
-@property (assign) id target;
-@property (assign) SEL selector;
-
+@interface EQSTRScrollView : NSScrollView
@property (readonly) BOOL isRefreshing;
@property (readonly) NSView *refreshHeader;
@property (readonly) NSProgressIndicator *refreshSpinner;
@property (readonly) NSView *refreshArrow;
+
+@property (nonatomic, copy) void (^refreshBlock)(EQSTRScrollView *scrollView);
+
- (void)startLoading;
- (void)stopLoading;
-- (BOOL)overRefreshView;
-- (void)createHeaderView;
-- (void)viewBoundsChanged:(NSNotification*)note;
-
-- (CGFloat)minimumScroll;
@end
View
215 ScrollToRefresh/src/EQSTRScrollView.m
@@ -30,35 +30,64 @@
// code modeled from https://github.com/leah/PullToRefresh/blob/master/Classes/PullRefreshTableViewController.m
+@interface EQSTRScrollView ()
+@property (nonatomic, assign) BOOL _overRefreshView;
+
+- (BOOL)overRefreshView;
+- (void)createHeaderView;
+- (void)viewBoundsChanged:(NSNotification*)note;
+
+- (CGFloat)minimumScroll;
+
+@end
+
@implementation EQSTRScrollView
-@synthesize isRefreshing, refreshHeader, target, selector, refreshSpinner, refreshArrow;
+
+#pragma mark - Private Properties
+
+@synthesize _overRefreshView;
+
+#pragma mark - Public Properties
+
+@synthesize isRefreshing = _isRefreshing;
+@synthesize refreshHeader = _refreshHeader;
+@synthesize refreshSpinner = _refreshSpinner;
+@synthesize refreshArrow = _refreshArrow;
+@synthesize refreshBlock = _refreshBlock;
+
+#pragma mark - Create Header View
+
- (void)viewDidMoveToWindow {
[self createHeaderView];
}
-- (NSClipView*)contentView {
+
+- (NSClipView *)contentView {
NSClipView *superClipView = [super contentView];
if (![superClipView isKindOfClass:[EQSTRClipView class]]) {
+
// create new clipview
- NSView *documentView = superClipView.documentView;
+ NSView *documentView = superClipView.documentView;
- EQSTRClipView *clipView = [[EQSTRClipView alloc] initWithFrame:superClipView.frame];
- clipView.documentView=documentView;
- clipView.copiesOnScroll=NO;
- clipView.drawsBackground=NO;
- [self setContentView:clipView];
+ EQSTRClipView *clipView = [[EQSTRClipView alloc] initWithFrame:superClipView.frame];
+ clipView.documentView = documentView;
+ clipView.copiesOnScroll = NO;
+ clipView.drawsBackground = NO;
+ [self setContentView:clipView];
[clipView release];
- superClipView = [super contentView];
+ superClipView = [super contentView];
+
}
return superClipView;
}
+
- (void)createHeaderView {
// delete old stuff if any
- if (refreshHeader) {
- [refreshHeader removeFromSuperview];
- [refreshHeader release];
- refreshHeader = nil;
+ if (self.refreshHeader) {
+ [_refreshHeader removeFromSuperview];
+ [_refreshHeader release];
+ _refreshHeader = nil;
}
[self setVerticalScrollElasticity:NSScrollElasticityAllowed];
@@ -75,121 +104,143 @@ - (void)createHeaderView {
// add header view to clipview
NSRect contentRect = [self.contentView.documentView frame];
- refreshHeader = [[NSView alloc] initWithFrame:NSMakeRect(0,
- 0-REFRESH_HEADER_HEIGHT, //contentRect.origin.y+contentRect.size.height,
- contentRect.size.width,
- REFRESH_HEADER_HEIGHT)];
+ _refreshHeader = [[NSView alloc] initWithFrame:NSMakeRect(0,
+ 0 - REFRESH_HEADER_HEIGHT,
+ contentRect.size.width,
+ REFRESH_HEADER_HEIGHT)];
- // arrow
+ // Create Arrow
NSImage *arrowImage = [NSImage imageNamed:@"arrow"];
- refreshArrow = [[NSView alloc] initWithFrame:NSMakeRect(floor(NSMidX(refreshHeader.bounds)-arrowImage.size.width/2),
- floor(NSMidY(refreshHeader.bounds)-arrowImage.size.height/2),
- arrowImage.size.width,
- arrowImage.size.height)];
- refreshArrow.wantsLayer=YES;
- refreshArrow.layer=[CALayer layer];
- refreshArrow.layer.contents=(id)[arrowImage CGImageForProposedRect:NULL
- context:nil
- hints:nil];
-
- refreshSpinner = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(floor(NSMidX(refreshHeader.bounds)-30),
- floor(NSMidY(refreshHeader.bounds)-20),
- 60.0f,
- 40.0f)];
- refreshSpinner.style=NSProgressIndicatorSpinningStyle;
- refreshSpinner.displayedWhenStopped=NO;
- refreshSpinner.usesThreadedAnimation=YES;
- refreshSpinner.indeterminate=YES;
- refreshSpinner.bezeled=NO;
- [refreshSpinner sizeToFit];
-
- [refreshSpinner setFrame:NSMakeRect(floor(NSMidX(refreshHeader.bounds)-refreshSpinner.frame.size.width/2),
- floor(NSMidY(refreshHeader.bounds)-refreshSpinner.frame.size.height/2),
- refreshSpinner.frame.size.width,
- refreshSpinner.frame.size.height)];
+ _refreshArrow = [[NSView alloc] initWithFrame:NSMakeRect(floor(NSMidX(self.refreshHeader.bounds) - arrowImage.size.width / 2),
+ floor(NSMidY(self.refreshHeader.bounds) - arrowImage.size.height / 2),
+ arrowImage.size.width,
+ arrowImage.size.height)];
+ self.refreshArrow.wantsLayer = YES;
+ self.refreshArrow.layer = [CALayer layer];
+ self.refreshArrow.layer.contents = (id)[arrowImage CGImageForProposedRect:NULL
+ context:nil
+ hints:nil];
+
+ // Create spinner
+ _refreshSpinner = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(floor(NSMidX(self.refreshHeader.bounds) - 30),
+ floor(NSMidY(self.refreshHeader.bounds) - 20),
+ 60.0f,
+ 40.0f)];
+ self.refreshSpinner.style = NSProgressIndicatorSpinningStyle;
+ self.refreshSpinner.displayedWhenStopped = NO;
+ self.refreshSpinner.usesThreadedAnimation = YES;
+ self.refreshSpinner.indeterminate = YES;
+ self.refreshSpinner.bezeled = NO;
+ [self.refreshSpinner sizeToFit];
+
+ // Center the spinner in the header
+ [self.refreshSpinner setFrame:NSMakeRect(floor(NSMidX(self.refreshHeader.bounds) - self.refreshSpinner.frame.size.width / 2),
+ floor(NSMidY(self.refreshHeader.bounds) - self.refreshSpinner.frame.size.height / 2),
+ self.refreshSpinner.frame.size.width,
+ self.refreshSpinner.frame.size.height)];
// set autoresizing masks
- refreshSpinner.autoresizingMask = NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin | NSViewMaxYMargin; // center
- refreshArrow.autoresizingMask = NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin | NSViewMaxYMargin; // center
- refreshHeader.autoresizingMask = NSViewWidthSizable | NSViewMinXMargin | NSViewMaxXMargin; // stretch/center
+ self.refreshSpinner.autoresizingMask = NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin | NSViewMaxYMargin; // center
+ self.refreshArrow.autoresizingMask = NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin | NSViewMaxYMargin; // center
+ self.refreshHeader.autoresizingMask = NSViewWidthSizable | NSViewMinXMargin | NSViewMaxXMargin; // stretch/center
- [refreshHeader addSubview:refreshArrow];
- [refreshHeader addSubview:refreshSpinner];
+ // Put everything in place
+ [self.refreshHeader addSubview:self.refreshArrow];
+ [self.refreshHeader addSubview:self.refreshSpinner];
- [self.contentView addSubview:refreshHeader];
+ [self.contentView addSubview:self.refreshHeader];
- [refreshArrow release];
- [refreshSpinner release];
+ [self.refreshArrow release];
+ [self.refreshSpinner release];
+ // Scroll to top
[self.contentView scrollToPoint:NSMakePoint(contentRect.origin.x, 0)];
[self reflectScrolledClipView:self.contentView];
}
+
+#pragma mark - Detecting Scroll
+
- (void)scrollWheel:(NSEvent *)event {
- if (event.phase==NSEventPhaseEnded) {
- if (overHeaderView&&!isRefreshing) {
+ if (event.phase == NSEventPhaseEnded) {
+ if (self._overRefreshView && ! self.isRefreshing) {
[self startLoading];
}
}
+
[super scrollWheel:event];
}
-- (void)viewBoundsChanged:(NSNotification*)note {
- if (isRefreshing)
+
+- (void)viewBoundsChanged:(NSNotification *)note {
+ if (self.isRefreshing)
return;
+
BOOL start = [self overRefreshView];
if (start) {
+
// point arrow up
- [refreshArrow layer].transform = CATransform3DMakeRotation(M_PI, 0, 0, 1);
- overHeaderView = YES;
+ [self.refreshArrow layer].transform = CATransform3DMakeRotation(M_PI, 0, 0, 1);
+ self._overRefreshView = YES;
+
} else {
+
// point arrow down
- [refreshArrow layer].transform = CATransform3DMakeRotation(M_PI * 2, 0, 0, 1);
- overHeaderView = NO;
+ [self.refreshArrow layer].transform = CATransform3DMakeRotation(M_PI * 2, 0, 0, 1);
+ self._overRefreshView = NO;
+
}
}
+
- (BOOL)overRefreshView {
- NSClipView *clipView = self.contentView;
- NSRect bounds = clipView.bounds;
+ NSClipView *clipView = self.contentView;
+ NSRect bounds = clipView.bounds;
- CGFloat scrollValue = bounds.origin.y;
+ CGFloat scrollValue = bounds.origin.y;
CGFloat minimumScroll = self.minimumScroll;
- return (scrollValue<=minimumScroll);
+ return (scrollValue <= minimumScroll);
+}
+
+- (CGFloat)minimumScroll {
+ return 0 - self.refreshHeader.frame.size.height;
}
+
+#pragma mark - Refresh
+
- (void)startLoading {
[self willChangeValueForKey:@"isRefreshing"];
- isRefreshing = YES;
+ _isRefreshing = YES;
[self didChangeValueForKey:@"isRefreshing"];
- refreshArrow.hidden = YES;
- [refreshSpinner startAnimation:self];
+ self.refreshArrow.hidden = YES;
+ [self.refreshSpinner startAnimation:self];
- if (self.target&&[self.target respondsToSelector:self.selector])
- [self.target performSelectorOnMainThread:self.selector
- withObject:self
- waitUntilDone:YES];
+ if (self.refreshBlock) {
+ self.refreshBlock(self);
+ }
}
+
- (void)stopLoading {
- refreshArrow.hidden = NO;
- [refreshArrow layer].transform = CATransform3DMakeRotation(M_PI * 2, 0, 0, 1);
- [refreshSpinner stopAnimation:self];
+ self.refreshArrow.hidden = NO;
+
+ [self.refreshArrow layer].transform = CATransform3DMakeRotation(M_PI * 2, 0, 0, 1);
+ [self.refreshSpinner stopAnimation:self];
// now fake an event of scrolling for a natural look
[self willChangeValueForKey:@"isRefreshing"];
- isRefreshing = NO;
+ _isRefreshing = NO;
[self didChangeValueForKey:@"isRefreshing"];
- CGEventRef cgEvent = CGEventCreateScrollWheelEvent(NULL,
- kCGScrollEventUnitLine,
- 2,
- 1,
- 0);
+ CGEventRef cgEvent = CGEventCreateScrollWheelEvent(NULL,
+ kCGScrollEventUnitLine,
+ 2,
+ 1,
+ 0);
+
NSEvent *scrollEvent = [NSEvent eventWithCGEvent:cgEvent];
[self scrollWheel:scrollEvent];
CFRelease(cgEvent);
}
-- (CGFloat)minimumScroll {
- return 0-refreshHeader.frame.size.height;
-}
+
@end

0 comments on commit fde84cd

Please sign in to comment.
Something went wrong with that request. Please try again.