Repository: Friend-LGA/LGRefreshView Branch: master Commit: a9e20b128178 Files: 37 Total size: 124.4 KB Directory structure: gitextract_u9cqzi8n/ ├── .gitignore ├── Demo/ │ ├── LGRefreshViewDemo/ │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── DACircularProgress/ │ │ │ ├── DACircularProgressView.h │ │ │ ├── DACircularProgressView.m │ │ │ ├── DALabeledCircularProgressView.h │ │ │ └── DALabeledCircularProgressView.m │ │ ├── Images.xcassets/ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ └── LaunchImage.launchimage/ │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── NavigationController.h │ │ ├── NavigationController.m │ │ ├── RefreshCollectionViewController.h │ │ ├── RefreshCollectionViewController.m │ │ ├── RefreshScrollViewController.h │ │ ├── RefreshScrollViewController.m │ │ ├── RefreshTableViewController.h │ │ ├── RefreshTableViewController.m │ │ ├── TableViewController.h │ │ ├── TableViewController.m │ │ └── main.m │ └── LGRefreshViewDemo.xcodeproj/ │ ├── project.pbxproj │ └── project.xcworkspace/ │ └── contents.xcworkspacedata ├── Framework/ │ ├── LGRefreshViewFramework/ │ │ ├── DACircularProgress/ │ │ │ ├── DACircularProgressView.h │ │ │ ├── DACircularProgressView.m │ │ │ ├── DALabeledCircularProgressView.h │ │ │ └── DALabeledCircularProgressView.m │ │ ├── Info.plist │ │ └── LGRefreshViewFramework.h │ └── LGRefreshViewFramework.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ └── contents.xcworkspacedata │ └── xcshareddata/ │ └── xcschemes/ │ └── LGRefreshViewFramework.xcscheme ├── LGRefreshView/ │ ├── LGRefreshView.h │ └── LGRefreshView.m ├── LGRefreshView.podspec ├── LICENSE └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Xcode # build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.hmap *.ipa *.xcuserstate # CocoaPods # # We recommend against adding the Pods directory to your .gitignore. However # you should judge for yourself, the pros and cons are mentioned at: # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control # Pods/ ### ._* .hgignore .DS_Store ================================================ FILE: Demo/LGRefreshViewDemo/AppDelegate.h ================================================ // // AppDelegate.h // LGRefreshViewDemo // // Created by Grigory Lutkov on 18.02.15. // Copyright (c) 2015 Grigory Lutkov. All rights reserved. // #import @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end ================================================ FILE: Demo/LGRefreshViewDemo/AppDelegate.m ================================================ // // AppDelegate.m // LGRefreshViewDemo // // Created by Grigory Lutkov on 18.02.15. // Copyright (c) 2015 Grigory Lutkov. All rights reserved. // #import "AppDelegate.h" #import "NavigationController.h" #import "TableViewController.h" @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { TableViewController *tableViewController = [TableViewController new]; NavigationController *navigationController = [[NavigationController alloc] initWithRootViewController:tableViewController]; self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.window.rootViewController = navigationController; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - (void)applicationWillEnterForeground:(UIApplication *)application { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - (void)applicationDidBecomeActive:(UIApplication *)application { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - (void)applicationWillTerminate:(UIApplication *)application { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } @end ================================================ FILE: Demo/LGRefreshViewDemo/DACircularProgress/DACircularProgressView.h ================================================ // // DACircularProgressView.h // DACircularProgress // // Created by Daniel Amitay on 2/6/12. // Copyright (c) 2012 Daniel Amitay. All rights reserved. // #import @interface DACircularProgressView : UIView @property(nonatomic, strong) UIColor *trackTintColor UI_APPEARANCE_SELECTOR; @property(nonatomic, strong) UIColor *progressTintColor UI_APPEARANCE_SELECTOR; @property(nonatomic, strong) UIColor *innerTintColor UI_APPEARANCE_SELECTOR; @property(nonatomic) NSInteger roundedCorners UI_APPEARANCE_SELECTOR; // Can not use BOOL with UI_APPEARANCE_SELECTOR :-( @property(nonatomic) CGFloat thicknessRatio UI_APPEARANCE_SELECTOR; @property(nonatomic) NSInteger clockwiseProgress UI_APPEARANCE_SELECTOR; // Can not use BOOL with UI_APPEARANCE_SELECTOR :-( @property(nonatomic) CGFloat progress; @property(nonatomic) CGFloat indeterminateDuration UI_APPEARANCE_SELECTOR; @property(nonatomic) NSInteger indeterminate UI_APPEARANCE_SELECTOR; // Can not use BOOL with UI_APPEARANCE_SELECTOR :-( - (void)setProgress:(CGFloat)progress animated:(BOOL)animated; - (void)setProgress:(CGFloat)progress animated:(BOOL)animated initialDelay:(CFTimeInterval)initialDelay; - (void)setProgress:(CGFloat)progress animated:(BOOL)animated initialDelay:(CFTimeInterval)initialDelay withDuration:(CFTimeInterval)duration; @end ================================================ FILE: Demo/LGRefreshViewDemo/DACircularProgress/DACircularProgressView.m ================================================ // // DACircularProgressView.m // DACircularProgress // // Created by Daniel Amitay on 2/6/12. // Copyright (c) 2012 Daniel Amitay. All rights reserved. // #import "DACircularProgressView.h" #import @interface DACircularProgressLayer : CALayer @property(nonatomic, strong) UIColor *trackTintColor; @property(nonatomic, strong) UIColor *progressTintColor; @property(nonatomic, strong) UIColor *innerTintColor; @property(nonatomic) NSInteger roundedCorners; @property(nonatomic) CGFloat thicknessRatio; @property(nonatomic) CGFloat progress; @property(nonatomic) NSInteger clockwiseProgress; @end @implementation DACircularProgressLayer @dynamic trackTintColor; @dynamic progressTintColor; @dynamic innerTintColor; @dynamic roundedCorners; @dynamic thicknessRatio; @dynamic progress; @dynamic clockwiseProgress; + (BOOL)needsDisplayForKey:(NSString *)key { if ([key isEqualToString:@"progress"]) { return YES; } else { return [super needsDisplayForKey:key]; } } - (void)drawInContext:(CGContextRef)context { CGRect rect = self.bounds; CGPoint centerPoint = CGPointMake(rect.size.width / 2.0f, rect.size.height / 2.0f); CGFloat radius = MIN(rect.size.height, rect.size.width) / 2.0f; BOOL clockwise = (self.clockwiseProgress != 0); CGFloat progress = MIN(self.progress, 1.0f - FLT_EPSILON); CGFloat radians = 0; if (clockwise) { radians = (float)((progress * 2.0f * M_PI) - M_PI_2); } else { radians = (float)(3 * M_PI_2 - (progress * 2.0f * M_PI)); } CGContextSetFillColorWithColor(context, self.trackTintColor.CGColor); CGMutablePathRef trackPath = CGPathCreateMutable(); CGPathMoveToPoint(trackPath, NULL, centerPoint.x, centerPoint.y); CGPathAddArc(trackPath, NULL, centerPoint.x, centerPoint.y, radius, (float)(2.0f * M_PI), 0.0f, TRUE); CGPathCloseSubpath(trackPath); CGContextAddPath(context, trackPath); CGContextFillPath(context); CGPathRelease(trackPath); if (progress > 0.0f) { CGContextSetFillColorWithColor(context, self.progressTintColor.CGColor); CGMutablePathRef progressPath = CGPathCreateMutable(); CGPathMoveToPoint(progressPath, NULL, centerPoint.x, centerPoint.y); CGPathAddArc(progressPath, NULL, centerPoint.x, centerPoint.y, radius, (float)(3.0f * M_PI_2), radians, !clockwise); CGPathCloseSubpath(progressPath); CGContextAddPath(context, progressPath); CGContextFillPath(context); CGPathRelease(progressPath); } if (progress > 0.0f && self.roundedCorners) { CGFloat pathWidth = radius * self.thicknessRatio; CGFloat xOffset = radius * (1.0f + ((1.0f - (self.thicknessRatio / 2.0f)) * cosf(radians))); CGFloat yOffset = radius * (1.0f + ((1.0f - (self.thicknessRatio / 2.0f)) * sinf(radians))); CGPoint endPoint = CGPointMake(xOffset, yOffset); CGRect startEllipseRect = (CGRect) { .origin.x = centerPoint.x - pathWidth / 2.0f, .origin.y = 0.0f, .size.width = pathWidth, .size.height = pathWidth }; CGContextAddEllipseInRect(context, startEllipseRect); CGContextFillPath(context); CGRect endEllipseRect = (CGRect) { .origin.x = endPoint.x - pathWidth / 2.0f, .origin.y = endPoint.y - pathWidth / 2.0f, .size.width = pathWidth, .size.height = pathWidth }; CGContextAddEllipseInRect(context, endEllipseRect); CGContextFillPath(context); } CGContextSetBlendMode(context, kCGBlendModeClear); CGFloat innerRadius = radius * (1.0f - self.thicknessRatio); CGRect clearRect = (CGRect) { .origin.x = centerPoint.x - innerRadius, .origin.y = centerPoint.y - innerRadius, .size.width = innerRadius * 2.0f, .size.height = innerRadius * 2.0f }; CGContextAddEllipseInRect(context, clearRect); CGContextFillPath(context); if (self.innerTintColor) { CGContextSetBlendMode(context, kCGBlendModeNormal); CGContextSetFillColorWithColor(context, [self.innerTintColor CGColor]); CGContextAddEllipseInRect(context, clearRect); CGContextFillPath(context); } } @end @interface DACircularProgressView () @end @implementation DACircularProgressView + (void) initialize { if (self == [DACircularProgressView class]) { DACircularProgressView *circularProgressViewAppearance = [DACircularProgressView appearance]; [circularProgressViewAppearance setTrackTintColor:[[UIColor whiteColor] colorWithAlphaComponent:0.3f]]; [circularProgressViewAppearance setProgressTintColor:[UIColor whiteColor]]; [circularProgressViewAppearance setInnerTintColor:nil]; [circularProgressViewAppearance setBackgroundColor:[UIColor clearColor]]; [circularProgressViewAppearance setThicknessRatio:0.3f]; [circularProgressViewAppearance setRoundedCorners:NO]; [circularProgressViewAppearance setClockwiseProgress:YES]; [circularProgressViewAppearance setIndeterminateDuration:2.0f]; [circularProgressViewAppearance setIndeterminate:NO]; } } + (Class)layerClass { return [DACircularProgressLayer class]; } - (DACircularProgressLayer *)circularProgressLayer { return (DACircularProgressLayer *)self.layer; } - (id)init { return [super initWithFrame:CGRectMake(0.0f, 0.0f, 40.0f, 40.0f)]; } - (void)didMoveToWindow { [super didMoveToWindow]; CGFloat windowContentsScale = self.window.screen.scale; self.circularProgressLayer.contentsScale = windowContentsScale; [self.circularProgressLayer setNeedsDisplay]; } #pragma mark - Progress - (CGFloat)progress { return self.circularProgressLayer.progress; } - (void)setProgress:(CGFloat)progress { [self setProgress:progress animated:NO]; } - (void)setProgress:(CGFloat)progress animated:(BOOL)animated { [self setProgress:progress animated:animated initialDelay:0.0]; } - (void)setProgress:(CGFloat)progress animated:(BOOL)animated initialDelay:(CFTimeInterval)initialDelay { CGFloat pinnedProgress = MIN(MAX(progress, 0.0f), 1.0f); [self setProgress:progress animated:animated initialDelay:initialDelay withDuration:fabs(self.progress - pinnedProgress)]; } - (void)setProgress:(CGFloat)progress animated:(BOOL)animated initialDelay:(CFTimeInterval)initialDelay withDuration:(CFTimeInterval)duration { [self.layer removeAnimationForKey:@"indeterminateAnimation"]; [self.circularProgressLayer removeAnimationForKey:@"progress"]; CGFloat pinnedProgress = MIN(MAX(progress, 0.0f), 1.0f); if (animated) { CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"progress"]; animation.duration = duration; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; animation.fillMode = kCAFillModeForwards; animation.fromValue = [NSNumber numberWithFloat:self.progress]; animation.toValue = [NSNumber numberWithFloat:pinnedProgress]; animation.beginTime = CACurrentMediaTime() + initialDelay; animation.delegate = self; [self.circularProgressLayer addAnimation:animation forKey:@"progress"]; } else { [self.circularProgressLayer setNeedsDisplay]; self.circularProgressLayer.progress = pinnedProgress; } } - (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag { NSNumber *pinnedProgressNumber = [animation valueForKey:@"toValue"]; self.circularProgressLayer.progress = [pinnedProgressNumber floatValue]; } #pragma mark - UIAppearance methods - (UIColor *)trackTintColor { return self.circularProgressLayer.trackTintColor; } - (void)setTrackTintColor:(UIColor *)trackTintColor { self.circularProgressLayer.trackTintColor = trackTintColor; [self.circularProgressLayer setNeedsDisplay]; } - (UIColor *)progressTintColor { return self.circularProgressLayer.progressTintColor; } - (void)setProgressTintColor:(UIColor *)progressTintColor { self.circularProgressLayer.progressTintColor = progressTintColor; [self.circularProgressLayer setNeedsDisplay]; } - (UIColor *)innerTintColor { return self.circularProgressLayer.innerTintColor; } - (void)setInnerTintColor:(UIColor *)innerTintColor { self.circularProgressLayer.innerTintColor = innerTintColor; [self.circularProgressLayer setNeedsDisplay]; } - (NSInteger)roundedCorners { return self.roundedCorners; } - (void)setRoundedCorners:(NSInteger)roundedCorners { self.circularProgressLayer.roundedCorners = roundedCorners; [self.circularProgressLayer setNeedsDisplay]; } - (CGFloat)thicknessRatio { return self.circularProgressLayer.thicknessRatio; } - (void)setThicknessRatio:(CGFloat)thicknessRatio { self.circularProgressLayer.thicknessRatio = MIN(MAX(thicknessRatio, 0.f), 1.f); [self.circularProgressLayer setNeedsDisplay]; } - (NSInteger)indeterminate { CAAnimation *spinAnimation = [self.layer animationForKey:@"indeterminateAnimation"]; return (spinAnimation == nil ? 0 : 1); } - (void)setIndeterminate:(NSInteger)indeterminate { if (indeterminate) { if (!self.indeterminate) { CABasicAnimation *spinAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; spinAnimation.byValue = [NSNumber numberWithDouble:indeterminate > 0 ? 2.0f*M_PI : -2.0f*M_PI]; spinAnimation.duration = self.indeterminateDuration; spinAnimation.repeatCount = HUGE_VALF; [self.layer addAnimation:spinAnimation forKey:@"indeterminateAnimation"]; } } else { [self.layer removeAnimationForKey:@"indeterminateAnimation"]; } } - (NSInteger)clockwiseProgress { return self.circularProgressLayer.clockwiseProgress; } - (void)setClockwiseProgress:(NSInteger)clockwiseProgres { self.circularProgressLayer.clockwiseProgress = clockwiseProgres; [self.circularProgressLayer setNeedsDisplay]; } @end ================================================ FILE: Demo/LGRefreshViewDemo/DACircularProgress/DALabeledCircularProgressView.h ================================================ // // DALabeledCircularProgressView.h // DACircularProgressExample // // Created by Josh Sklar on 4/8/14. // Copyright (c) 2014 Shout Messenger. All rights reserved. // #import "DACircularProgressView.h" /** @class DALabeledCircularProgressView @brief Subclass of DACircularProgressView that adds a UILabel. */ @interface DALabeledCircularProgressView : DACircularProgressView /** UILabel placed right on the DACircularProgressView. */ @property (strong, nonatomic) UILabel *progressLabel; @end ================================================ FILE: Demo/LGRefreshViewDemo/DACircularProgress/DALabeledCircularProgressView.m ================================================ // // DALabeledCircularProgressView.m // DACircularProgressExample // // Created by Josh Sklar on 4/8/14. // Copyright (c) 2014 Shout Messenger. All rights reserved. // #import "DALabeledCircularProgressView.h" @implementation DALabeledCircularProgressView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self initializeLabel]; } return self; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { [self initializeLabel]; } return self; } #pragma mark - Internal methods /** Creates and initializes -[DALabeledCircularProgressView progressLabel]. */ - (void)initializeLabel { self.progressLabel = [[UILabel alloc] initWithFrame:self.bounds]; self.progressLabel.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; self.progressLabel.textAlignment = NSTextAlignmentCenter; self.progressLabel.backgroundColor = [UIColor clearColor]; [self addSubview:self.progressLabel]; } @end ================================================ FILE: Demo/LGRefreshViewDemo/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/LGRefreshViewDemo/Images.xcassets/LaunchImage.launchimage/Contents.json ================================================ { "images" : [ { "extent" : "full-screen", "idiom" : "iphone", "subtype" : "736h", "filename" : "Launch-Phone-55-P@3x.png", "minimum-system-version" : "8.0", "orientation" : "portrait", "scale" : "3x" }, { "extent" : "full-screen", "idiom" : "iphone", "subtype" : "736h", "filename" : "Launch-Phone-55-L@3x.png", "minimum-system-version" : "8.0", "orientation" : "landscape", "scale" : "3x" }, { "extent" : "full-screen", "idiom" : "iphone", "subtype" : "667h", "filename" : "Launch-Phone-47-P@2x.png", "minimum-system-version" : "8.0", "orientation" : "portrait", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "iphone", "extent" : "full-screen", "minimum-system-version" : "7.0", "filename" : "Launch-Phone-35-P@2x.png", "scale" : "2x" }, { "extent" : "full-screen", "idiom" : "iphone", "subtype" : "retina4", "filename" : "Launch-Phone-40-P@2x.png", "minimum-system-version" : "7.0", "orientation" : "portrait", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "filename" : "Launch-Pad-P@1x.png", "scale" : "1x" }, { "orientation" : "landscape", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "filename" : "Launch-Pad-L@1x.png", "scale" : "1x" }, { "orientation" : "portrait", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "filename" : "Launch-Pad-P@2x.png", "scale" : "2x" }, { "orientation" : "landscape", "idiom" : "ipad", "extent" : "full-screen", "minimum-system-version" : "7.0", "filename" : "Launch-Pad-L@2x.png", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "iphone", "extent" : "full-screen", "filename" : "Launch-Phone-35-P@1x.png", "scale" : "1x" }, { "orientation" : "portrait", "idiom" : "iphone", "extent" : "full-screen", "filename" : "Launch-Phone-35-P@2x.png", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "iphone", "extent" : "full-screen", "filename" : "Launch-Phone-40-P@2x.png", "subtype" : "retina4", "scale" : "2x" }, { "orientation" : "portrait", "idiom" : "ipad", "extent" : "full-screen", "filename" : "Launch-Pad-P@1x.png", "scale" : "1x" }, { "orientation" : "landscape", "idiom" : "ipad", "extent" : "full-screen", "filename" : "Launch-Pad-L@1x.png", "scale" : "1x" }, { "orientation" : "portrait", "idiom" : "ipad", "extent" : "full-screen", "filename" : "Launch-Pad-P@2x.png", "scale" : "2x" }, { "orientation" : "landscape", "idiom" : "ipad", "extent" : "full-screen", "filename" : "Launch-Pad-L@2x.png", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: Demo/LGRefreshViewDemo/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSRequiresIPhoneOS UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: Demo/LGRefreshViewDemo/NavigationController.h ================================================ // // NavigationController.h // LGRefreshViewDemo // // Created by Grigory Lutkov on 18.02.15. // Copyright (c) 2015 Grigory Lutkov. All rights reserved. // #import @interface NavigationController : UINavigationController @end ================================================ FILE: Demo/LGRefreshViewDemo/NavigationController.m ================================================ // // NavigationController.m // LGRefreshViewDemo // // Created by Grigory Lutkov on 18.02.15. // Copyright (c) 2015 Grigory Lutkov. All rights reserved. // #import "NavigationController.h" @interface NavigationController () @end @implementation NavigationController - (void)viewDidLoad { [super viewDidLoad]; self.navigationBar.translucent = YES; self.navigationBar.barTintColor = [UIColor colorWithRed:0.f green:0.5 blue:1.f alpha:1.f]; self.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName: [UIColor whiteColor]}; self.navigationBar.tintColor = [UIColor colorWithWhite:1.f alpha:0.5]; } - (BOOL)shouldAutorotate { return self.topViewController.shouldAutorotate; } - (BOOL)prefersStatusBarHidden { return UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation); } - (UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleLightContent; } @end ================================================ FILE: Demo/LGRefreshViewDemo/RefreshCollectionViewController.h ================================================ // // RefreshCollectionViewController.h // LGRefreshViewDemo // // Created by Grigory Lutkov on 22.02.15. // Copyright (c) 2015 Grigory Lutkov. All rights reserved. // #import @interface RefreshCollectionViewController : UIViewController - (id)initWithTitle:(NSString *)title; @end ================================================ FILE: Demo/LGRefreshViewDemo/RefreshCollectionViewController.m ================================================ // // RefreshCollectionViewController.m // LGRefreshViewDemo // // Created by Grigory Lutkov on 22.02.15. // Copyright (c) 2015 Grigory Lutkov. All rights reserved. // #import "RefreshCollectionViewController.h" #import "LGRefreshView.h" @interface RefreshCollectionViewCell : UICollectionViewCell @property (strong, nonatomic) UILabel *textLabel; @property (strong, nonatomic) UIView *separatorView; @end @implementation RefreshCollectionViewCell - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { _textLabel = [UILabel new]; _textLabel.font = [UIFont systemFontOfSize:16.f]; [self addSubview:_textLabel]; _separatorView = [UIView new]; _separatorView.backgroundColor = [UIColor colorWithRed:0.85 green:0.85 blue:0.85 alpha:1.f]; [self addSubview:_separatorView]; } return self; } - (void)layoutSubviews { [super layoutSubviews]; [_textLabel sizeToFit]; _textLabel.center = CGPointMake(self.frame.size.width/2, self.frame.size.height/2); _textLabel.frame = CGRectIntegral(_textLabel.frame); _separatorView.frame = CGRectMake(15.f, self.frame.size.height-1.f, self.frame.size.width-30.f, 1.f); } @end #pragma mark - @interface RefreshCollectionViewController () @property (strong, nonatomic) UICollectionView *collectionView; @property (strong, nonatomic) NSString *updateString; @property (strong, nonatomic) UIButton *triggerButton; @property (strong, nonatomic) LGRefreshView *refreshView; @end @implementation RefreshCollectionViewController - (id)initWithTitle:(NSString *)title { self = [super init]; if (self) { self.title = title; // ----- UIColor *blueColor = [UIColor colorWithRed:0.f green:0.5 blue:1.f alpha:1.f]; UIColor *grayColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.f]; UICollectionViewFlowLayout *collectionViewLayout = [UICollectionViewFlowLayout new]; collectionViewLayout.sectionInset = UIEdgeInsetsZero; collectionViewLayout.minimumLineSpacing = 0.f; collectionViewLayout.minimumInteritemSpacing = 0.f; collectionViewLayout.scrollDirection = UICollectionViewScrollDirectionVertical; _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:collectionViewLayout]; _collectionView.dataSource = self; _collectionView.delegate = self; _collectionView.backgroundColor = [UIColor whiteColor]; _collectionView.alwaysBounceVertical = YES; _collectionView.allowsSelection = NO; [_collectionView registerClass:[RefreshCollectionViewCell class] forCellWithReuseIdentifier:@"cell"]; [self.view addSubview:_collectionView]; _updateString = @"Updated never"; _triggerButton = [UIButton new]; [_triggerButton setBackgroundImage:[self image1x1WithColor:grayColor] forState:UIControlStateNormal]; [_triggerButton setBackgroundImage:[self image1x1WithColor:blueColor] forState:UIControlStateHighlighted]; [_triggerButton setTitle:@"Trigger" forState:UIControlStateNormal]; [_triggerButton setTitleColor:blueColor forState:UIControlStateNormal]; [_triggerButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted]; [_triggerButton addTarget:self action:@selector(triggerAction) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:_triggerButton]; // ----- __weak typeof(self) wself = self; _refreshView = [LGRefreshView refreshViewWithScrollView:_collectionView refreshHandler:^(LGRefreshView *refreshView) { if (wself) { __strong typeof(wself) self = wself; NSDate *date = [NSDate date]; NSDateFormatter *dateFormatter = [NSDateFormatter new]; dateFormatter.dateFormat = @"yyyy.MM.dd HH:mm:ss"; self.updateString = [NSString stringWithFormat:@"Updated at %@", [dateFormatter stringFromDate:date]]; [self.collectionView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:0 inSection:0]]]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void) { [self.refreshView endRefreshing]; }); } }]; _refreshView.tintColor = blueColor; _refreshView.backgroundColor = grayColor; } return self; } - (UIImage *)image1x1WithColor:(UIColor *)color { CGRect rect = CGRectMake(0.f, 0.f, 1.f, 1.f); UIGraphicsBeginImageContext(rect.size); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, color.CGColor); CGContextFillRect(context, rect); UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } #pragma mark - Dealloc - (void)dealloc { NSLog(@"%s [Line %d]", __PRETTY_FUNCTION__, __LINE__); } #pragma mark - Appearing - (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; [_collectionView.collectionViewLayout invalidateLayout]; _collectionView.frame = CGRectMake(0.f, 0.f, self.view.frame.size.width, self.view.frame.size.height); _triggerButton.frame = CGRectMake(0.f, self.view.frame.size.height-44.f, self.view.frame.size.width, 44.f); } #pragma mark - Rotation /** Its not nessessery, but better duing like so */ - (BOOL)shouldAutorotate { return !_refreshView.isRefreshing; } #pragma mark - UICollectionView DataSource - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return 1; } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return 1; } #pragma mark - UICollectionView Delegate - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { RefreshCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath]; cell.textLabel.text = _updateString; [cell setNeedsLayout]; return cell; } #pragma mark - UICollectionViewLayout Delegate - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { return CGSizeMake(self.view.frame.size.width, 44.f); } #pragma mark - - (void)triggerAction { [_refreshView triggerAnimated:YES]; } @end ================================================ FILE: Demo/LGRefreshViewDemo/RefreshScrollViewController.h ================================================ // // RefreshScrollViewController.h // LGRefreshViewDemo // // Created by Grigory Lutkov on 18.02.15. // Copyright (c) 2015 Grigory Lutkov. All rights reserved. // #import @interface RefreshScrollViewController : UIViewController - (id)initWithTitle:(NSString *)title; @end ================================================ FILE: Demo/LGRefreshViewDemo/RefreshScrollViewController.m ================================================ // // RefreshScrollViewController.m // LGRefreshViewDemo // // Created by Grigory Lutkov on 18.02.15. // Copyright (c) 2015 Grigory Lutkov. All rights reserved. // #import "RefreshScrollViewController.h" #import "LGRefreshView.h" @interface RefreshScrollViewController () @property (strong, nonatomic) UIScrollView *scrollView; @property (strong, nonatomic) UILabel *updateLabel; @property (strong, nonatomic) UIButton *triggerButton; @property (strong, nonatomic) LGRefreshView *refreshView; @end @implementation RefreshScrollViewController - (id)initWithTitle:(NSString *)title { self = [super init]; if (self) { self.title = title; // ----- UIColor *blueColor = [UIColor colorWithRed:0.f green:0.5 blue:1.f alpha:1.f]; UIColor *grayColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.f]; _scrollView = [UIScrollView new]; _scrollView.backgroundColor = [UIColor whiteColor]; _scrollView.alwaysBounceVertical = YES; [self.view addSubview:_scrollView]; _updateLabel = [UILabel new]; _updateLabel.font = [UIFont systemFontOfSize:16.f]; _updateLabel.text = @"Updated never"; [_scrollView addSubview:_updateLabel]; _triggerButton = [UIButton new]; [_triggerButton setBackgroundImage:[self image1x1WithColor:grayColor] forState:UIControlStateNormal]; [_triggerButton setBackgroundImage:[self image1x1WithColor:blueColor] forState:UIControlStateHighlighted]; [_triggerButton setTitle:@"Trigger" forState:UIControlStateNormal]; [_triggerButton setTitleColor:blueColor forState:UIControlStateNormal]; [_triggerButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted]; [_triggerButton addTarget:self action:@selector(triggerAction) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:_triggerButton]; // ----- __weak typeof(self) wself = self; _refreshView = [LGRefreshView refreshViewWithScrollView:_scrollView refreshHandler:^(LGRefreshView *refreshView) { if (wself) { __strong typeof(wself) self = wself; NSDate *date = [NSDate date]; NSDateFormatter *dateFormatter = [NSDateFormatter new]; dateFormatter.dateFormat = @"yyyy.MM.dd HH:mm:ss"; self.updateLabel.text = [NSString stringWithFormat:@"Updated at %@", [dateFormatter stringFromDate:date]]; [self.updateLabel sizeToFit]; self.updateLabel.center = CGPointMake(self.scrollView.frame.size.width/2, 20.f+self.updateLabel.frame.size.height/2); self.updateLabel.frame = CGRectIntegral(self.updateLabel.frame); self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width, self.updateLabel.frame.origin.y+self.updateLabel.frame.size.height+20.f); [UIView transitionWithView:self.updateLabel duration:0.3 options:UIViewAnimationOptionTransitionCrossDissolve animations:nil completion:nil]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void) { [self.refreshView endRefreshing]; }); } }]; _refreshView.tintColor = blueColor; _refreshView.backgroundColor = grayColor; } return self; } - (UIImage *)image1x1WithColor:(UIColor *)color { CGRect rect = CGRectMake(0.f, 0.f, 1.f, 1.f); UIGraphicsBeginImageContext(rect.size); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, color.CGColor); CGContextFillRect(context, rect); UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } #pragma mark - Dealloc - (void)dealloc { NSLog(@"%s [Line %d]", __PRETTY_FUNCTION__, __LINE__); } #pragma mark - Appearing - (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; _scrollView.frame = CGRectMake(0.f, 0.f, self.view.frame.size.width, self.view.frame.size.height); [_updateLabel sizeToFit]; _updateLabel.center = CGPointMake(_scrollView.frame.size.width/2, 20.f+_updateLabel.frame.size.height/2); _updateLabel.frame = CGRectIntegral(_updateLabel.frame); _scrollView.contentSize = CGSizeMake(_scrollView.frame.size.width, _updateLabel.frame.origin.y+_updateLabel.frame.size.height+20.f); _triggerButton.frame = CGRectMake(0.f, self.view.frame.size.height-44.f, self.view.frame.size.width, 44.f); } #pragma mark - Rotation /** It's not necessary, but better doing like so */ - (BOOL)shouldAutorotate { return !_refreshView.isRefreshing; } #pragma mark - - (void)triggerAction { [_refreshView triggerAnimated:YES]; } @end ================================================ FILE: Demo/LGRefreshViewDemo/RefreshTableViewController.h ================================================ // // RefreshTableViewController.h // LGRefreshViewDemo // // Created by Grigory Lutkov on 21.02.15. // Copyright (c) 2015 Grigory Lutkov. All rights reserved. // #import @interface RefreshTableViewController : UIViewController - (id)initWithTitle:(NSString *)title; @end ================================================ FILE: Demo/LGRefreshViewDemo/RefreshTableViewController.m ================================================ // // RefreshTableViewController.m // LGRefreshViewDemo // // Created by Grigory Lutkov on 21.02.15. // Copyright (c) 2015 Grigory Lutkov. All rights reserved. // #import "RefreshTableViewController.h" #import "LGRefreshView.h" @interface RefreshTableViewController () @property (strong, nonatomic) UITableView *tableView; @property (strong, nonatomic) NSString *updateString; @property (strong, nonatomic) UIButton *triggerButton; @property (strong, nonatomic) LGRefreshView *refreshView; @end @implementation RefreshTableViewController - (id)initWithTitle:(NSString *)title { self = [super init]; if (self) { self.title = title; // ----- UIColor *blueColor = [UIColor colorWithRed:0.f green:0.5 blue:1.f alpha:1.f]; UIColor *grayColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.f]; _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain]; _tableView.dataSource = self; _tableView.delegate = self; _tableView.backgroundColor = [UIColor whiteColor]; _tableView.alwaysBounceVertical = YES; _tableView.allowsSelection = NO; [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"]; [self.view addSubview:_tableView]; _updateString = @"Updated never"; _triggerButton = [UIButton new]; [_triggerButton setBackgroundImage:[self image1x1WithColor:grayColor] forState:UIControlStateNormal]; [_triggerButton setBackgroundImage:[self image1x1WithColor:blueColor] forState:UIControlStateHighlighted]; [_triggerButton setTitle:@"Trigger" forState:UIControlStateNormal]; [_triggerButton setTitleColor:blueColor forState:UIControlStateNormal]; [_triggerButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted]; [_triggerButton addTarget:self action:@selector(triggerAction) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:_triggerButton]; // ----- __weak typeof(self) wself = self; _refreshView = [LGRefreshView refreshViewWithScrollView:_tableView refreshHandler:^(LGRefreshView *refreshView) { if (wself) { __strong typeof(wself) self = wself; NSDate *date = [NSDate date]; NSDateFormatter *dateFormatter = [NSDateFormatter new]; dateFormatter.dateFormat = @"yyyy.MM.dd HH:mm:ss"; self.updateString = [NSString stringWithFormat:@"Updated at %@", [dateFormatter stringFromDate:date]]; [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void) { [self.refreshView endRefreshing]; }); } }]; _refreshView.tintColor = blueColor; _refreshView.backgroundColor = grayColor; } return self; } - (UIImage *)image1x1WithColor:(UIColor *)color { CGRect rect = CGRectMake(0.f, 0.f, 1.f, 1.f); UIGraphicsBeginImageContext(rect.size); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(context, color.CGColor); CGContextFillRect(context, rect); UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } #pragma mark - Dealloc - (void)dealloc { NSLog(@"%s [Line %d]", __PRETTY_FUNCTION__, __LINE__); } #pragma mark - Appearing - (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; _tableView.frame = CGRectMake(0.f, 0.f, self.view.frame.size.width, self.view.frame.size.height); _triggerButton.frame = CGRectMake(0.f, self.view.frame.size.height-44.f, self.view.frame.size.width, 44.f); } #pragma mark - Rotation /** It's not necessary, but better doing like so */ - (BOOL)shouldAutorotate { return !_refreshView.isRefreshing; } #pragma mark - UITableView DataSource - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 1; } #pragma mark - UITableView Delegate - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; cell.textLabel.text = _updateString; return cell; } #pragma mark - UITableView Delegate - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 44.f; } #pragma mark - - (void)triggerAction { [_refreshView triggerAnimated:YES]; } @end ================================================ FILE: Demo/LGRefreshViewDemo/TableViewController.h ================================================ // // TableViewController.h // LGRefreshViewDemo // // Created by Grigory Lutkov on 18.02.15. // Copyright (c) 2015 Grigory Lutkov. All rights reserved. // #import @interface TableViewController : UITableViewController @end ================================================ FILE: Demo/LGRefreshViewDemo/TableViewController.m ================================================ // // TableViewController.m // LGRefreshViewDemo // // Created by Grigory Lutkov on 18.02.15. // Copyright (c) 2015 Grigory Lutkov. All rights reserved. // #import "TableViewController.h" #import "RefreshScrollViewController.h" #import "RefreshTableViewController.h" #import "RefreshCollectionViewController.h" @interface TableViewController () @property (strong, nonatomic) NSArray *titlesArray; @end @implementation TableViewController - (id)init { self = [super initWithStyle:UITableViewStylePlain]; if (self) { self.title = @"LGRefreshView"; _titlesArray = @[@"UIScrollView", @"UITableView", @"UICollectionView"]; [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"]; } return self; } #pragma mark - UITableView DataSource - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return _titlesArray.count; } #pragma mark - UITableView Delegate - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; cell.textLabel.font = [UIFont systemFontOfSize:16.f]; cell.textLabel.text = _titlesArray[indexPath.row]; return cell; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 44.f; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.row == 0) { RefreshScrollViewController *viewController = [[RefreshScrollViewController alloc] initWithTitle:_titlesArray[indexPath.row]]; [self.navigationController pushViewController:viewController animated:YES]; } else if (indexPath.row == 1) { RefreshTableViewController *viewController = [[RefreshTableViewController alloc] initWithTitle:_titlesArray[indexPath.row]]; [self.navigationController pushViewController:viewController animated:YES]; } else if (indexPath.row == 2) { RefreshCollectionViewController *viewController = [[RefreshCollectionViewController alloc] initWithTitle:_titlesArray[indexPath.row]]; [self.navigationController pushViewController:viewController animated:YES]; } } @end ================================================ FILE: Demo/LGRefreshViewDemo/main.m ================================================ // // main.m // LGRefreshViewDemo // // Created by Grigory Lutkov on 18.02.15. // Copyright (c) 2015 Grigory Lutkov. All rights reserved. // #import #import "AppDelegate.h" int main(int argc, char * argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } ================================================ FILE: Demo/LGRefreshViewDemo.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 4A2C41B71BF4C9E300D071CD /* DACircularProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A2C41B41BF4C9E300D071CD /* DACircularProgressView.m */; }; 4A2C41B81BF4C9E300D071CD /* DALabeledCircularProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A2C41B61BF4C9E300D071CD /* DALabeledCircularProgressView.m */; }; 4A2C41BC1BF4CA0100D071CD /* LGRefreshView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A2C41BB1BF4CA0100D071CD /* LGRefreshView.m */; }; 4A45A9C91A98AE2A00AC75D0 /* RefreshTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A45A9C81A98AE2A00AC75D0 /* RefreshTableViewController.m */; }; 4A4783A31A99D6560058F504 /* RefreshCollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A4783A21A99D6560058F504 /* RefreshCollectionViewController.m */; }; 4ADC01FC1AC2E1E900F40A74 /* RefreshScrollViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4ADC01F51AC2E1E900F40A74 /* RefreshScrollViewController.m */; }; 841015B91A94CA2B0004B53B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 841015B81A94CA2B0004B53B /* main.m */; }; 841015BC1A94CA2B0004B53B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 841015BB1A94CA2B0004B53B /* AppDelegate.m */; }; 841015BF1A94CA2B0004B53B /* TableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 841015BE1A94CA2B0004B53B /* TableViewController.m */; }; 841015C41A94CA2B0004B53B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 841015C31A94CA2B0004B53B /* Images.xcassets */; }; 841015DE1A94CAEA0004B53B /* NavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 841015DD1A94CAEA0004B53B /* NavigationController.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 4A2C41B31BF4C9E300D071CD /* DACircularProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DACircularProgressView.h; sourceTree = ""; }; 4A2C41B41BF4C9E300D071CD /* DACircularProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DACircularProgressView.m; sourceTree = ""; }; 4A2C41B51BF4C9E300D071CD /* DALabeledCircularProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DALabeledCircularProgressView.h; sourceTree = ""; }; 4A2C41B61BF4C9E300D071CD /* DALabeledCircularProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DALabeledCircularProgressView.m; sourceTree = ""; }; 4A2C41BA1BF4CA0100D071CD /* LGRefreshView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LGRefreshView.h; sourceTree = ""; }; 4A2C41BB1BF4CA0100D071CD /* LGRefreshView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LGRefreshView.m; sourceTree = ""; }; 4A45A9C71A98AE2A00AC75D0 /* RefreshTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RefreshTableViewController.h; sourceTree = ""; }; 4A45A9C81A98AE2A00AC75D0 /* RefreshTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RefreshTableViewController.m; sourceTree = ""; }; 4A4783A11A99D6560058F504 /* RefreshCollectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RefreshCollectionViewController.h; sourceTree = ""; }; 4A4783A21A99D6560058F504 /* RefreshCollectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RefreshCollectionViewController.m; sourceTree = ""; }; 4ADC01F41AC2E1E900F40A74 /* RefreshScrollViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RefreshScrollViewController.h; sourceTree = ""; }; 4ADC01F51AC2E1E900F40A74 /* RefreshScrollViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RefreshScrollViewController.m; sourceTree = ""; }; 841015B31A94CA2B0004B53B /* LGRefreshViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LGRefreshViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 841015B71A94CA2B0004B53B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 841015B81A94CA2B0004B53B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 841015BA1A94CA2B0004B53B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 841015BB1A94CA2B0004B53B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 841015BD1A94CA2B0004B53B /* TableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TableViewController.h; sourceTree = ""; }; 841015BE1A94CA2B0004B53B /* TableViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TableViewController.m; sourceTree = ""; }; 841015C31A94CA2B0004B53B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 841015DC1A94CAEA0004B53B /* NavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NavigationController.h; sourceTree = ""; }; 841015DD1A94CAEA0004B53B /* NavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NavigationController.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 841015B01A94CA2B0004B53B /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 4A2C41B21BF4C9E300D071CD /* DACircularProgress */ = { isa = PBXGroup; children = ( 4A2C41B31BF4C9E300D071CD /* DACircularProgressView.h */, 4A2C41B41BF4C9E300D071CD /* DACircularProgressView.m */, 4A2C41B51BF4C9E300D071CD /* DALabeledCircularProgressView.h */, 4A2C41B61BF4C9E300D071CD /* DALabeledCircularProgressView.m */, ); name = DACircularProgress; path = LGRefreshViewDemo/DACircularProgress; sourceTree = ""; }; 4A2C41B91BF4CA0100D071CD /* LGRefreshView */ = { isa = PBXGroup; children = ( 4A2C41BA1BF4CA0100D071CD /* LGRefreshView.h */, 4A2C41BB1BF4CA0100D071CD /* LGRefreshView.m */, ); name = LGRefreshView; path = ../LGRefreshView; sourceTree = ""; }; 841015AA1A94CA2B0004B53B = { isa = PBXGroup; children = ( 4A2C41B91BF4CA0100D071CD /* LGRefreshView */, 841015B51A94CA2B0004B53B /* LGRefreshViewDemo */, 841015B41A94CA2B0004B53B /* Products */, FE1F170CEC0E67195649D7BB /* Frameworks */, ); sourceTree = ""; }; 841015B41A94CA2B0004B53B /* Products */ = { isa = PBXGroup; children = ( 841015B31A94CA2B0004B53B /* LGRefreshViewDemo.app */, ); name = Products; sourceTree = ""; }; 841015B51A94CA2B0004B53B /* LGRefreshViewDemo */ = { isa = PBXGroup; children = ( 841015BA1A94CA2B0004B53B /* AppDelegate.h */, 841015BB1A94CA2B0004B53B /* AppDelegate.m */, 841015DC1A94CAEA0004B53B /* NavigationController.h */, 841015DD1A94CAEA0004B53B /* NavigationController.m */, 841015BD1A94CA2B0004B53B /* TableViewController.h */, 841015BE1A94CA2B0004B53B /* TableViewController.m */, 841E90251A95FA0500BF6E8A /* UIScrollView */, 841E90261A95FA1700BF6E8A /* UITableView */, 841E90271A95FA2000BF6E8A /* UICollectionView */, 841015C31A94CA2B0004B53B /* Images.xcassets */, 841015B61A94CA2B0004B53B /* Supporting Files */, ); path = LGRefreshViewDemo; sourceTree = ""; }; 841015B61A94CA2B0004B53B /* Supporting Files */ = { isa = PBXGroup; children = ( 841015B71A94CA2B0004B53B /* Info.plist */, 841015B81A94CA2B0004B53B /* main.m */, ); name = "Supporting Files"; sourceTree = ""; }; 841E90251A95FA0500BF6E8A /* UIScrollView */ = { isa = PBXGroup; children = ( 4ADC01F41AC2E1E900F40A74 /* RefreshScrollViewController.h */, 4ADC01F51AC2E1E900F40A74 /* RefreshScrollViewController.m */, ); name = UIScrollView; sourceTree = ""; }; 841E90261A95FA1700BF6E8A /* UITableView */ = { isa = PBXGroup; children = ( 4A45A9C71A98AE2A00AC75D0 /* RefreshTableViewController.h */, 4A45A9C81A98AE2A00AC75D0 /* RefreshTableViewController.m */, ); name = UITableView; sourceTree = ""; }; 841E90271A95FA2000BF6E8A /* UICollectionView */ = { isa = PBXGroup; children = ( 4A4783A11A99D6560058F504 /* RefreshCollectionViewController.h */, 4A4783A21A99D6560058F504 /* RefreshCollectionViewController.m */, ); name = UICollectionView; sourceTree = ""; }; FE1F170CEC0E67195649D7BB /* Frameworks */ = { isa = PBXGroup; children = ( 4A2C41B21BF4C9E300D071CD /* DACircularProgress */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 841015B21A94CA2B0004B53B /* LGRefreshViewDemo */ = { isa = PBXNativeTarget; buildConfigurationList = 841015D61A94CA2B0004B53B /* Build configuration list for PBXNativeTarget "LGRefreshViewDemo" */; buildPhases = ( 841015AF1A94CA2B0004B53B /* Sources */, 841015B01A94CA2B0004B53B /* Frameworks */, 841015B11A94CA2B0004B53B /* Resources */, ); buildRules = ( ); dependencies = ( ); name = LGRefreshViewDemo; productName = LGRefreshViewDemo; productReference = 841015B31A94CA2B0004B53B /* LGRefreshViewDemo.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 841015AB1A94CA2B0004B53B /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0710; ORGANIZATIONNAME = Demo; TargetAttributes = { 841015B21A94CA2B0004B53B = { CreatedOnToolsVersion = 6.1; }; }; }; buildConfigurationList = 841015AE1A94CA2B0004B53B /* Build configuration list for PBXProject "LGRefreshViewDemo" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 841015AA1A94CA2B0004B53B; productRefGroup = 841015B41A94CA2B0004B53B /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 841015B21A94CA2B0004B53B /* LGRefreshViewDemo */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 841015B11A94CA2B0004B53B /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 841015C41A94CA2B0004B53B /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 841015AF1A94CA2B0004B53B /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 841015BF1A94CA2B0004B53B /* TableViewController.m in Sources */, 4A2C41B81BF4C9E300D071CD /* DALabeledCircularProgressView.m in Sources */, 4A45A9C91A98AE2A00AC75D0 /* RefreshTableViewController.m in Sources */, 4A4783A31A99D6560058F504 /* RefreshCollectionViewController.m in Sources */, 4ADC01FC1AC2E1E900F40A74 /* RefreshScrollViewController.m in Sources */, 841015DE1A94CAEA0004B53B /* NavigationController.m in Sources */, 4A2C41B71BF4C9E300D071CD /* DACircularProgressView.m in Sources */, 841015BC1A94CA2B0004B53B /* AppDelegate.m in Sources */, 841015B91A94CA2B0004B53B /* main.m in Sources */, 4A2C41BC1BF4CA0100D071CD /* LGRefreshView.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ 841015D41A94CA2B0004B53B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 6.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 841015D51A94CA2B0004B53B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 6.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 841015D71A94CA2B0004B53B /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CODE_SIGN_IDENTITY = "iPhone Developer"; HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = LGRefreshViewDemo/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 6.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.test.$(PRODUCT_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 841015D81A94CA2B0004B53B /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CODE_SIGN_IDENTITY = "iPhone Developer"; HEADER_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = LGRefreshViewDemo/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 6.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.test.$(PRODUCT_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 841015AE1A94CA2B0004B53B /* Build configuration list for PBXProject "LGRefreshViewDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( 841015D41A94CA2B0004B53B /* Debug */, 841015D51A94CA2B0004B53B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 841015D61A94CA2B0004B53B /* Build configuration list for PBXNativeTarget "LGRefreshViewDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( 841015D71A94CA2B0004B53B /* Debug */, 841015D81A94CA2B0004B53B /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 841015AB1A94CA2B0004B53B /* Project object */; } ================================================ FILE: Demo/LGRefreshViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Framework/LGRefreshViewFramework/DACircularProgress/DACircularProgressView.h ================================================ // // DACircularProgressView.h // DACircularProgress // // Created by Daniel Amitay on 2/6/12. // Copyright (c) 2012 Daniel Amitay. All rights reserved. // #import @interface DACircularProgressView : UIView @property(nonatomic, strong) UIColor *trackTintColor UI_APPEARANCE_SELECTOR; @property(nonatomic, strong) UIColor *progressTintColor UI_APPEARANCE_SELECTOR; @property(nonatomic, strong) UIColor *innerTintColor UI_APPEARANCE_SELECTOR; @property(nonatomic) NSInteger roundedCorners UI_APPEARANCE_SELECTOR; // Can not use BOOL with UI_APPEARANCE_SELECTOR :-( @property(nonatomic) CGFloat thicknessRatio UI_APPEARANCE_SELECTOR; @property(nonatomic) NSInteger clockwiseProgress UI_APPEARANCE_SELECTOR; // Can not use BOOL with UI_APPEARANCE_SELECTOR :-( @property(nonatomic) CGFloat progress; @property(nonatomic) CGFloat indeterminateDuration UI_APPEARANCE_SELECTOR; @property(nonatomic) NSInteger indeterminate UI_APPEARANCE_SELECTOR; // Can not use BOOL with UI_APPEARANCE_SELECTOR :-( - (void)setProgress:(CGFloat)progress animated:(BOOL)animated; - (void)setProgress:(CGFloat)progress animated:(BOOL)animated initialDelay:(CFTimeInterval)initialDelay; - (void)setProgress:(CGFloat)progress animated:(BOOL)animated initialDelay:(CFTimeInterval)initialDelay withDuration:(CFTimeInterval)duration; @end ================================================ FILE: Framework/LGRefreshViewFramework/DACircularProgress/DACircularProgressView.m ================================================ // // DACircularProgressView.m // DACircularProgress // // Created by Daniel Amitay on 2/6/12. // Copyright (c) 2012 Daniel Amitay. All rights reserved. // #import "DACircularProgressView.h" #import @interface DACircularProgressLayer : CALayer @property(nonatomic, strong) UIColor *trackTintColor; @property(nonatomic, strong) UIColor *progressTintColor; @property(nonatomic, strong) UIColor *innerTintColor; @property(nonatomic) NSInteger roundedCorners; @property(nonatomic) CGFloat thicknessRatio; @property(nonatomic) CGFloat progress; @property(nonatomic) NSInteger clockwiseProgress; @end @implementation DACircularProgressLayer @dynamic trackTintColor; @dynamic progressTintColor; @dynamic innerTintColor; @dynamic roundedCorners; @dynamic thicknessRatio; @dynamic progress; @dynamic clockwiseProgress; + (BOOL)needsDisplayForKey:(NSString *)key { if ([key isEqualToString:@"progress"]) { return YES; } else { return [super needsDisplayForKey:key]; } } - (void)drawInContext:(CGContextRef)context { CGRect rect = self.bounds; CGPoint centerPoint = CGPointMake(rect.size.width / 2.0f, rect.size.height / 2.0f); CGFloat radius = MIN(rect.size.height, rect.size.width) / 2.0f; BOOL clockwise = (self.clockwiseProgress != 0); CGFloat progress = MIN(self.progress, 1.0f - FLT_EPSILON); CGFloat radians = 0; if (clockwise) { radians = (float)((progress * 2.0f * M_PI) - M_PI_2); } else { radians = (float)(3 * M_PI_2 - (progress * 2.0f * M_PI)); } CGContextSetFillColorWithColor(context, self.trackTintColor.CGColor); CGMutablePathRef trackPath = CGPathCreateMutable(); CGPathMoveToPoint(trackPath, NULL, centerPoint.x, centerPoint.y); CGPathAddArc(trackPath, NULL, centerPoint.x, centerPoint.y, radius, (float)(2.0f * M_PI), 0.0f, TRUE); CGPathCloseSubpath(trackPath); CGContextAddPath(context, trackPath); CGContextFillPath(context); CGPathRelease(trackPath); if (progress > 0.0f) { CGContextSetFillColorWithColor(context, self.progressTintColor.CGColor); CGMutablePathRef progressPath = CGPathCreateMutable(); CGPathMoveToPoint(progressPath, NULL, centerPoint.x, centerPoint.y); CGPathAddArc(progressPath, NULL, centerPoint.x, centerPoint.y, radius, (float)(3.0f * M_PI_2), radians, !clockwise); CGPathCloseSubpath(progressPath); CGContextAddPath(context, progressPath); CGContextFillPath(context); CGPathRelease(progressPath); } if (progress > 0.0f && self.roundedCorners) { CGFloat pathWidth = radius * self.thicknessRatio; CGFloat xOffset = radius * (1.0f + ((1.0f - (self.thicknessRatio / 2.0f)) * cosf(radians))); CGFloat yOffset = radius * (1.0f + ((1.0f - (self.thicknessRatio / 2.0f)) * sinf(radians))); CGPoint endPoint = CGPointMake(xOffset, yOffset); CGRect startEllipseRect = (CGRect) { .origin.x = centerPoint.x - pathWidth / 2.0f, .origin.y = 0.0f, .size.width = pathWidth, .size.height = pathWidth }; CGContextAddEllipseInRect(context, startEllipseRect); CGContextFillPath(context); CGRect endEllipseRect = (CGRect) { .origin.x = endPoint.x - pathWidth / 2.0f, .origin.y = endPoint.y - pathWidth / 2.0f, .size.width = pathWidth, .size.height = pathWidth }; CGContextAddEllipseInRect(context, endEllipseRect); CGContextFillPath(context); } CGContextSetBlendMode(context, kCGBlendModeClear); CGFloat innerRadius = radius * (1.0f - self.thicknessRatio); CGRect clearRect = (CGRect) { .origin.x = centerPoint.x - innerRadius, .origin.y = centerPoint.y - innerRadius, .size.width = innerRadius * 2.0f, .size.height = innerRadius * 2.0f }; CGContextAddEllipseInRect(context, clearRect); CGContextFillPath(context); if (self.innerTintColor) { CGContextSetBlendMode(context, kCGBlendModeNormal); CGContextSetFillColorWithColor(context, [self.innerTintColor CGColor]); CGContextAddEllipseInRect(context, clearRect); CGContextFillPath(context); } } @end @interface DACircularProgressView () @end @implementation DACircularProgressView + (void) initialize { if (self == [DACircularProgressView class]) { DACircularProgressView *circularProgressViewAppearance = [DACircularProgressView appearance]; [circularProgressViewAppearance setTrackTintColor:[[UIColor whiteColor] colorWithAlphaComponent:0.3f]]; [circularProgressViewAppearance setProgressTintColor:[UIColor whiteColor]]; [circularProgressViewAppearance setInnerTintColor:nil]; [circularProgressViewAppearance setBackgroundColor:[UIColor clearColor]]; [circularProgressViewAppearance setThicknessRatio:0.3f]; [circularProgressViewAppearance setRoundedCorners:NO]; [circularProgressViewAppearance setClockwiseProgress:YES]; [circularProgressViewAppearance setIndeterminateDuration:2.0f]; [circularProgressViewAppearance setIndeterminate:NO]; } } + (Class)layerClass { return [DACircularProgressLayer class]; } - (DACircularProgressLayer *)circularProgressLayer { return (DACircularProgressLayer *)self.layer; } - (id)init { return [super initWithFrame:CGRectMake(0.0f, 0.0f, 40.0f, 40.0f)]; } - (void)didMoveToWindow { [super didMoveToWindow]; CGFloat windowContentsScale = self.window.screen.scale; self.circularProgressLayer.contentsScale = windowContentsScale; [self.circularProgressLayer setNeedsDisplay]; } #pragma mark - Progress - (CGFloat)progress { return self.circularProgressLayer.progress; } - (void)setProgress:(CGFloat)progress { [self setProgress:progress animated:NO]; } - (void)setProgress:(CGFloat)progress animated:(BOOL)animated { [self setProgress:progress animated:animated initialDelay:0.0]; } - (void)setProgress:(CGFloat)progress animated:(BOOL)animated initialDelay:(CFTimeInterval)initialDelay { CGFloat pinnedProgress = MIN(MAX(progress, 0.0f), 1.0f); [self setProgress:progress animated:animated initialDelay:initialDelay withDuration:fabs(self.progress - pinnedProgress)]; } - (void)setProgress:(CGFloat)progress animated:(BOOL)animated initialDelay:(CFTimeInterval)initialDelay withDuration:(CFTimeInterval)duration { [self.layer removeAnimationForKey:@"indeterminateAnimation"]; [self.circularProgressLayer removeAnimationForKey:@"progress"]; CGFloat pinnedProgress = MIN(MAX(progress, 0.0f), 1.0f); if (animated) { CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"progress"]; animation.duration = duration; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; animation.fillMode = kCAFillModeForwards; animation.fromValue = [NSNumber numberWithFloat:self.progress]; animation.toValue = [NSNumber numberWithFloat:pinnedProgress]; animation.beginTime = CACurrentMediaTime() + initialDelay; animation.delegate = self; [self.circularProgressLayer addAnimation:animation forKey:@"progress"]; } else { [self.circularProgressLayer setNeedsDisplay]; self.circularProgressLayer.progress = pinnedProgress; } } - (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag { NSNumber *pinnedProgressNumber = [animation valueForKey:@"toValue"]; self.circularProgressLayer.progress = [pinnedProgressNumber floatValue]; } #pragma mark - UIAppearance methods - (UIColor *)trackTintColor { return self.circularProgressLayer.trackTintColor; } - (void)setTrackTintColor:(UIColor *)trackTintColor { self.circularProgressLayer.trackTintColor = trackTintColor; [self.circularProgressLayer setNeedsDisplay]; } - (UIColor *)progressTintColor { return self.circularProgressLayer.progressTintColor; } - (void)setProgressTintColor:(UIColor *)progressTintColor { self.circularProgressLayer.progressTintColor = progressTintColor; [self.circularProgressLayer setNeedsDisplay]; } - (UIColor *)innerTintColor { return self.circularProgressLayer.innerTintColor; } - (void)setInnerTintColor:(UIColor *)innerTintColor { self.circularProgressLayer.innerTintColor = innerTintColor; [self.circularProgressLayer setNeedsDisplay]; } - (NSInteger)roundedCorners { return self.roundedCorners; } - (void)setRoundedCorners:(NSInteger)roundedCorners { self.circularProgressLayer.roundedCorners = roundedCorners; [self.circularProgressLayer setNeedsDisplay]; } - (CGFloat)thicknessRatio { return self.circularProgressLayer.thicknessRatio; } - (void)setThicknessRatio:(CGFloat)thicknessRatio { self.circularProgressLayer.thicknessRatio = MIN(MAX(thicknessRatio, 0.f), 1.f); [self.circularProgressLayer setNeedsDisplay]; } - (NSInteger)indeterminate { CAAnimation *spinAnimation = [self.layer animationForKey:@"indeterminateAnimation"]; return (spinAnimation == nil ? 0 : 1); } - (void)setIndeterminate:(NSInteger)indeterminate { if (indeterminate) { if (!self.indeterminate) { CABasicAnimation *spinAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; spinAnimation.byValue = [NSNumber numberWithDouble:indeterminate > 0 ? 2.0f*M_PI : -2.0f*M_PI]; spinAnimation.duration = self.indeterminateDuration; spinAnimation.repeatCount = HUGE_VALF; [self.layer addAnimation:spinAnimation forKey:@"indeterminateAnimation"]; } } else { [self.layer removeAnimationForKey:@"indeterminateAnimation"]; } } - (NSInteger)clockwiseProgress { return self.circularProgressLayer.clockwiseProgress; } - (void)setClockwiseProgress:(NSInteger)clockwiseProgres { self.circularProgressLayer.clockwiseProgress = clockwiseProgres; [self.circularProgressLayer setNeedsDisplay]; } @end ================================================ FILE: Framework/LGRefreshViewFramework/DACircularProgress/DALabeledCircularProgressView.h ================================================ // // DALabeledCircularProgressView.h // DACircularProgressExample // // Created by Josh Sklar on 4/8/14. // Copyright (c) 2014 Shout Messenger. All rights reserved. // #import "DACircularProgressView.h" /** @class DALabeledCircularProgressView @brief Subclass of DACircularProgressView that adds a UILabel. */ @interface DALabeledCircularProgressView : DACircularProgressView /** UILabel placed right on the DACircularProgressView. */ @property (strong, nonatomic) UILabel *progressLabel; @end ================================================ FILE: Framework/LGRefreshViewFramework/DACircularProgress/DALabeledCircularProgressView.m ================================================ // // DALabeledCircularProgressView.m // DACircularProgressExample // // Created by Josh Sklar on 4/8/14. // Copyright (c) 2014 Shout Messenger. All rights reserved. // #import "DALabeledCircularProgressView.h" @implementation DALabeledCircularProgressView - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self initializeLabel]; } return self; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { [self initializeLabel]; } return self; } #pragma mark - Internal methods /** Creates and initializes -[DALabeledCircularProgressView progressLabel]. */ - (void)initializeLabel { self.progressLabel = [[UILabel alloc] initWithFrame:self.bounds]; self.progressLabel.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; self.progressLabel.textAlignment = NSTextAlignmentCenter; self.progressLabel.backgroundColor = [UIColor clearColor]; [self addSubview:self.progressLabel]; } @end ================================================ FILE: Framework/LGRefreshViewFramework/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass ================================================ FILE: Framework/LGRefreshViewFramework/LGRefreshViewFramework.h ================================================ // // LGRefreshViewFramework.h // LGRefreshViewFramework // // Created by Grigory Lutkov on 11.11.15. // Copyright © 2015 Grigory Lutkov. All rights reserved. // #import //! Project version number for LGRefreshViewFramework. FOUNDATION_EXPORT double LGRefreshViewFrameworkVersionNumber; //! Project version string for LGRefreshViewFramework. FOUNDATION_EXPORT const unsigned char LGRefreshViewFrameworkVersionString[]; #pragma mark - #import #import #import ================================================ FILE: Framework/LGRefreshViewFramework.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 4A2C41A91BF4C76D00D071CD /* DACircularProgressView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2C41A51BF4C76D00D071CD /* DACircularProgressView.h */; settings = {ATTRIBUTES = (Private, ); }; }; 4A2C41AA1BF4C76D00D071CD /* DACircularProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A2C41A61BF4C76D00D071CD /* DACircularProgressView.m */; }; 4A2C41AB1BF4C76D00D071CD /* DALabeledCircularProgressView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2C41A71BF4C76D00D071CD /* DALabeledCircularProgressView.h */; settings = {ATTRIBUTES = (Private, ); }; }; 4A2C41AC1BF4C76D00D071CD /* DALabeledCircularProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A2C41A81BF4C76D00D071CD /* DALabeledCircularProgressView.m */; }; 4A2C41B01BF4C77400D071CD /* LGRefreshView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4A2C41AE1BF4C77400D071CD /* LGRefreshView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4A2C41B11BF4C77400D071CD /* LGRefreshView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A2C41AF1BF4C77400D071CD /* LGRefreshView.m */; }; 4AF139851BF384AC0037B073 /* LGRefreshViewFramework.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AF139841BF384AC0037B073 /* LGRefreshViewFramework.h */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 4A2C41A51BF4C76D00D071CD /* DACircularProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DACircularProgressView.h; sourceTree = ""; }; 4A2C41A61BF4C76D00D071CD /* DACircularProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DACircularProgressView.m; sourceTree = ""; }; 4A2C41A71BF4C76D00D071CD /* DALabeledCircularProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DALabeledCircularProgressView.h; sourceTree = ""; }; 4A2C41A81BF4C76D00D071CD /* DALabeledCircularProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DALabeledCircularProgressView.m; sourceTree = ""; }; 4A2C41AE1BF4C77400D071CD /* LGRefreshView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LGRefreshView.h; sourceTree = ""; }; 4A2C41AF1BF4C77400D071CD /* LGRefreshView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LGRefreshView.m; sourceTree = ""; }; 4AF139811BF384AC0037B073 /* LGRefreshViewFramework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LGRefreshViewFramework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4AF139841BF384AC0037B073 /* LGRefreshViewFramework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LGRefreshViewFramework.h; sourceTree = ""; }; 4AF139861BF384AC0037B073 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 4AF1397D1BF384AC0037B073 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 4A2C41A41BF4C76D00D071CD /* DACircularProgress */ = { isa = PBXGroup; children = ( 4A2C41A51BF4C76D00D071CD /* DACircularProgressView.h */, 4A2C41A61BF4C76D00D071CD /* DACircularProgressView.m */, 4A2C41A71BF4C76D00D071CD /* DALabeledCircularProgressView.h */, 4A2C41A81BF4C76D00D071CD /* DALabeledCircularProgressView.m */, ); name = DACircularProgress; path = LGRefreshViewFramework/DACircularProgress; sourceTree = ""; }; 4A2C41AD1BF4C77400D071CD /* LGRefreshView */ = { isa = PBXGroup; children = ( 4A2C41AE1BF4C77400D071CD /* LGRefreshView.h */, 4A2C41AF1BF4C77400D071CD /* LGRefreshView.m */, ); name = LGRefreshView; path = ../LGRefreshView; sourceTree = ""; }; 4AF139771BF384AC0037B073 = { isa = PBXGroup; children = ( 4A2C41AD1BF4C77400D071CD /* LGRefreshView */, 4A2C41A41BF4C76D00D071CD /* DACircularProgress */, 4AF139831BF384AC0037B073 /* LGRefreshViewFramework */, 4AF139821BF384AC0037B073 /* Products */, ); sourceTree = ""; }; 4AF139821BF384AC0037B073 /* Products */ = { isa = PBXGroup; children = ( 4AF139811BF384AC0037B073 /* LGRefreshViewFramework.framework */, ); name = Products; sourceTree = ""; }; 4AF139831BF384AC0037B073 /* LGRefreshViewFramework */ = { isa = PBXGroup; children = ( 4AF139841BF384AC0037B073 /* LGRefreshViewFramework.h */, 4AF139861BF384AC0037B073 /* Info.plist */, ); path = LGRefreshViewFramework; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 4AF1397E1BF384AC0037B073 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 4A2C41B01BF4C77400D071CD /* LGRefreshView.h in Headers */, 4A2C41A91BF4C76D00D071CD /* DACircularProgressView.h in Headers */, 4A2C41AB1BF4C76D00D071CD /* DALabeledCircularProgressView.h in Headers */, 4AF139851BF384AC0037B073 /* LGRefreshViewFramework.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 4AF139801BF384AC0037B073 /* LGRefreshViewFramework */ = { isa = PBXNativeTarget; buildConfigurationList = 4AF139891BF384AC0037B073 /* Build configuration list for PBXNativeTarget "LGRefreshViewFramework" */; buildPhases = ( 4AF1397C1BF384AC0037B073 /* Sources */, 4AF1397D1BF384AC0037B073 /* Frameworks */, 4AF1397E1BF384AC0037B073 /* Headers */, 4AF1397F1BF384AC0037B073 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = LGRefreshViewFramework; productName = LGRefreshViewFramework; productReference = 4AF139811BF384AC0037B073 /* LGRefreshViewFramework.framework */; productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 4AF139781BF384AC0037B073 /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0710; ORGANIZATIONNAME = "Grigory Lutkov"; TargetAttributes = { 4AF139801BF384AC0037B073 = { CreatedOnToolsVersion = 7.1.1; }; }; }; buildConfigurationList = 4AF1397B1BF384AC0037B073 /* Build configuration list for PBXProject "LGRefreshViewFramework" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = 4AF139771BF384AC0037B073; productRefGroup = 4AF139821BF384AC0037B073 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 4AF139801BF384AC0037B073 /* LGRefreshViewFramework */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 4AF1397F1BF384AC0037B073 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 4AF1397C1BF384AC0037B073 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 4A2C41AA1BF4C76D00D071CD /* DACircularProgressView.m in Sources */, 4A2C41AC1BF4C76D00D071CD /* DALabeledCircularProgressView.m in Sources */, 4A2C41B11BF4C77400D071CD /* LGRefreshView.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ 4AF139871BF384AC0037B073 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; 4AF139881BF384AC0037B073 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; 4AF1398A1BF384AC0037B073 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = LGRefreshViewFramework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.Friend-LGA.LGRefreshViewFramework"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Debug; }; 4AF1398B1BF384AC0037B073 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = LGRefreshViewFramework/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.Friend-LGA.LGRefreshViewFramework"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 4AF1397B1BF384AC0037B073 /* Build configuration list for PBXProject "LGRefreshViewFramework" */ = { isa = XCConfigurationList; buildConfigurations = ( 4AF139871BF384AC0037B073 /* Debug */, 4AF139881BF384AC0037B073 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4AF139891BF384AC0037B073 /* Build configuration list for PBXNativeTarget "LGRefreshViewFramework" */ = { isa = XCConfigurationList; buildConfigurations = ( 4AF1398A1BF384AC0037B073 /* Debug */, 4AF1398B1BF384AC0037B073 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 4AF139781BF384AC0037B073 /* Project object */; } ================================================ FILE: Framework/LGRefreshViewFramework.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Framework/LGRefreshViewFramework.xcodeproj/xcshareddata/xcschemes/LGRefreshViewFramework.xcscheme ================================================ ================================================ FILE: LGRefreshView/LGRefreshView.h ================================================ // // LGRefreshView.h // LGRefreshView // // // The MIT License (MIT) // // Copyright (c) 2015 Grigory Lutkov // (https://github.com/Friend-LGA/LGRefreshView) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // #import @class LGRefreshView; static NSString *const kLGRefreshViewBeginRefreshingNotification = @"LGRefreshViewBeginRefreshingNotification"; static NSString *const kLGRefreshViewEndRefreshingNotification = @"LGRefreshViewEndRefreshingNotification"; @protocol LGRefreshViewDelegate @required - (void)refreshViewRefreshing:(LGRefreshView *)refreshView; @end @interface LGRefreshView : UIView @property (assign, nonatomic, readonly, getter=isRefreshing) BOOL refreshing; @property (assign, nonatomic, getter=isEnabled) BOOL enabled; @property (strong, nonatomic) UIColor *tintColor; @property (assign, nonatomic) CGFloat offsetY; @property (assign, nonatomic) UIView *loadingView; /** Do not forget about weak referens to self */ @property (strong, nonatomic) void (^refreshHandler)(LGRefreshView *refreshView); @property (assign, nonatomic) id delegate; - (instancetype)initWithScrollView:(UIScrollView *)scrollView; + (instancetype)refreshViewWithScrollView:(UIScrollView *)scrollView; #pragma mark - /** Do not forget about weak referens to self for refreshHandler block */ - (instancetype)initWithScrollView:(UIScrollView *)scrollView refreshHandler:(void(^)(LGRefreshView *refreshView))refreshHandler; /** Do not forget about weak referens to self for refreshHandler block */ + (instancetype)refreshViewWithScrollView:(UIScrollView *)scrollView refreshHandler:(void(^)(LGRefreshView *refreshView))refreshHandler; #pragma mark - - (instancetype)initWithScrollView:(UIScrollView *)scrollView delegate:(id)delegate; + (instancetype)refreshViewWithScrollView:(UIScrollView *)scrollView delegate:(id)delegate; #pragma mark - + (void)setTintColor:(UIColor *)tintColor; + (void)setLoadingView:(UIView *)view; /** Needs to be called when refreshing is ended */ - (void)endRefreshing; /** Force refreshing programmatically */ - (void)triggerAnimated:(BOOL)animated; #pragma mark - /** Unavailable, use +refreshViewWithScrollView... instead */ + (instancetype)new __attribute__((unavailable("use +refreshViewWithScrollView... instead"))); /** Unavailable, use -initWithScrollView... instead */ - (instancetype)init __attribute__((unavailable("use -initWithScrollView... instead"))); /** Unavailable, use -initWithScrollView... instead */ - (instancetype)initWithFrame:(CGRect)frame __attribute__((unavailable("use -initWithScrollView... instead"))); @end ================================================ FILE: LGRefreshView/LGRefreshView.m ================================================ // // LGRefreshView.m // LGRefreshView // // // The MIT License (MIT) // // Copyright (c) 2015 Grigory Lutkov // (https://github.com/Friend-LGA/LGRefreshView) // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // #import "LGRefreshView.h" #import "DACircularProgressView.h" #define kLGRefreshViewMainScreenSideMax MAX(UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height) #define kLGRefreshViewDeviceIsOld (NSProcessInfo.processInfo.activeProcessorCount < 2) #define kLGRefreshViewDegreesToRadians(d) ((d) * M_PI / 180) #define kLGRefreshViewCircleOutMaxProgress (_loadingView ? 1.f : 0.93) #define kLGRefreshViewCircleInMaxProgress (_loadingView ? 1.f : 0.9) #define kLGRefreshViewHeight 64.f #define kLGRefreshViewCircleOutSize (kLGRefreshViewHeight * 0.5) #define kLGRefreshViewCircleInSize (kLGRefreshViewHeight * 0.3) #define kLGRefreshViewCircleOutThicknessRatio 0.2 #define kLGRefreshViewCircleInThicknessRatio 0.25 static UIView *kLGRefreshViewLoadingView; static UIColor *kLGRefreshViewTintColor; @interface LGRefreshView () @property (assign, nonatomic, getter=isObserversAdded) BOOL observersAdded; @property (assign, nonatomic, getter=isRefreshing) BOOL refreshing; @property (assign, nonatomic, getter=isIgnoreInset) BOOL ignoreInset; @property (assign, nonatomic, getter=isIgnoreOffset) BOOL ignoreOffset; @property (assign, nonatomic, getter=isTransformed) BOOL transformed; @property (assign, nonatomic, getter=isTriggered) BOOL triggered; @property (assign, nonatomic) UIScrollView *scrollView; @property (strong, nonatomic) UIView *backgroundView; @property (strong, nonatomic) DACircularProgressView *circleViewOut; @property (strong, nonatomic) DACircularProgressView *circleViewIn; @property (assign, nonatomic) UIEdgeInsets originalContentInset; /** 0.0 - 1.0 */ @property (assign, nonatomic) CGFloat timeOffset; @property (strong, nonatomic) NSDate *beginUpdatingDate; @end @implementation LGRefreshView - (instancetype)initWithScrollView:(UIScrollView *)scrollView { self = [super init]; if (self) { _enabled = YES; _tintColor = (kLGRefreshViewTintColor ? kLGRefreshViewTintColor : [UIColor colorWithRed:0.f green:0.5 blue:1.0 alpha:1.f]); _scrollView = scrollView; _originalContentInset = _scrollView.contentInset; [super setBackgroundColor:[UIColor clearColor]]; _circleViewOut = [DACircularProgressView new]; _circleViewOut.backgroundColor = [UIColor clearColor]; _circleViewOut.trackTintColor = [UIColor clearColor]; _circleViewOut.progressTintColor = _tintColor; _circleViewOut.roundedCorners = 3; [_circleViewOut setProgress:0.f animated:NO]; _circleViewOut.alpha = 0.f; _circleViewOut.layer.anchorPoint = CGPointMake(0.5, 0.5); _circleViewOut.thicknessRatio = kLGRefreshViewCircleOutThicknessRatio; [self addSubview:_circleViewOut]; _circleViewIn = [DACircularProgressView new]; _circleViewIn.backgroundColor = [UIColor clearColor]; _circleViewIn.trackTintColor = [UIColor clearColor]; _circleViewIn.progressTintColor = _tintColor; _circleViewIn.roundedCorners = 3; [_circleViewIn setProgress:0.f animated:NO]; _circleViewIn.alpha = 0.f; _circleViewIn.layer.anchorPoint = CGPointMake(0.5, 0.5); _circleViewIn.transform = CGAffineTransformScale(_circleViewIn.transform, -1, 1); _circleViewIn.thicknessRatio = kLGRefreshViewCircleInThicknessRatio; [self addSubview:_circleViewIn]; if (kLGRefreshViewLoadingView) { _loadingView = kLGRefreshViewLoadingView; _loadingView.alpha = 0.f; [_loadingView removeFromSuperview]; [self addSubview:_loadingView]; } [_scrollView insertSubview:self atIndex:0]; [self layoutInvalidate]; } return self; } + (instancetype)refreshViewWithScrollView:(UIScrollView *)scrollView { return [[self alloc] initWithScrollView:scrollView]; } #pragma mark - - (instancetype)initWithScrollView:(UIScrollView *)scrollView refreshHandler:(void(^)(LGRefreshView *refreshView))refreshHandler; { self = [self initWithScrollView:scrollView]; if (self) { _refreshHandler = refreshHandler; } return self; } + (instancetype)refreshViewWithScrollView:(UIScrollView *)scrollView refreshHandler:(void(^)(LGRefreshView *refreshView))refreshHandler { return [[self alloc] initWithScrollView:scrollView refreshHandler:refreshHandler]; } #pragma mark - - (instancetype)initWithScrollView:(UIScrollView *)scrollView delegate:(id)delegate { self = [self initWithScrollView:scrollView]; if (self) { _delegate = delegate; } return self; } + (instancetype)refreshViewWithScrollView:(UIScrollView *)scrollView delegate:(id)delegate { return [[self alloc] initWithScrollView:scrollView delegate:delegate]; } #pragma mark - Dealloc - (void)dealloc { #if DEBUG NSLog(@"%s [Line %d]", __PRETTY_FUNCTION__, __LINE__); #endif _delegate = nil; } #pragma mark - - (void)willMoveToSuperview:(UIView *)newSuperview { [super willMoveToSuperview:newSuperview]; if (!newSuperview) [self removeObservers]; else [self addObservers]; } #pragma mark - Setters and Getters - (void)setTintColor:(UIColor *)tintColor { _tintColor = tintColor; if (_circleViewOut) _circleViewOut.progressTintColor = _tintColor; if (_circleViewIn) _circleViewIn.progressTintColor = _tintColor; } - (void)setBackgroundColor:(UIColor *)backgroundColor { if ([backgroundColor isEqual:[UIColor clearColor]]) { if (_backgroundView) { [_backgroundView removeFromSuperview]; _backgroundView = nil; } } else { if (!_backgroundView) { _backgroundView = [UIView new]; _backgroundView.backgroundColor = backgroundColor; _backgroundView.frame = CGRectMake(0.f, self.frame.size.height-kLGRefreshViewMainScreenSideMax, self.frame.size.width, kLGRefreshViewMainScreenSideMax); [self insertSubview:_backgroundView atIndex:0]; } _backgroundView.backgroundColor = backgroundColor; } } - (void)setEnabled:(BOOL)enabled { if (enabled != _enabled) { _enabled = enabled; self.hidden = !_enabled; if (_enabled) [self addObservers]; else [self removeObservers]; } } - (void)setOffsetY:(CGFloat)offsetY { if (offsetY != _offsetY) { _offsetY = offsetY; [self layoutInvalidate]; } } - (void)setLoadingView:(UIView *)loadingView { if (_loadingView) [_loadingView removeFromSuperview]; _loadingView = loadingView; if (_loadingView) { _loadingView.alpha = 0.f; [_loadingView removeFromSuperview]; [self addSubview:_loadingView]; } } + (void)setLoadingView:(UIView *)view { kLGRefreshViewLoadingView = view; if (kLGRefreshViewLoadingView) kLGRefreshViewLoadingView.alpha = 0.f; } + (void)setTintColor:(UIColor *)tintColor { kLGRefreshViewTintColor = tintColor; } #pragma mark - - (void)layoutInvalidate { if (self.superview) { CGRect selfFrame = CGRectMake(0.f, -kLGRefreshViewHeight+_offsetY, _scrollView.frame.size.width, kLGRefreshViewHeight); if ([UIScreen mainScreen].scale == 1.f) selfFrame = CGRectIntegral(selfFrame); self.frame = selfFrame; if (_backgroundView) _backgroundView.frame = CGRectMake(0.f, self.frame.size.height-kLGRefreshViewMainScreenSideMax, self.frame.size.width, kLGRefreshViewMainScreenSideMax); CGRect circleFrame = CGRectMake((self.frame.size.width-kLGRefreshViewCircleOutSize)/2, (self.frame.size.height-kLGRefreshViewCircleOutSize)/2, kLGRefreshViewCircleOutSize, kLGRefreshViewCircleOutSize); if ([UIScreen mainScreen].scale == 1.f) circleFrame = CGRectIntegral(circleFrame); _circleViewOut.frame = circleFrame; circleFrame = CGRectMake((self.frame.size.width-kLGRefreshViewCircleInSize)/2, (self.frame.size.height-kLGRefreshViewCircleInSize)/2, kLGRefreshViewCircleInSize, kLGRefreshViewCircleInSize); if ([UIScreen mainScreen].scale == 1.f) circleFrame = CGRectIntegral(circleFrame); _circleViewIn.frame = circleFrame; if (_loadingView) _loadingView.center = CGPointMake(self.frame.size.width/2.f, self.frame.size.height/2.f); } } - (CGSize)sizeThatFits:(CGSize)size { return CGSizeMake(size.width, kLGRefreshViewHeight); } - (void)restoreDefaultState { [_circleViewOut.layer removeAllAnimations]; _circleViewOut.transform = CGAffineTransformIdentity; _circleViewOut.alpha = 0.f; [_circleViewOut setProgress:0.f animated:NO]; [_circleViewIn.layer removeAllAnimations]; _circleViewIn.transform = CGAffineTransformIdentity; _circleViewIn.transform = CGAffineTransformScale(_circleViewIn.transform, -1, 1); _circleViewIn.alpha = 0.f; [_circleViewIn setProgress:0.f animated:NO]; [_loadingView.layer removeAllAnimations]; _loadingView.alpha = 0.f; _transformed = NO; [self layoutInvalidate]; } - (void)triggerAnimated:(BOOL)animated { if (!self.isTriggered && !self.isRefreshing) { _triggered = YES; _scrollView.scrollEnabled = YES; _scrollView.userInteractionEnabled = YES; [self restoreDefaultState]; [_circleViewOut setProgress:kLGRefreshViewCircleOutMaxProgress animated:NO]; [_circleViewIn setProgress:kLGRefreshViewCircleInMaxProgress animated:NO]; if (!_loadingView) [self runSpinAnimation]; if (animated) { [LGRefreshView animateStandardWithAnimations:^(void) { [self triggerAnimations]; } completion:^(BOOL finished) { [self triggerCompletion]; }]; } else { [self triggerAnimations]; [self triggerCompletion]; } } } - (void)triggerAnimations { if (_loadingView) { if (![_loadingView.superview isEqual:self]) { [_loadingView removeFromSuperview]; [self addSubview:_loadingView]; } _loadingView.alpha = 1.f; _circleViewOut.alpha = 0.f; _circleViewIn.alpha = 0.f; _loadingView.center = CGPointMake(self.frame.size.width/2.f, self.frame.size.height/2.f); } else { _circleViewOut.alpha = 1.f; _circleViewIn.alpha = 1.f; } _circleViewOut.center = CGPointMake(self.frame.size.width/2.f, self.frame.size.height/2.f); _circleViewIn.center = CGPointMake(self.frame.size.width/2.f, self.frame.size.height/2.f); _ignoreInset = YES; _ignoreOffset = YES; [_scrollView setContentInset:UIEdgeInsetsMake(self.frame.size.height+_originalContentInset.top, _originalContentInset.left, _originalContentInset.bottom, _originalContentInset.right)]; _ignoreInset = NO; _ignoreOffset = NO; } - (void)triggerCompletion { [self beginRefreshing]; } #pragma mark - Observers - (void)addObservers { if (!self.isObserversAdded && _scrollView) { _observersAdded = YES; _originalContentInset = _scrollView.contentInset; [_scrollView addObserver:self forKeyPath:@"contentInset" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionPrior context:nil]; [_scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil]; [_scrollView addObserver:self forKeyPath:@"bounds" options:NSKeyValueObservingOptionNew context:nil]; } } - (void)removeObservers { if (self.isObserversAdded && _scrollView) { _observersAdded = NO; [_scrollView removeObserver:self forKeyPath:@"contentInset"]; [_scrollView removeObserver:self forKeyPath:@"contentOffset"]; [_scrollView removeObserver:self forKeyPath:@"bounds"]; } } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"bounds"]) { if (self.bounds.size.width != _scrollView.bounds.size.width) { [self layoutInvalidate]; if (self.isRefreshing) { [self removeFromSuperview]; [self restoreDefaultState]; UIEdgeInsets contentInset = _scrollView.contentInset; contentInset.top -= self.bounds.size.height; _scrollView.contentInset = contentInset; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void) { if (!self.superview) { _refreshing = NO; _triggered = NO; [_scrollView insertSubview:self atIndex:0]; [self layoutInvalidate]; _scrollView.scrollEnabled = YES; _scrollView.userInteractionEnabled = YES; } }); } } } else if ([keyPath isEqualToString:@"contentInset"]) { if (self.isIgnoreInset) return; UIEdgeInsets newInset = [[change valueForKey:NSKeyValueChangeNewKey] UIEdgeInsetsValue]; _originalContentInset = newInset; } else if ([keyPath isEqualToString:@"contentOffset"]) { if (self.isIgnoreOffset) return; BOOL isTrackingAndDragging = (_scrollView.isTracking && _scrollView.isDragging); CGPoint newOffset = [[change valueForKey:NSKeyValueChangeNewKey] CGPointValue]; CGFloat offsetY = newOffset.y + _originalContentInset.top; // Set position of refreshView subviews if (offsetY < 0.f) { CGFloat tempOffsetY = offsetY+self.frame.size.height/2; CGFloat progress = (tempOffsetY >= 0.f ? 0.f : -tempOffsetY/self.frame.size.height) * 2; // ----- if (!self.isRefreshing) { _circleViewOut.alpha = progress * 2; _circleViewIn.alpha = progress * 2; } // ----- BOOL isCanTransform = YES; if (!kLGRefreshViewDeviceIsOld) { CGFloat scale = progress + 0.5; if (!self.isTransformed && (scale <= 1.f || !CGSizeEqualToSize(_circleViewOut.frame.size, CGSizeMake(kLGRefreshViewCircleOutSize, kLGRefreshViewCircleOutSize)))) { isCanTransform = NO; if (scale > 1.f) scale = 1.f; CGFloat circleOutSize = kLGRefreshViewCircleOutSize * scale; _circleViewOut.frame = CGRectMake((self.frame.size.width-circleOutSize)/2, self.frame.size.height-circleOutSize/2+offsetY/2, circleOutSize, circleOutSize); CGFloat circleInSize = kLGRefreshViewCircleInSize * scale; _circleViewIn.frame = CGRectMake((self.frame.size.width-circleInSize)/2, self.frame.size.height-circleInSize/2+offsetY/2, circleInSize, circleInSize); } else { _circleViewOut.center = CGPointMake(self.frame.size.width/2, self.frame.size.height+offsetY/2); _circleViewIn.center = CGPointMake(self.frame.size.width/2, self.frame.size.height+offsetY/2); if (_loadingView) _loadingView.center = CGPointMake(self.frame.size.width/2, self.frame.size.height+offsetY/2); } } else { _circleViewOut.center = CGPointMake(self.frame.size.width/2, self.frame.size.height+offsetY/2); _circleViewIn.center = CGPointMake(self.frame.size.width/2, self.frame.size.height+offsetY/2); if (_loadingView) _loadingView.center = CGPointMake(self.frame.size.width/2, self.frame.size.height+offsetY/2); } // ----- if (!self.isRefreshing && isTrackingAndDragging) { if (isCanTransform) { if (progress > 1.f) { CGFloat angle = progress-1.f; angle = kLGRefreshViewDegreesToRadians(angle); angle *= 150; _circleViewOut.transform = CGAffineTransformIdentity; _circleViewOut.transform = CGAffineTransformRotate(_circleViewOut.transform, angle); _circleViewIn.transform = CGAffineTransformIdentity; _circleViewIn.transform = CGAffineTransformScale(_circleViewIn.transform, -1, 1); _circleViewIn.transform = CGAffineTransformRotate(_circleViewIn.transform, angle); _transformed = YES; } else if (self.isTransformed) { _circleViewOut.transform = CGAffineTransformIdentity; _circleViewIn.transform = CGAffineTransformIdentity; _circleViewIn.transform = CGAffineTransformScale(_circleViewIn.transform, -1, 1); _transformed = NO; } } // ----- if (progress > 1.f) progress = 1.f; [_circleViewOut setProgress:progress*kLGRefreshViewCircleOutMaxProgress animated:NO]; [_circleViewIn setProgress:progress*kLGRefreshViewCircleInMaxProgress animated:NO]; } } if (self.isRefreshing) { // Set the inset depending on the situation if (!isTrackingAndDragging && offsetY < 0 && offsetY >= -self.frame.size.height) { _ignoreInset = YES; _ignoreOffset = YES; [_scrollView setContentInset:UIEdgeInsetsMake(self.frame.size.height+_originalContentInset.top, _originalContentInset.left, _originalContentInset.bottom, _originalContentInset.right)]; _ignoreInset = NO; _ignoreOffset = NO; } } else { // Start refreshing if (!isTrackingAndDragging && _circleViewOut.progress >= kLGRefreshViewCircleOutMaxProgress && offsetY <= -self.frame.size.height) [self beginRefreshing]; } } else [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; } #pragma mark - Animations - (void)showLoadingView:(BOOL)animated { if (![_loadingView.superview isEqual:self]) { [_loadingView removeFromSuperview]; [self addSubview:_loadingView]; } if (animated) { NSTimeInterval duration = 0.2; CABasicAnimation *animation; animation = [CABasicAnimation animationWithKeyPath:@"opacity"]; animation.duration = duration; animation.fromValue = [NSNumber numberWithFloat:1.f]; animation.removedOnCompletion = NO; _circleViewIn.layer.opacity = 0.f; [_circleViewIn.layer addAnimation:animation forKey:@"opacityAnimation"]; _circleViewOut.layer.opacity = 0.f; [_circleViewOut.layer addAnimation:animation forKey:@"opacityAnimation"]; [UIView animateWithDuration:duration animations:^{ _loadingView.alpha = 1.f; }]; } else { _circleViewIn.alpha = 0.f; _circleViewOut.alpha = 0.f; _loadingView.alpha = 1.f; } } - (void)runSpinAnimation { if (![_circleViewOut.layer.animationKeys containsObject:@"rotationAnimation"]) { CGFloat multiplier = 1000000.f; NSTimeInterval duration = 0.7 * multiplier; CGFloat rotations = 1.f * multiplier; float value = (M_PI * 2.0 * rotations); CABasicAnimation *rotationAnimation; rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; rotationAnimation.duration = duration; rotationAnimation.cumulative = YES; rotationAnimation.repeatCount = 1; rotationAnimation.toValue = [NSNumber numberWithFloat:value]; [_circleViewOut.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"]; rotationAnimation.toValue = [NSNumber numberWithFloat:-value]; [_circleViewIn.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"]; } } - (void)beginRefreshing { if (!self.isRefreshing) { _refreshing = YES; _scrollView.scrollEnabled = NO; _scrollView.userInteractionEnabled = NO; if (_loadingView && !_loadingView.alpha) [self showLoadingView:YES]; else [self runSpinAnimation]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void) { _beginUpdatingDate = [NSDate date]; // ----- [[NSNotificationCenter defaultCenter] postNotificationName:kLGRefreshViewBeginRefreshingNotification object:self userInfo:nil]; if (_refreshHandler) _refreshHandler(self); if (_delegate && [_delegate respondsToSelector:@selector(refreshViewRefreshing:)]) [_delegate refreshViewRefreshing:self]; }); } } - (void)endRefreshing { if (self.isRefreshing) { NSDate *endUpdatingDate = [NSDate date]; NSTimeInterval interval = [endUpdatingDate timeIntervalSinceDate:_beginUpdatingDate]; NSTimeInterval minimum = 1.5; if (interval < minimum) { NSTimeInterval after = minimum-interval; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(after * NSEC_PER_SEC)), dispatch_get_main_queue(), ^(void) { [self endRefreshing2]; }); } else [self endRefreshing2]; } } - (void)endRefreshing2 { if (self.superview) { [LGRefreshView animateStandardWithAnimations:^(void) { [self endRefreshing2Animation]; } completion:^(BOOL finished) { [self endRefreshing2Completion]; }]; } } - (void)endRefreshing2Animation { if (self.superview) { _circleViewOut.alpha = 0.f; _circleViewIn.alpha = 0.f; if (_loadingView && [_loadingView.superview isEqual:self]) _loadingView.alpha = 0.f; _ignoreInset = YES; [_scrollView setContentInset:_originalContentInset]; _ignoreInset = NO; } } - (void)endRefreshing2Completion { if (self.superview) { [self restoreDefaultState]; _refreshing = NO; _triggered = NO; _scrollView.scrollEnabled = YES; _scrollView.userInteractionEnabled = YES; // ----- [[NSNotificationCenter defaultCenter] postNotificationName:kLGRefreshViewEndRefreshingNotification object:self userInfo:nil]; } } #pragma mark - Support + (void)animateStandardWithAnimations:(void(^)())animations completion:(void(^)(BOOL finished))completion { if ([UIDevice currentDevice].systemVersion.floatValue >= 7.0) { [UIView animateWithDuration:0.5 delay:0.0 usingSpringWithDamping:1.f initialSpringVelocity:0.5 options:0 animations:animations completion:completion]; } else { [UIView animateWithDuration:0.5*0.66 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:animations completion:completion]; } } @end ================================================ FILE: LGRefreshView.podspec ================================================ Pod::Spec.new do |s| s.name = 'LGRefreshView' s.version = '1.0.5' s.platform = :ios, '6.0' s.license = 'MIT' s.homepage = 'https://github.com/Friend-LGA/LGRefreshView' s.author = { 'Grigory Lutkov' => 'Friend.LGA@gmail.com' } s.source = { :git => 'https://github.com/Friend-LGA/LGRefreshView.git', :tag => s.version } s.summary = 'iOS pull to refresh for UIScrollView, UITableView and UICollectionView' s.requires_arc = true s.source_files = 'LGRefreshView/*.{h,m}' s.dependency 'DACircularProgress', '~> 2.3.0' end ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 Grigory Lutkov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # LGRefreshView iOS pull to refresh for UIScrollView, UITableView and UICollectionView. ## Preview ## Installation ### With source code - [Download repository](https://github.com/Friend-LGA/LGRefreshView/archive/master.zip), then add [LGRefreshView directory](https://github.com/Friend-LGA/LGRefreshView/blob/master/LGRefreshView/) to your project. - Also you need to install [DACircularProgress](https://github.com/danielamitay/DACircularProgress) library. ### With CocoaPods CocoaPods is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries in your projects. To install with cocoaPods, follow the "Get Started" section on [CocoaPods](https://cocoapods.org/). #### Podfile ```ruby platform :ios, '6.0' pod 'LGRefreshView', '~> 1.0.0' ``` ### With Carthage Carthage is a lightweight dependency manager for Swift and Objective-C. It leverages CocoaTouch modules and is less invasive than CocoaPods. To install with carthage, follow the instruction on [Carthage](https://github.com/Carthage/Carthage/). #### Cartfile ``` github "Friend-LGA/LGRefreshView" ~> 1.0.0 ``` ## Usage In the source files where you need to use the library, import the header file: ```objective-c #import "LGRefreshView.h" ``` ### Initialization You have several methods for initialization: ```objective-c - (instancetype)initWithScrollView:(UIScrollView *)scrollView; // also you can pass UITableView and UICollectionView, becose its subclasses of UIScrollView ``` More init methods you can find in [LGRefreshView.h](https://github.com/Friend-LGA/LGRefreshView/blob/master/LGRefreshView/LGRefreshView.h) ### Handle actions To handle actions you can use initialization methods with blocks or delegate, or implement it after initialization. #### Delegate ```objective-c @property (assign, nonatomic) id delegate; - (void)refreshViewRefreshing:(LGRefreshView *)refreshView; ``` #### Blocks ```objective-c @property (strong, nonatomic) void (^refreshHandler)(LGRefreshView *refreshView); ``` #### Notifications Here is also some notifications, that you can add to NSNotificationsCenter: ```objective-c kLGRefreshViewBeginRefreshingNotification; kLGRefreshViewEndRefreshingNotification; ``` ### More For more details try Xcode [Demo project](https://github.com/Friend-LGA/LGRefreshView/blob/master/Demo) and see [LGRefreshView.h](https://github.com/Friend-LGA/LGRefreshView/blob/master/LGRefreshView/LGRefreshView.h) ## License LGRefreshView is released under the MIT license. See [LICENSE](https://raw.githubusercontent.com/Friend-LGA/LGRefreshView/master/LICENSE) for details.