Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Adding pull to refresh in posts view.

  • Loading branch information...
commit b536891b74f55bf30bf69be0326e4c228aeaf4e8 1 parent 850382d
@jsakuda jsakuda authored
View
15 HI Capacity.xcodeproj/project.pbxproj
@@ -17,6 +17,7 @@
09359FEB1588974400B4EA3E /* line@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 09359FEA1588974400B4EA3E /* line@2x.png */; };
09359FED1588977500B4EA3E /* line.png in Resources */ = {isa = PBXBuildFile; fileRef = 09359FEC1588977500B4EA3E /* line.png */; };
09517A83158AF4320016EDF8 /* Post.m in Sources */ = {isa = PBXBuildFile; fileRef = 09517A82158AF4320016EDF8 /* Post.m */; };
+ 098B1F6815B921CB00ACFAD1 /* ODRefreshControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 098B1F6715B921CB00ACFAD1 /* ODRefreshControl.m */; };
09A4459C1567A6CD00634C53 /* NSDate+TKCategory.m in Sources */ = {isa = PBXBuildFile; fileRef = 09A4458E1567A6CD00634C53 /* NSDate+TKCategory.m */; };
09A4459D1567A6CD00634C53 /* TapkuLibrary.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 09A4458F1567A6CD00634C53 /* TapkuLibrary.bundle */; };
09A4459E1567A6CD00634C53 /* TKCalendarMonthTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 09A445911567A6CD00634C53 /* TKCalendarMonthTableViewController.m */; };
@@ -105,6 +106,8 @@
09359FEC1588977500B4EA3E /* line.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = line.png; sourceTree = "<group>"; };
09517A81158AF4320016EDF8 /* Post.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Post.h; sourceTree = "<group>"; };
09517A82158AF4320016EDF8 /* Post.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Post.m; sourceTree = "<group>"; };
+ 098B1F6615B921CB00ACFAD1 /* ODRefreshControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ODRefreshControl.h; sourceTree = "<group>"; };
+ 098B1F6715B921CB00ACFAD1 /* ODRefreshControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ODRefreshControl.m; sourceTree = "<group>"; };
09A4458D1567A6CD00634C53 /* NSDate+TKCategory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+TKCategory.h"; sourceTree = "<group>"; };
09A4458E1567A6CD00634C53 /* NSDate+TKCategory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "NSDate+TKCategory.m"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
09A4458F1567A6CD00634C53 /* TapkuLibrary.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TapkuLibrary.bundle; sourceTree = "<group>"; };
@@ -237,6 +240,16 @@
path = Model;
sourceTree = "<group>";
};
+ 098B1F6515B921CB00ACFAD1 /* ODRefreshControl */ = {
+ isa = PBXGroup;
+ children = (
+ 098B1F6615B921CB00ACFAD1 /* ODRefreshControl.h */,
+ 098B1F6715B921CB00ACFAD1 /* ODRefreshControl.m */,
+ );
+ name = ODRefreshControl;
+ path = vendor/ODRefreshControl;
+ sourceTree = "<group>";
+ };
09A4458C1567A6CD00634C53 /* TapkuLibrary */ = {
isa = PBXGroup;
children = (
@@ -283,6 +296,7 @@
09B27FF1157D55A00015FF1A /* SVProgressHUD */,
09A4458C1567A6CD00634C53 /* TapkuLibrary */,
A39E34281564E0D40076ED6D /* MKNetworkKit */,
+ 098B1F6515B921CB00ACFAD1 /* ODRefreshControl */,
A39E33F2155FA29F0076ED6D /* HI Capacity */,
A39E3413155FA29F0076ED6D /* HI CapacityTests */,
A39E33EB155FA29F0076ED6D /* Frameworks */,
@@ -602,6 +616,7 @@
0907D664158721E2009C395E /* AboutViewController.m in Sources */,
0907D67115873DF6009C395E /* Location.m in Sources */,
09517A83158AF4320016EDF8 /* Post.m in Sources */,
+ 098B1F6815B921CB00ACFAD1 /* ODRefreshControl.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
2  HI Capacity/PostsViewController.h
@@ -7,9 +7,11 @@
//
#import <UIKit/UIKit.h>
+#import "ODRefreshControl.h"
@interface PostsViewController : UITableViewController<UITableViewDelegate> {
MKNetworkOperation *runningOp;
+ ODRefreshControl *refreshControl;
}
@property (strong, nonatomic) NSMutableArray *posts;
View
61 HI Capacity/PostsViewController.m
@@ -40,25 +40,10 @@ - (void)viewDidLoad
UIImageView *imageView = [[UIImageView alloc] initWithImage: image];
self.navigationItem.titleView = imageView;
- // Start loading spinner
- [self showLoading];
-
- NSMutableDictionary *headerFields = [NSMutableDictionary dictionary];
- [headerFields setValue:@"iOS" forKey:@"x-client-identifier"];
- [headerFields setValue:@"application/json" forKey:@"Accept"];
- HTTPEngine *httpEngine = [[HTTPEngine alloc] initWithHostName:@"hicapacity.org" customHeaderFields:headerFields];
- runningOp = [httpEngine posts:nil :^(NSMutableArray *returnedPosts) {
- posts = returnedPosts;
- [postTableView reloadData];
- [self dismissLoading:NO]; // Stop loading spinner
- runningOp = nil;
- }
- onError:^(NSError *error) {
- // please handle the error
- [self dismissLoading:YES]; // Stop loading spinner
- runningOp = nil;
- }];
+ refreshControl = [[ODRefreshControl alloc] initInScrollView:self.tableView];
+ [refreshControl addTarget:self action:@selector(dropViewDidBeginRefreshing:) forControlEvents:UIControlEventValueChanged];
+ [self reloadPosts];
}
- (void)viewDidUnload
@@ -89,6 +74,42 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}
+- (void)dropViewDidBeginRefreshing:(ODRefreshControl *)refreshControl
+{
+ double delayInSeconds = 0.0;
+ dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
+ dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
+ [self reloadPosts];
+ });
+}
+
+- (void)reloadPosts {
+ // Start loading spinner
+ [self showLoading];
+
+ NSMutableDictionary *headerFields = [NSMutableDictionary dictionary];
+ [headerFields setValue:@"iOS" forKey:@"x-client-identifier"];
+ [headerFields setValue:@"application/json" forKey:@"Accept"];
+ HTTPEngine *httpEngine = [[HTTPEngine alloc] initWithHostName:@"hicapacity.org" customHeaderFields:headerFields];
+ runningOp = [httpEngine posts:nil :^(NSMutableArray *returnedPosts) {
+ posts = returnedPosts;
+ [postTableView reloadData];
+ [self dismissLoading:NO]; // Stop loading spinner
+ if ([refreshControl refreshing]) {
+ [refreshControl endRefreshing]; // Stop the refreshing
+ }
+ runningOp = nil;
+ }
+ onError:^(NSError *error) {
+ // please handle the error
+ [self dismissLoading:YES]; // Stop loading spinner
+ if ([refreshControl refreshing]) {
+ [refreshControl endRefreshing]; // Stop the refreshing
+ }
+ runningOp = nil;
+ }];
+}
+
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
@@ -136,7 +157,7 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
- (void) showLoading {
[SVProgressHUD showWithStatus:@"Loading" maskType:SVProgressHUDMaskTypeNone];
- [[[self view] subviews]makeObjectsPerformSelector:@selector(setUserInteractionEnabled:) withObject:[NSNumber numberWithBool:FALSE]];
+ [[self view] setUserInteractionEnabled:NO];
}
- (void) dismissLoading:(BOOL)error {
@@ -146,7 +167,7 @@ - (void) dismissLoading:(BOOL)error {
else {
[SVProgressHUD dismiss];
}
- [[[self view] subviews]makeObjectsPerformSelector:@selector(setUserInteractionEnabled:) withObject:[NSNumber numberWithBool:TRUE]];
+ [[self view] setUserInteractionEnabled:YES];
}
@end
View
34 vendor/ODRefreshControl/ODRefreshControl.h
@@ -0,0 +1,34 @@
+//
+// ODRefreshControl.h
+// ODRefreshControl
+//
+// Created by Fabio Ritrovato on 6/13/12.
+// Copyright (c) 2012 orange in a day. All rights reserved.
+//
+// https://github.com/Sephiroth87/ODRefreshControl
+//
+
+#import <UIKit/UIKit.h>
+#import <QuartzCore/QuartzCore.h>
+
+@interface ODRefreshControl : UIControl {
+ CAShapeLayer *_shapeLayer;
+ CAShapeLayer *_arrowLayer;
+ CAShapeLayer *_highlightLayer;
+ UIActivityIndicatorView *_activity;
+ BOOL _refreshing;
+ BOOL _canRefresh;
+}
+
+@property (nonatomic, readonly) BOOL refreshing;
+@property (nonatomic, strong) UIColor *tintColor;
+
+- (id)initInScrollView:(UIScrollView *)scrollView;
+
+// Tells the control that a refresh operation was started programmatically
+- (void)beginRefreshing;
+
+// Tells the control the refresh operation has ended
+- (void)endRefreshing;
+
+@end
View
319 vendor/ODRefreshControl/ODRefreshControl.m
@@ -0,0 +1,319 @@
+//
+// ODRefreshControl.m
+// ODRefreshControl
+//
+// Created by Fabio Ritrovato on 6/13/12.
+// Copyright (c) 2012 orange in a day. All rights reserved.
+//
+// https://github.com/Sephiroth87/ODRefreshControl
+//
+
+#import "ODRefreshControl.h"
+
+#define kTotalViewHeight 200
+#define kOpenedViewHeight 44
+#define kMinTopPadding 9
+#define kMaxTopPadding 5
+#define kMinTopRadius 12.5
+#define kMaxTopRadius 16
+#define kMinBottomRadius 3
+#define kMaxBottomRadius 16
+#define kMinBottomPadding 4
+#define kMaxBottomPadding 6
+#define kMinArrowSize 2
+#define kMaxArrowSize 3
+#define kMinArrowRadius 5
+#define kMaxArrowRadius 7
+#define kMaxDistance 53
+
+@interface ODRefreshControl ()
+
+@property (nonatomic, assign) UIScrollView *scrollView;
+
+@end
+
+@implementation ODRefreshControl
+
+@synthesize refreshing = _refreshing;
+@synthesize tintColor = _tintColor;
+
+@synthesize scrollView = _scrollView;
+
+static inline CGFloat lerp(CGFloat a, CGFloat b, CGFloat p)
+{
+ return a + (b - a) * p;
+}
+
+- (id)initInScrollView:(UIScrollView *)scrollView
+{
+ self = [super initWithFrame:CGRectMake(0, -kTotalViewHeight, scrollView.frame.size.width, kTotalViewHeight)];
+ if (self) {
+ self.scrollView = scrollView;
+
+ self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
+ [scrollView addSubview:self];
+ [scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
+
+ _activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
+ _activity.center = CGPointMake(floor(self.frame.size.width / 2), floor(self.frame.size.height / 2));
+ _activity.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
+ _activity.alpha = 0;
+ [_activity startAnimating];
+ [self addSubview:_activity];
+
+ _refreshing = NO;
+ _canRefresh = YES;
+ _tintColor = [UIColor colorWithRed:155.0 / 255.0 green:162.0 / 255.0 blue:172.0 / 255.0 alpha:1.0];
+
+ _shapeLayer = [CAShapeLayer layer];
+ _shapeLayer.fillColor = [_tintColor CGColor];
+ _shapeLayer.strokeColor = [[[UIColor darkGrayColor] colorWithAlphaComponent:0.5] CGColor];
+ _shapeLayer.lineWidth = 0.5;
+ _shapeLayer.shadowColor = [[UIColor blackColor] CGColor];
+ _shapeLayer.shadowOffset = CGSizeMake(0, 1);
+ _shapeLayer.shadowOpacity = 0.4;
+ _shapeLayer.shadowRadius = 0.5;
+ [self.layer addSublayer:_shapeLayer];
+
+ _arrowLayer = [CAShapeLayer layer];
+ _arrowLayer.strokeColor = [[[UIColor darkGrayColor] colorWithAlphaComponent:0.5] CGColor];
+ _arrowLayer.lineWidth = 0.5;
+ _arrowLayer.fillColor = [[UIColor whiteColor] CGColor];
+ [_shapeLayer addSublayer:_arrowLayer];
+
+ _highlightLayer = [CAShapeLayer layer];
+ _highlightLayer.fillColor = [[[UIColor whiteColor] colorWithAlphaComponent:0.2] CGColor];
+ [_shapeLayer addSublayer:_highlightLayer];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [self.scrollView removeObserver:self forKeyPath:@"contentOffset" context:nil];
+ self.scrollView = nil;
+}
+
+- (void)setTintColor:(UIColor *)tintColor
+{
+ _tintColor = tintColor;
+ _shapeLayer.fillColor = [_tintColor CGColor];
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
+{
+ CGFloat offset = [[change objectForKey:@"new"] CGPointValue].y;
+
+ if (_refreshing) {
+ if (offset != 0) {
+ // Keep thing pinned at the top
+
+ [CATransaction begin];
+ [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
+ _shapeLayer.position = CGPointMake(0, kMaxDistance + offset + kOpenedViewHeight);
+ [CATransaction commit];
+ //_activity.center = CGPointMake(floor(self.frame.size.width / 2), MIN(offset + self.frame.size.height + floor(self.frame.size.height / 2), floor(self.frame.size.height / 2)));
+ _activity.center = CGPointMake(floor(self.frame.size.width / 2), MIN(offset + self.frame.size.height + floor(kOpenedViewHeight / 2), self.frame.size.height - kOpenedViewHeight/ 2));
+
+ // Set the inset only when bouncing back and not dragging
+ if (offset >= -kOpenedViewHeight && !self.scrollView.dragging) {
+ [self.scrollView setContentInset:UIEdgeInsetsMake(kOpenedViewHeight, 0, 0, 0)];
+ }
+ }
+ return;
+ } else {
+ // Check if we can trigger a new refresh
+ if (!_canRefresh) {
+ if (offset >= 0) {
+ _canRefresh = YES;
+ } else {
+ return;
+ }
+ }
+ }
+
+ BOOL triggered = NO;
+
+ CGMutablePathRef path = CGPathCreateMutable();
+
+ //Calculate some useful points and values
+ CGFloat verticalShift = MAX(0, -((kMaxTopRadius + kMaxBottomRadius + kMaxTopPadding + kMaxBottomPadding) + offset));
+ CGFloat distance = MIN(kMaxDistance, fabs(verticalShift));
+ CGFloat percentage = 1 - (distance / kMaxDistance);
+
+ CGFloat currentTopPadding = lerp(kMinTopPadding, kMaxTopPadding, percentage);
+ CGFloat currentTopRadius = lerp(kMinTopRadius, kMaxTopRadius, percentage);
+ CGFloat currentBottomRadius = lerp(kMinBottomRadius, kMaxBottomRadius, percentage);
+ CGFloat currentBottomPadding = lerp(kMinBottomPadding, kMaxBottomPadding, percentage);
+
+ CGPoint bottomOrigin = CGPointMake(floor(self.bounds.size.width / 2), self.bounds.size.height - currentBottomPadding -currentBottomRadius);
+ CGPoint topOrigin = CGPointZero;
+ if (distance == 0) {
+ topOrigin = CGPointMake(floor(self.bounds.size.width / 2), bottomOrigin.y);
+ } else {
+ topOrigin = CGPointMake(floor(self.bounds.size.width / 2), self.bounds.size.height + offset + currentTopPadding + currentTopRadius);
+ if (percentage == 0) {
+ bottomOrigin.y -= (fabs(verticalShift) - kMaxDistance);
+ triggered = YES;
+ }
+ }
+
+ //Top semicircle
+ CGPathAddArc(path, NULL, topOrigin.x, topOrigin.y, currentTopRadius, 0, M_PI, YES);
+
+ //Left curve
+ CGPoint leftCp1 = CGPointMake(lerp((topOrigin.x - currentTopRadius), (bottomOrigin.x - currentBottomRadius), 0.1), lerp(topOrigin.y, bottomOrigin.y, 0.2));
+ CGPoint leftCp2 = CGPointMake(lerp((topOrigin.x - currentTopRadius), (bottomOrigin.x - currentBottomRadius), 0.9), lerp(topOrigin.y, bottomOrigin.y, 0.2));
+ CGPoint leftDestination = CGPointMake(bottomOrigin.x - currentBottomRadius, bottomOrigin.y);
+
+ CGPathAddCurveToPoint(path, NULL, leftCp1.x, leftCp1.y, leftCp2.x, leftCp2.y, leftDestination.x, leftDestination.y);
+
+ //Bottom semicircle
+ CGPathAddArc(path, NULL, bottomOrigin.x, bottomOrigin.y, currentBottomRadius, M_PI, 0, YES);
+
+ //Right curve
+ CGPoint rightCp2 = CGPointMake(lerp((topOrigin.x + currentTopRadius), (bottomOrigin.x + currentBottomRadius), 0.1), lerp(topOrigin.y, bottomOrigin.y, 0.2));
+ CGPoint rightCp1 = CGPointMake(lerp((topOrigin.x + currentTopRadius), (bottomOrigin.x + currentBottomRadius), 0.9), lerp(topOrigin.y, bottomOrigin.y, 0.2));
+ CGPoint rightDestination = CGPointMake(topOrigin.x + currentTopRadius, topOrigin.y);
+
+ CGPathAddCurveToPoint(path, NULL, rightCp1.x, rightCp1.y, rightCp2.x, rightCp2.y, rightDestination.x, rightDestination.y);
+ CGPathCloseSubpath(path);
+
+ if (!triggered) {
+ // Set paths
+
+ _shapeLayer.path = path;
+ _shapeLayer.shadowPath = path;
+
+ // Add the arrow shape
+
+ CGFloat currentArrowSize = lerp(kMinArrowSize, kMaxArrowSize, percentage);
+ CGFloat currentArrowRadius = lerp(kMinArrowRadius, kMaxArrowRadius, percentage);
+ CGFloat arrowBigRadius = currentArrowRadius + (currentArrowSize / 2);
+ CGFloat arrowSmallRadius = currentArrowRadius - (currentArrowSize / 2);
+ CGMutablePathRef arrowPath = CGPathCreateMutable();
+ CGPathAddArc(arrowPath, NULL, topOrigin.x, topOrigin.y, arrowBigRadius, 0, 3 * M_PI_2, NO);
+ CGPathAddLineToPoint(arrowPath, NULL, topOrigin.x, topOrigin.y - arrowBigRadius - currentArrowSize);
+ CGPathAddLineToPoint(arrowPath, NULL, topOrigin.x + (2 * currentArrowSize), topOrigin.y - arrowBigRadius + (currentArrowSize / 2));
+ CGPathAddLineToPoint(arrowPath, NULL, topOrigin.x, topOrigin.y - arrowBigRadius + (2 * currentArrowSize));
+ CGPathAddLineToPoint(arrowPath, NULL, topOrigin.x, topOrigin.y - arrowBigRadius + currentArrowSize);
+ CGPathAddArc(arrowPath, NULL, topOrigin.x, topOrigin.y, arrowSmallRadius, 3 * M_PI_2, 0, YES);
+ CGPathCloseSubpath(arrowPath);
+ _arrowLayer.path = arrowPath;
+ [_arrowLayer setFillRule:kCAFillRuleEvenOdd];
+ CGPathRelease(arrowPath);
+
+ // Add thr highlight shape
+
+ CGMutablePathRef highlightPath = CGPathCreateMutable();
+ CGPathAddArc(highlightPath, NULL, topOrigin.x, topOrigin.y, currentTopRadius, 0, M_PI, YES);
+ CGPathAddArc(highlightPath, NULL, topOrigin.x, topOrigin.y + 1.25, currentTopRadius, M_PI, 0, NO);
+
+ _highlightLayer.path = highlightPath;
+ [_highlightLayer setFillRule:kCAFillRuleNonZero];
+ CGPathRelease(highlightPath);
+
+ } else {
+ // Start the shape disappearance animation
+
+ CGFloat radius = lerp(kMinBottomRadius, kMaxBottomRadius, 0.2);
+ CABasicAnimation *pathMorph = [CABasicAnimation animationWithKeyPath:@"path"];
+ pathMorph.duration = 0.15;
+ pathMorph.fillMode = kCAFillModeForwards;
+ pathMorph.removedOnCompletion = NO;
+ CGMutablePathRef toPath = CGPathCreateMutable();
+ CGPathAddArc(toPath, NULL, topOrigin.x, topOrigin.y, radius, 0, M_PI, YES);
+ CGPathAddCurveToPoint(toPath, NULL, topOrigin.x - radius, topOrigin.y, topOrigin.x - radius, topOrigin.y, topOrigin.x - radius, topOrigin.y);
+ CGPathAddArc(toPath, NULL, topOrigin.x, topOrigin.y, radius, M_PI, 0, YES);
+ CGPathAddCurveToPoint(toPath, NULL, topOrigin.x + radius, topOrigin.y, topOrigin.x + radius, topOrigin.y, topOrigin.x + radius, topOrigin.y);
+ CGPathCloseSubpath(toPath);
+ pathMorph.toValue = (__bridge id)toPath;
+ [_shapeLayer addAnimation:pathMorph forKey:nil];
+ CABasicAnimation *shadowPathMorph = [CABasicAnimation animationWithKeyPath:@"shadowPath"];
+ shadowPathMorph.duration = 0.15;
+ shadowPathMorph.fillMode = kCAFillModeForwards;
+ shadowPathMorph.removedOnCompletion = NO;
+ shadowPathMorph.toValue = (__bridge id)toPath;
+ [_shapeLayer addAnimation:shadowPathMorph forKey:nil];
+ CGPathRelease(toPath);
+ CABasicAnimation *shapeAlphaAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
+ shapeAlphaAnimation.duration = 0.1;
+ shapeAlphaAnimation.beginTime = CACurrentMediaTime() + 0.1;
+ shapeAlphaAnimation.toValue = [NSNumber numberWithFloat:0];
+ shapeAlphaAnimation.fillMode = kCAFillModeForwards;
+ shapeAlphaAnimation.removedOnCompletion = NO;
+ [_shapeLayer addAnimation:shapeAlphaAnimation forKey:nil];
+ CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
+ alphaAnimation.duration = 0.1;
+ alphaAnimation.toValue = [NSNumber numberWithFloat:0];
+ alphaAnimation.fillMode = kCAFillModeForwards;
+ alphaAnimation.removedOnCompletion = NO;
+ [_arrowLayer addAnimation:alphaAnimation forKey:nil];
+ [_highlightLayer addAnimation:alphaAnimation forKey:nil];
+
+ [CATransaction begin];
+ [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
+ _activity.layer.transform = CATransform3DMakeScale(0.1, 0.1, 1);
+ [CATransaction commit];
+ [UIView animateWithDuration:0.2 delay:0.15 options:UIViewAnimationOptionCurveLinear animations:^{
+ _activity.alpha = 1;
+ _activity.layer.transform = CATransform3DMakeScale(1, 1, 1);
+ } completion:nil];
+
+ _refreshing = YES;
+ _canRefresh = NO;
+ [self sendActionsForControlEvents:UIControlEventValueChanged];
+ }
+
+ CGPathRelease(path);
+}
+
+- (void)beginRefreshing
+{
+ if (!_refreshing) {
+ CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
+ alphaAnimation.duration = 0.0001;
+ alphaAnimation.toValue = [NSNumber numberWithFloat:0];
+ alphaAnimation.fillMode = kCAFillModeForwards;
+ alphaAnimation.removedOnCompletion = NO;
+ [_shapeLayer addAnimation:alphaAnimation forKey:nil];
+ [_arrowLayer addAnimation:alphaAnimation forKey:nil];
+ [_highlightLayer addAnimation:alphaAnimation forKey:nil];
+
+ [CATransaction begin];
+ [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
+ _activity.layer.transform = CATransform3DMakeScale(0.1, 0.1, 1);
+ [CATransaction commit];
+ [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
+ _activity.alpha = 1;
+ _activity.layer.transform = CATransform3DMakeScale(1, 1, 1);
+ } completion:nil];
+ [UIView animateWithDuration:0.4 animations:^{
+ [self.scrollView setContentInset:UIEdgeInsetsMake(kOpenedViewHeight, 0, 0, 0)];
+ }];
+
+ _refreshing = YES;
+ _canRefresh = NO;
+ }
+}
+
+- (void)endRefreshing
+{
+ _refreshing = NO;
+ [UIView animateWithDuration:0.4 animations:^{
+ [self.scrollView setContentInset:UIEdgeInsetsMake(0, 0, 0, 0)];
+ _activity.alpha = 0;
+ _activity.layer.transform = CATransform3DMakeScale(0.1, 0.1, 1);
+ } completion:^(BOOL finished) {
+ [_shapeLayer removeAllAnimations];
+ _shapeLayer.path = nil;
+ _shapeLayer.shadowPath = nil;
+ _shapeLayer.position = CGPointZero;
+ [_arrowLayer removeAllAnimations];
+ _arrowLayer.path = nil;
+ [_highlightLayer removeAllAnimations];
+ _highlightLayer.path = nil;
+ }];
+}
+
+@end
Please sign in to comment.
Something went wrong with that request. Please try again.