├── .gitignore ├── Classes ├── DemoTableViewController.h ├── DemoTableViewController.m ├── PullRefreshTableViewController.h ├── PullRefreshTableViewController.m ├── PullToRefreshAppDelegate.h └── PullToRefreshAppDelegate.m ├── LICENSE ├── PullToRefresh-Info.plist ├── PullToRefresh.xcodeproj └── project.pbxproj ├── PullToRefresh_Prefix.pch ├── README.markdown ├── arrow.png └── main.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | build/* 3 | *.pbxuser 4 | !default.pbxuser 5 | *.mode1v3 6 | !default.mode1v3 7 | *.mode2v3 8 | !default.mode2v3 9 | *.perspectivev3 10 | !default.perspectivev3 11 | *.xcworkspace 12 | !default.xcworkspace 13 | xcuserdata 14 | profile 15 | *.moved-aside 16 | -------------------------------------------------------------------------------- /Classes/DemoTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.h 3 | // PullToRefresh 4 | // 5 | // Created by Leah Culver on 7/25/10. 6 | // Copyright Plancast 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PullRefreshTableViewController.h" 11 | 12 | @interface DemoTableViewController : PullRefreshTableViewController { 13 | NSMutableArray *items; 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Classes/DemoTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.m 3 | // PullToRefresh 4 | // 5 | // Created by Leah Culver on 7/25/10. 6 | // Copyright Plancast 2010. All rights reserved. 7 | // 8 | 9 | #import "DemoTableViewController.h" 10 | 11 | 12 | @implementation DemoTableViewController 13 | 14 | - (void)viewDidLoad { 15 | [super viewDidLoad]; 16 | 17 | self.title = @"Pull to Refresh"; 18 | items = [[NSMutableArray alloc] initWithObjects:@"What time is it?", nil]; 19 | } 20 | 21 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 22 | return 1; 23 | } 24 | 25 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 26 | return [items count]; 27 | } 28 | 29 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 30 | 31 | static NSString *CellIdentifier = @"CellIdentifier"; 32 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 33 | if (cell == nil) { 34 | cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 35 | } 36 | 37 | cell.textLabel.text = [items objectAtIndex:indexPath.row]; 38 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 39 | 40 | return cell; 41 | } 42 | 43 | - (void)refresh { 44 | [self performSelector:@selector(addItem) withObject:nil afterDelay:2.0]; 45 | } 46 | 47 | - (void)addItem { 48 | // Add a new time 49 | NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; 50 | [dateFormatter setTimeStyle:NSDateFormatterMediumStyle]; 51 | NSString *now = [dateFormatter stringFromDate:[NSDate date]]; 52 | [items insertObject:[NSString stringWithFormat:@"%@", now] atIndex:0]; 53 | 54 | [self.tableView reloadData]; 55 | 56 | [self stopLoading]; 57 | } 58 | 59 | - (void)dealloc { 60 | [items release]; 61 | [super dealloc]; 62 | } 63 | 64 | @end 65 | 66 | -------------------------------------------------------------------------------- /Classes/PullRefreshTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PullRefreshTableViewController.h 3 | // Plancast 4 | // 5 | // Created by Leah Culver on 7/2/10. 6 | // Copyright (c) 2010 Leah Culver 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import 31 | 32 | 33 | @interface PullRefreshTableViewController : UITableViewController { 34 | UIView *refreshHeaderView; 35 | UILabel *refreshLabel; 36 | UIImageView *refreshArrow; 37 | UIActivityIndicatorView *refreshSpinner; 38 | BOOL isDragging; 39 | BOOL isLoading; 40 | NSString *textPull; 41 | NSString *textRelease; 42 | NSString *textLoading; 43 | } 44 | 45 | @property (nonatomic, retain) UIView *refreshHeaderView; 46 | @property (nonatomic, retain) UILabel *refreshLabel; 47 | @property (nonatomic, retain) UIImageView *refreshArrow; 48 | @property (nonatomic, retain) UIActivityIndicatorView *refreshSpinner; 49 | @property (nonatomic, copy) NSString *textPull; 50 | @property (nonatomic, copy) NSString *textRelease; 51 | @property (nonatomic, copy) NSString *textLoading; 52 | 53 | - (void)setupStrings; 54 | - (void)addPullToRefreshHeader; 55 | - (void)startLoading; 56 | - (void)stopLoading; 57 | - (void)refresh; 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /Classes/PullRefreshTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PullRefreshTableViewController.m 3 | // Plancast 4 | // 5 | // Created by Leah Culver on 7/2/10. 6 | // Copyright (c) 2010 Leah Culver 7 | // 8 | // Permission is hereby granted, free of charge, to any person 9 | // obtaining a copy of this software and associated documentation 10 | // files (the "Software"), to deal in the Software without 11 | // restriction, including without limitation the rights to use, 12 | // copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the 14 | // Software is furnished to do so, subject to the following 15 | // conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be 18 | // included in all copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 22 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 24 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 25 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 26 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | // OTHER DEALINGS IN THE SOFTWARE. 28 | // 29 | 30 | #import 31 | #import "PullRefreshTableViewController.h" 32 | 33 | #define REFRESH_HEADER_HEIGHT 52.0f 34 | 35 | 36 | @implementation PullRefreshTableViewController 37 | 38 | @synthesize textPull, textRelease, textLoading, refreshHeaderView, refreshLabel, refreshArrow, refreshSpinner; 39 | 40 | - (id)initWithStyle:(UITableViewStyle)style { 41 | self = [super initWithStyle:style]; 42 | if (self != nil) { 43 | [self setupStrings]; 44 | } 45 | return self; 46 | } 47 | 48 | - (id)initWithCoder:(NSCoder *)aDecoder { 49 | self = [super initWithCoder:aDecoder]; 50 | if (self != nil) { 51 | [self setupStrings]; 52 | } 53 | return self; 54 | } 55 | 56 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { 57 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 58 | if (self != nil) { 59 | [self setupStrings]; 60 | } 61 | return self; 62 | } 63 | 64 | - (void)viewDidLoad { 65 | [super viewDidLoad]; 66 | [self addPullToRefreshHeader]; 67 | } 68 | 69 | - (void)setupStrings{ 70 | textPull = [[NSString alloc] initWithString:@"Pull down to refresh..."]; 71 | textRelease = [[NSString alloc] initWithString:@"Release to refresh..."]; 72 | textLoading = [[NSString alloc] initWithString:@"Loading..."]; 73 | } 74 | 75 | - (void)addPullToRefreshHeader { 76 | refreshHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0 - REFRESH_HEADER_HEIGHT, 320, REFRESH_HEADER_HEIGHT)]; 77 | refreshHeaderView.backgroundColor = [UIColor clearColor]; 78 | 79 | refreshLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, REFRESH_HEADER_HEIGHT)]; 80 | refreshLabel.backgroundColor = [UIColor clearColor]; 81 | refreshLabel.font = [UIFont boldSystemFontOfSize:12.0]; 82 | refreshLabel.textAlignment = NSTextAlignmentCenter; 83 | 84 | refreshArrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"arrow.png"]]; 85 | refreshArrow.frame = CGRectMake(floorf((REFRESH_HEADER_HEIGHT - 27) / 2), 86 | (floorf(REFRESH_HEADER_HEIGHT - 44) / 2), 87 | 27, 44); 88 | 89 | refreshSpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 90 | refreshSpinner.frame = CGRectMake(floorf(floorf(REFRESH_HEADER_HEIGHT - 20) / 2), floorf((REFRESH_HEADER_HEIGHT - 20) / 2), 20, 20); 91 | refreshSpinner.hidesWhenStopped = YES; 92 | 93 | [refreshHeaderView addSubview:refreshLabel]; 94 | [refreshHeaderView addSubview:refreshArrow]; 95 | [refreshHeaderView addSubview:refreshSpinner]; 96 | [self.tableView addSubview:refreshHeaderView]; 97 | } 98 | 99 | - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { 100 | if (isLoading) return; 101 | isDragging = YES; 102 | } 103 | 104 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 105 | if (isLoading) { 106 | // Update the content inset, good for section headers 107 | if (scrollView.contentOffset.y > 0) 108 | self.tableView.contentInset = UIEdgeInsetsZero; 109 | else if (scrollView.contentOffset.y >= -REFRESH_HEADER_HEIGHT) 110 | self.tableView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0); 111 | } else if (isDragging && scrollView.contentOffset.y < 0) { 112 | // Update the arrow direction and label 113 | [UIView animateWithDuration:0.25 animations:^{ 114 | if (scrollView.contentOffset.y < -REFRESH_HEADER_HEIGHT) { 115 | // User is scrolling above the header 116 | refreshLabel.text = self.textRelease; 117 | [refreshArrow layer].transform = CATransform3DMakeRotation(M_PI, 0, 0, 1); 118 | } else { 119 | // User is scrolling somewhere within the header 120 | refreshLabel.text = self.textPull; 121 | [refreshArrow layer].transform = CATransform3DMakeRotation(M_PI * 2, 0, 0, 1); 122 | } 123 | }]; 124 | } 125 | } 126 | 127 | - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { 128 | if (isLoading) return; 129 | isDragging = NO; 130 | if (scrollView.contentOffset.y <= -REFRESH_HEADER_HEIGHT) { 131 | // Released above the header 132 | [self startLoading]; 133 | } 134 | } 135 | 136 | - (void)startLoading { 137 | isLoading = YES; 138 | 139 | // Show the header 140 | [UIView animateWithDuration:0.3 animations:^{ 141 | self.tableView.contentInset = UIEdgeInsetsMake(REFRESH_HEADER_HEIGHT, 0, 0, 0); 142 | refreshLabel.text = self.textLoading; 143 | refreshArrow.hidden = YES; 144 | [refreshSpinner startAnimating]; 145 | }]; 146 | 147 | // Refresh action! 148 | [self refresh]; 149 | } 150 | 151 | - (void)stopLoading { 152 | isLoading = NO; 153 | 154 | // Hide the header 155 | [UIView animateWithDuration:0.3 animations:^{ 156 | self.tableView.contentInset = UIEdgeInsetsZero; 157 | [refreshArrow layer].transform = CATransform3DMakeRotation(M_PI * 2, 0, 0, 1); 158 | } 159 | completion:^(BOOL finished) { 160 | [self performSelector:@selector(stopLoadingComplete)]; 161 | }]; 162 | } 163 | 164 | - (void)stopLoadingComplete { 165 | // Reset the header 166 | refreshLabel.text = self.textPull; 167 | refreshArrow.hidden = NO; 168 | [refreshSpinner stopAnimating]; 169 | } 170 | 171 | - (void)refresh { 172 | // This is just a demo. Override this method with your custom reload action. 173 | // Don't forget to call stopLoading at the end. 174 | [self performSelector:@selector(stopLoading) withObject:nil afterDelay:2.0]; 175 | } 176 | 177 | - (void)dealloc { 178 | [refreshHeaderView release]; 179 | [refreshLabel release]; 180 | [refreshArrow release]; 181 | [refreshSpinner release]; 182 | [textPull release]; 183 | [textRelease release]; 184 | [textLoading release]; 185 | [super dealloc]; 186 | } 187 | 188 | @end 189 | -------------------------------------------------------------------------------- /Classes/PullToRefreshAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // PullToRefreshAppDelegate.h 3 | // PullToRefresh 4 | // 5 | // Created by Leah Culver on 7/25/10. 6 | // Copyright Plancast 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PullToRefreshAppDelegate : NSObject { 12 | UIWindow *window; 13 | UINavigationController *navigationController; 14 | } 15 | 16 | @property (nonatomic, retain) UIWindow *window; 17 | @property (nonatomic, retain) UINavigationController *navigationController; 18 | 19 | @end 20 | 21 | -------------------------------------------------------------------------------- /Classes/PullToRefreshAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // PullToRefreshAppDelegate.m 3 | // PullToRefresh 4 | // 5 | // Created by Leah Culver on 7/25/10. 6 | // Copyright Plancast 2010. All rights reserved. 7 | // 8 | 9 | #import "PullToRefreshAppDelegate.h" 10 | #import "DemoTableViewController.h" 11 | 12 | 13 | @implementation PullToRefreshAppDelegate 14 | 15 | @synthesize window; 16 | @synthesize navigationController; 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | 21 | CGRect screenBounds = [[UIScreen mainScreen] bounds]; 22 | self.window = [[[UIWindow alloc] initWithFrame: screenBounds] autorelease]; 23 | 24 | DemoTableViewController *demoTableViewController = [[[DemoTableViewController alloc] init] autorelease]; 25 | navigationController = [[UINavigationController alloc] initWithRootViewController:demoTableViewController]; 26 | 27 | [window addSubview:navigationController.view]; 28 | [window makeKeyAndVisible]; 29 | 30 | return YES; 31 | } 32 | 33 | - (void)dealloc { 34 | [navigationController release]; 35 | [window release]; 36 | [super dealloc]; 37 | } 38 | 39 | 40 | @end 41 | 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Leah Culver 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /PullToRefresh-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | com.yourcompany.${PRODUCT_NAME:rfc1034identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /PullToRefresh.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 45; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1D3623260D0F684500981E51 /* PullToRefreshAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* PullToRefreshAppDelegate.m */; }; 11 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; 12 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 13 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; 14 | 2892E4100DC94CBA00A64D0F /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2892E40F0DC94CBA00A64D0F /* CoreGraphics.framework */; }; 15 | 28C286E10D94DF7D0034E888 /* DemoTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28C286E00D94DF7D0034E888 /* DemoTableViewController.m */; }; 16 | 4CAFBC8011FC96FC00651784 /* PullRefreshTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CAFBC7F11FC96FC00651784 /* PullRefreshTableViewController.m */; }; 17 | 4CAFBCEF11FC994F00651784 /* README.markdown in Resources */ = {isa = PBXBuildFile; fileRef = 4CAFBCEE11FC994F00651784 /* README.markdown */; }; 18 | 4CAFBD0111FC9B2100651784 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CAFBD0011FC9B2100651784 /* QuartzCore.framework */; }; 19 | 4CBE3BEE11FE21CB007696B3 /* arrow.png in Resources */ = {isa = PBXBuildFile; fileRef = 4CBE3BED11FE21CB007696B3 /* arrow.png */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 24 | 1D3623240D0F684500981E51 /* PullToRefreshAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PullToRefreshAppDelegate.h; sourceTree = ""; }; 25 | 1D3623250D0F684500981E51 /* PullToRefreshAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PullToRefreshAppDelegate.m; sourceTree = ""; }; 26 | 1D6058910D05DD3D006BFB54 /* PullToRefresh.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PullToRefresh.app; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 28 | 2892E40F0DC94CBA00A64D0F /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 29 | 28A0AAE50D9B0CCF005BE974 /* PullToRefresh_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PullToRefresh_Prefix.pch; sourceTree = ""; }; 30 | 28C286DF0D94DF7D0034E888 /* DemoTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoTableViewController.h; sourceTree = ""; }; 31 | 28C286E00D94DF7D0034E888 /* DemoTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoTableViewController.m; sourceTree = ""; }; 32 | 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 33 | 4CAFBC7E11FC96FC00651784 /* PullRefreshTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PullRefreshTableViewController.h; sourceTree = ""; }; 34 | 4CAFBC7F11FC96FC00651784 /* PullRefreshTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PullRefreshTableViewController.m; sourceTree = ""; }; 35 | 4CAFBCEE11FC994F00651784 /* README.markdown */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.markdown; sourceTree = ""; }; 36 | 4CAFBD0011FC9B2100651784 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 37 | 4CBE3BED11FE21CB007696B3 /* arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = arrow.png; sourceTree = ""; }; 38 | 8D1107310486CEB800E47090 /* PullToRefresh-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "PullToRefresh-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; 39 | /* End PBXFileReference section */ 40 | 41 | /* Begin PBXFrameworksBuildPhase section */ 42 | 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, 47 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, 48 | 2892E4100DC94CBA00A64D0F /* CoreGraphics.framework in Frameworks */, 49 | 4CAFBD0111FC9B2100651784 /* QuartzCore.framework in Frameworks */, 50 | ); 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | /* End PBXFrameworksBuildPhase section */ 54 | 55 | /* Begin PBXGroup section */ 56 | 080E96DDFE201D6D7F000001 /* Classes */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 1D3623240D0F684500981E51 /* PullToRefreshAppDelegate.h */, 60 | 1D3623250D0F684500981E51 /* PullToRefreshAppDelegate.m */, 61 | 28C286DF0D94DF7D0034E888 /* DemoTableViewController.h */, 62 | 28C286E00D94DF7D0034E888 /* DemoTableViewController.m */, 63 | 4CAFBC7E11FC96FC00651784 /* PullRefreshTableViewController.h */, 64 | 4CAFBC7F11FC96FC00651784 /* PullRefreshTableViewController.m */, 65 | ); 66 | path = Classes; 67 | sourceTree = ""; 68 | }; 69 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | 1D6058910D05DD3D006BFB54 /* PullToRefresh.app */, 73 | ); 74 | name = Products; 75 | sourceTree = ""; 76 | }; 77 | 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | 080E96DDFE201D6D7F000001 /* Classes */, 81 | 29B97315FDCFA39411CA2CEA /* Other Sources */, 82 | 29B97317FDCFA39411CA2CEA /* Resources */, 83 | 29B97323FDCFA39411CA2CEA /* Frameworks */, 84 | 19C28FACFE9D520D11CA2CBB /* Products */, 85 | ); 86 | name = CustomTemplate; 87 | sourceTree = ""; 88 | }; 89 | 29B97315FDCFA39411CA2CEA /* Other Sources */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 28A0AAE50D9B0CCF005BE974 /* PullToRefresh_Prefix.pch */, 93 | 29B97316FDCFA39411CA2CEA /* main.m */, 94 | ); 95 | name = "Other Sources"; 96 | sourceTree = ""; 97 | }; 98 | 29B97317FDCFA39411CA2CEA /* Resources */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 4CBE3BED11FE21CB007696B3 /* arrow.png */, 102 | 4CAFBCEE11FC994F00651784 /* README.markdown */, 103 | 8D1107310486CEB800E47090 /* PullToRefresh-Info.plist */, 104 | ); 105 | name = Resources; 106 | sourceTree = ""; 107 | }; 108 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 4CAFBD0011FC9B2100651784 /* QuartzCore.framework */, 112 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, 113 | 1D30AB110D05D00D00671497 /* Foundation.framework */, 114 | 2892E40F0DC94CBA00A64D0F /* CoreGraphics.framework */, 115 | ); 116 | name = Frameworks; 117 | sourceTree = ""; 118 | }; 119 | /* End PBXGroup section */ 120 | 121 | /* Begin PBXNativeTarget section */ 122 | 1D6058900D05DD3D006BFB54 /* PullToRefresh */ = { 123 | isa = PBXNativeTarget; 124 | buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "PullToRefresh" */; 125 | buildPhases = ( 126 | 1D60588D0D05DD3D006BFB54 /* Resources */, 127 | 1D60588E0D05DD3D006BFB54 /* Sources */, 128 | 1D60588F0D05DD3D006BFB54 /* Frameworks */, 129 | ); 130 | buildRules = ( 131 | ); 132 | dependencies = ( 133 | ); 134 | name = PullToRefresh; 135 | productName = PullToRefresh; 136 | productReference = 1D6058910D05DD3D006BFB54 /* PullToRefresh.app */; 137 | productType = "com.apple.product-type.application"; 138 | }; 139 | /* End PBXNativeTarget section */ 140 | 141 | /* Begin PBXProject section */ 142 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 143 | isa = PBXProject; 144 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "PullToRefresh" */; 145 | compatibilityVersion = "Xcode 3.1"; 146 | hasScannedForEncodings = 1; 147 | knownRegions = ( 148 | English, 149 | Japanese, 150 | French, 151 | German, 152 | en, 153 | ); 154 | mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; 155 | projectDirPath = ""; 156 | projectRoot = ""; 157 | targets = ( 158 | 1D6058900D05DD3D006BFB54 /* PullToRefresh */, 159 | ); 160 | }; 161 | /* End PBXProject section */ 162 | 163 | /* Begin PBXResourcesBuildPhase section */ 164 | 1D60588D0D05DD3D006BFB54 /* Resources */ = { 165 | isa = PBXResourcesBuildPhase; 166 | buildActionMask = 2147483647; 167 | files = ( 168 | 4CAFBCEF11FC994F00651784 /* README.markdown in Resources */, 169 | 4CBE3BEE11FE21CB007696B3 /* arrow.png in Resources */, 170 | ); 171 | runOnlyForDeploymentPostprocessing = 0; 172 | }; 173 | /* End PBXResourcesBuildPhase section */ 174 | 175 | /* Begin PBXSourcesBuildPhase section */ 176 | 1D60588E0D05DD3D006BFB54 /* Sources */ = { 177 | isa = PBXSourcesBuildPhase; 178 | buildActionMask = 2147483647; 179 | files = ( 180 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */, 181 | 1D3623260D0F684500981E51 /* PullToRefreshAppDelegate.m in Sources */, 182 | 28C286E10D94DF7D0034E888 /* DemoTableViewController.m in Sources */, 183 | 4CAFBC8011FC96FC00651784 /* PullRefreshTableViewController.m in Sources */, 184 | ); 185 | runOnlyForDeploymentPostprocessing = 0; 186 | }; 187 | /* End PBXSourcesBuildPhase section */ 188 | 189 | /* Begin XCBuildConfiguration section */ 190 | 1D6058940D05DD3E006BFB54 /* Debug */ = { 191 | isa = XCBuildConfiguration; 192 | buildSettings = { 193 | ALWAYS_SEARCH_USER_PATHS = NO; 194 | COPY_PHASE_STRIP = NO; 195 | GCC_DYNAMIC_NO_PIC = NO; 196 | GCC_OPTIMIZATION_LEVEL = 0; 197 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 198 | GCC_PREFIX_HEADER = PullToRefresh_Prefix.pch; 199 | INFOPLIST_FILE = "PullToRefresh-Info.plist"; 200 | PRODUCT_NAME = PullToRefresh; 201 | }; 202 | name = Debug; 203 | }; 204 | 1D6058950D05DD3E006BFB54 /* Release */ = { 205 | isa = XCBuildConfiguration; 206 | buildSettings = { 207 | ALWAYS_SEARCH_USER_PATHS = NO; 208 | COPY_PHASE_STRIP = YES; 209 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 210 | GCC_PREFIX_HEADER = PullToRefresh_Prefix.pch; 211 | INFOPLIST_FILE = "PullToRefresh-Info.plist"; 212 | PRODUCT_NAME = PullToRefresh; 213 | VALIDATE_PRODUCT = YES; 214 | }; 215 | name = Release; 216 | }; 217 | C01FCF4F08A954540054247B /* Debug */ = { 218 | isa = XCBuildConfiguration; 219 | buildSettings = { 220 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 221 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 222 | GCC_C_LANGUAGE_STANDARD = c99; 223 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 224 | GCC_WARN_UNUSED_VARIABLE = YES; 225 | PREBINDING = NO; 226 | SDKROOT = iphoneos4.0; 227 | }; 228 | name = Debug; 229 | }; 230 | C01FCF5008A954540054247B /* Release */ = { 231 | isa = XCBuildConfiguration; 232 | buildSettings = { 233 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 234 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 235 | GCC_C_LANGUAGE_STANDARD = c99; 236 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 237 | GCC_WARN_UNUSED_VARIABLE = YES; 238 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 239 | PREBINDING = NO; 240 | SDKROOT = iphoneos4.0; 241 | }; 242 | name = Release; 243 | }; 244 | /* End XCBuildConfiguration section */ 245 | 246 | /* Begin XCConfigurationList section */ 247 | 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "PullToRefresh" */ = { 248 | isa = XCConfigurationList; 249 | buildConfigurations = ( 250 | 1D6058940D05DD3E006BFB54 /* Debug */, 251 | 1D6058950D05DD3E006BFB54 /* Release */, 252 | ); 253 | defaultConfigurationIsVisible = 0; 254 | defaultConfigurationName = Release; 255 | }; 256 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "PullToRefresh" */ = { 257 | isa = XCConfigurationList; 258 | buildConfigurations = ( 259 | C01FCF4F08A954540054247B /* Debug */, 260 | C01FCF5008A954540054247B /* Release */, 261 | ); 262 | defaultConfigurationIsVisible = 0; 263 | defaultConfigurationName = Release; 264 | }; 265 | /* End XCConfigurationList section */ 266 | }; 267 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 268 | } 269 | -------------------------------------------------------------------------------- /PullToRefresh_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'PullToRefresh' target in the 'PullToRefresh' project 3 | // 4 | #import 5 | 6 | #ifndef __IPHONE_3_0 7 | #warning "This project uses features only available in iPhone SDK 3.0 and later." 8 | #endif 9 | 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | **Attention:** As of iOS 6.0, there is a [UIRefreshControl](https://developer.apple.com/library/ios/documentation/uikit/reference/UIRefreshControl_class/Reference/Reference.html) object that makes adding pull-to-refresh functionality super easy. If you only need to support iOS 6.0 and later, I'd recommend using [UIRefreshControl](https://developer.apple.com/library/ios/documentation/uikit/reference/UIRefreshControl_class/Reference/Reference.html) instead. 2 | 3 | ### PullToRefresh 4 | 5 | A simple iPhone TableViewController for adding pull-to-refresh functionality. 6 | 7 | ![](http://s3.amazonaws.com/leah.baconfile.com/blog/refresh-small-1.png) 8 | ![](http://s3.amazonaws.com/leah.baconfile.com/blog/refresh-small-2.png) 9 | ![](http://s3.amazonaws.com/leah.baconfile.com/blog/refresh-small-3.png) 10 | ![](http://s3.amazonaws.com/leah.baconfile.com/blog/refresh-small-4.png) 11 | 12 | Inspired by [Tweetie 2](http://www.atebits.com/tweetie-iphone/), [Oliver Drobnik's blog post](http://www.drobnik.com/touch/2009/12/how-to-make-a-pull-to-reload-tableview-just-like-tweetie-2/) 13 | and [EGOTableViewPullRefresh](http://github.com/enormego/EGOTableViewPullRefresh). 14 | 15 | 16 | How to install 17 | 18 | 1. Copy the files, [PullRefreshTableViewController.h](https://raw.github.com/leah/PullToRefresh/master/Classes/PullRefreshTableViewController.h), 19 | [PullRefreshTableViewController.m](https://raw.github.com/leah/PullToRefresh/master/Classes/PullRefreshTableViewController.m), 20 | and [arrow.png](http://github.com/leah/PullToRefresh/raw/master/arrow.png) into your project. 21 | 22 | 2. Link against the QuartzCore framework (used for rotating the arrow image). 23 | 24 | 3. Create a TableViewController that is a subclass of PullRefreshTableViewController. 25 | 26 | 4. Customize by adding your own refresh() method. 27 | 28 | 29 | Enjoy! 30 | -------------------------------------------------------------------------------- /arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leah/PullToRefresh/1b48345efb99725c7ebcd69d5f726bd4b81e1ab2/arrow.png -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PullToRefresh 4 | // 5 | // Created by Leah Culver on 7/25/10. 6 | // Copyright __MyCompanyName__ 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) { 12 | 13 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 14 | int retVal = UIApplicationMain(argc, argv, nil, @"PullToRefreshAppDelegate"); 15 | [pool release]; 16 | return retVal; 17 | } 18 | --------------------------------------------------------------------------------