├── PongRefreshControlDemo
├── Podfile
├── PongRefreshControlDemo
│ ├── en.lproj
│ │ └── InfoPlist.strings
│ ├── BOZAppDelegate.h
│ ├── main.m
│ ├── BOZDemoViewController.h
│ ├── PongRefreshControlDemo-Prefix.pch
│ ├── BOZNoNavBarViewController.h
│ ├── Images.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── LaunchImage.launchimage
│ │ │ └── Contents.json
│ ├── BOZRegularViewController.h
│ ├── BOZScrollViewController.h
│ ├── PongRefreshControlDemo-Info.plist
│ ├── BOZNoNavBarViewController.xib
│ ├── BOZNoNavBarViewController.m
│ ├── BOZDemoViewController.m
│ ├── BOZAppDelegate.m
│ ├── BOZRegularViewController.m
│ ├── BOZScrollViewController.m
│ └── Storyboard.storyboard
├── PongRefreshControlDemoTests
│ ├── en.lproj
│ │ └── InfoPlist.strings
│ ├── PongRefreshControlDemoTests-Info.plist
│ └── PongRefreshControlDemoTests.m
└── PongRefreshControlDemo.xcodeproj
│ ├── project.xcworkspace
│ └── contents.xcworkspacedata
│ └── project.pbxproj
├── .gitignore
├── BOZPongRefreshControl.podspec
├── LICENSE
├── README.md
└── BOZPongRefreshControl
├── BOZPongRefreshControl.h
└── BOZPongRefreshControl.m
/PongRefreshControlDemo/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios
2 |
3 | podspec :path => "../BOZPongRefreshControl.podspec"
4 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemoTests/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | .DS_Store
3 | */build/*
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | xcuserdata
13 | profile
14 | *.moved-aside
15 | DerivedData
16 | .idea/
17 | *.hmap
18 | *.xccheckout
19 |
20 | #CocoaPods
21 | Pods
22 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/BOZAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // BOZAppDelegate.h
3 | // PongRefreshControlDemo
4 | //
5 | // Created by Ben Oztalay on 12/6/13.
6 | // Copyright (c) 2013 Ben Oztalay. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface BOZAppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // PongRefreshControlDemo
4 | //
5 | // Created by Ben Oztalay on 12/6/13.
6 | // Copyright (c) 2013 Ben Oztalay. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "BOZAppDelegate.h"
12 |
13 | int main(int argc, char * argv[])
14 | {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([BOZAppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/BOZDemoViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // BOZDemoViewController.h
3 | // PongRefreshControlDemo
4 | //
5 | // Created by Ben Oztalay on 12/6/13.
6 | // Copyright (c) 2013 Ben Oztalay. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BOZPongRefreshControl.h"
11 |
12 | @interface BOZDemoViewController : UITableViewController
13 |
14 | @property (strong, nonatomic) BOZPongRefreshControl* pongRefreshControl;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/PongRefreshControlDemo-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header
3 | //
4 | // The contents of this file are implicitly included at the beginning of every source file.
5 | //
6 |
7 | #import
8 |
9 | #ifndef __IPHONE_3_0
10 | #warning "This project uses features only available in iOS SDK 3.0 and later."
11 | #endif
12 |
13 | #ifdef __OBJC__
14 | #import
15 | #import
16 | #endif
17 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/BOZNoNavBarViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // BOZNoNavBarViewController.h
3 | // PongRefreshControlDemo
4 | //
5 | // Created by Ben Oztalay on 12/6/13.
6 | // Copyright (c) 2013 Ben Oztalay. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BOZPongRefreshControl.h"
11 |
12 | @interface BOZNoNavBarViewController : UITableViewController
13 |
14 | @property (strong, nonatomic) BOZPongRefreshControl* pongRefreshControl;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "40x40",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "60x60",
16 | "scale" : "2x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/BOZRegularViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // BOZRegularViewController.h
3 | // PongRefreshControlDemo
4 | //
5 | // Created by Ben Oztalay on 12/7/13.
6 | // Copyright (c) 2013 Ben Oztalay. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BOZPongRefreshControl.h"
11 |
12 | @interface BOZRegularViewController : UIViewController
13 |
14 | @property (weak, nonatomic) IBOutlet UITableView* tableView;
15 |
16 | @property (strong, nonatomic) BOZPongRefreshControl* pongRefreshControl;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/BOZScrollViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // BOZScrollViewController.h
3 | // PongRefreshControlDemo
4 | //
5 | // Created by Ben Oztalay on 12/7/13.
6 | // Copyright (c) 2013 Ben Oztalay. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "BOZPongRefreshControl.h"
11 |
12 | @interface BOZScrollViewController : UIViewController {
13 | UILabel* scrollMeLabel;
14 | }
15 |
16 | @property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
17 |
18 | @property (strong, nonatomic) BOZPongRefreshControl* pongRefreshControl;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "7.0",
8 | "scale" : "2x"
9 | },
10 | {
11 | "orientation" : "portrait",
12 | "idiom" : "iphone",
13 | "subtype" : "retina4",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "7.0",
16 | "scale" : "2x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemoTests/PongRefreshControlDemoTests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | com.boztalay.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/BOZPongRefreshControl.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'BOZPongRefreshControl'
3 | s.version = '1.0.1'
4 | s.summary = 'A pull-down-to-refresh control for iOS that plays pong, originally created for the MHacks III iOS app'
5 | s.homepage = 'https://github.com/boztalay/BOZPongRefreshControl'
6 | s.license = { :type => 'MIT', :file => 'LICENSE' }
7 | s.authors = { 'Ben Oztalay' => 'boztalay@gmail.com', 'Joseph Constan' => 'jcon5294@gmail.com', 'Mahir Eusufzai' => 'github.com/MahirEusufzai', 'ajfigueroa' => 'github.com/ajfigueroa'}
8 | s.platform = :ios
9 | s.source = { :git => 'https://github.com/boztalay/BOZPongRefreshControl.git', :tag => '1.0.1' }
10 | s.source_files = 'BOZPongRefreshControl/**/*.{h,m}'
11 | s.public_header_files = 'BOZPongRefreshControl/**/*.h'
12 | s.framework = 'UIKit'
13 | s.requires_arc = true
14 | end
15 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemoTests/PongRefreshControlDemoTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // PongRefreshControlDemoTests.m
3 | // PongRefreshControlDemoTests
4 | //
5 | // Created by Ben Oztalay on 12/6/13.
6 | // Copyright (c) 2013 Ben Oztalay. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface PongRefreshControlDemoTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation PongRefreshControlDemoTests
16 |
17 | - (void)setUp
18 | {
19 | [super setUp];
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 | }
22 |
23 | - (void)tearDown
24 | {
25 | // Put teardown code here. This method is called after the invocation of each test method in the class.
26 | [super tearDown];
27 | }
28 |
29 | - (void)testExample
30 | {
31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
32 | }
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Ben Oztalay
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/PongRefreshControlDemo-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | com.boztalay.${PRODUCT_NAME:rfc1034identifier}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1.0
25 | LSRequiresIPhoneOS
26 |
27 | UIMainStoryboardFile
28 | Storyboard
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeRight
37 | UIInterfaceOrientationLandscapeLeft
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/BOZNoNavBarViewController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/BOZNoNavBarViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // BOZNoNavBarViewController.m
3 | // PongRefreshControlDemo
4 | //
5 | // Created by Ben Oztalay on 12/6/13.
6 | // Copyright (c) 2013 Ben Oztalay. All rights reserved.
7 | //
8 |
9 | #import "BOZNoNavBarViewController.h"
10 |
11 | @implementation BOZNoNavBarViewController
12 |
13 | - (void)viewDidLoad
14 | {
15 | [super viewDidLoad];
16 |
17 | /* NOTE: Do NOT attach the refresh control in viewDidLoad!
18 | * If you do this here, it'll act very funny if you have
19 | * a navigation bar or other such similar thing that iOS 7
20 | * automatically offsets content for. You have to wait for
21 | * the subviews to get laid out first so the refresh
22 | * control knows how big that offset is!
23 | */
24 | }
25 |
26 | - (void)viewDidLayoutSubviews
27 | {
28 | self.pongRefreshControl = [BOZPongRefreshControl attachToTableView:self.tableView
29 | withRefreshTarget:self
30 | andRefreshAction:@selector(refreshTriggered)];
31 | self.pongRefreshControl.foregroundColor = [UIColor greenColor];
32 | }
33 |
34 | //Resetting the refresh control if the user leaves the screen
35 | - (void)viewWillDisappear:(BOOL)animated
36 | {
37 | [self.pongRefreshControl finishedLoading];
38 | }
39 |
40 | #pragma mark - Notifying the pong refresh control of scrolling
41 |
42 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView
43 | {
44 | [self.pongRefreshControl scrollViewDidScroll];
45 | }
46 |
47 | - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
48 | {
49 | [self.pongRefreshControl scrollViewDidEndDragging];
50 | }
51 |
52 | #pragma mark - Listening for the user to trigger a refresh
53 |
54 | - (void)refreshTriggered
55 | {
56 |
57 | }
58 |
59 | #pragma mark - Resetting the refresh control when loading is done
60 |
61 | - (IBAction)doneLoadingButtonPressed:(id)sender
62 | {
63 | [self.pongRefreshControl finishedLoading];
64 | }
65 |
66 | #pragma mark - Going back
67 |
68 | - (IBAction)goBackButtonPressed:(id)sender
69 | {
70 | [self dismissViewControllerAnimated:YES completion:NULL];
71 | }
72 |
73 | @end
74 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/BOZDemoViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // BOZDemoViewController.m
3 | // PongRefreshControlDemo
4 | //
5 | // Created by Ben Oztalay on 12/6/13.
6 | // Copyright (c) 2013 Ben Oztalay. All rights reserved.
7 | //
8 |
9 | #import "BOZDemoViewController.h"
10 |
11 | @implementation BOZDemoViewController
12 |
13 | - (void)viewDidLoad
14 | {
15 | [super viewDidLoad];
16 |
17 | /* NOTE: Do NOT attach the refresh control in viewDidLoad!
18 | * If you do this here, it'll act very funny if you have
19 | * a navigation bar or other such similar thing that iOS 7
20 | * automatically offsets content for. You have to wait for
21 | * the subviews to get laid out first so the refresh
22 | * control knows how big that offset is!
23 | */
24 | }
25 |
26 | - (void)viewDidLayoutSubviews
27 | {
28 | self.pongRefreshControl = [BOZPongRefreshControl attachToTableView:self.tableView
29 | withRefreshTarget:self
30 | andRefreshAction:@selector(refreshTriggered)];
31 | }
32 |
33 | - (void)viewWillDisappear:(BOOL)animated
34 | {
35 | //Resetting the refresh control if the user leaves the screen
36 | [self.pongRefreshControl finishedLoading];
37 | }
38 |
39 | #pragma mark - Notifying the pong refresh control of scrolling
40 |
41 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView
42 | {
43 | [self.pongRefreshControl scrollViewDidScroll];
44 | }
45 |
46 | - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
47 | {
48 | [self.pongRefreshControl scrollViewDidEndDragging];
49 | }
50 |
51 | #pragma mark - Listening for the user to trigger a refresh
52 |
53 | - (void)refreshTriggered
54 | {
55 | // UIAlertView *alert = [[UIAlertView alloc]
56 | // initWithTitle:@"Whoa!"
57 | // message:@"You triggered a refresh! Hit \"Done Loading\" to make it stop."
58 | // delegate:nil
59 | // cancelButtonTitle:@"Sweet!"
60 | // otherButtonTitles:nil];
61 | // [alert show];
62 | }
63 |
64 | #pragma mark - Resetting the refresh control when loading is done
65 |
66 | - (IBAction)doneLoadingButtonPressed:(id)sender
67 | {
68 | [self.pongRefreshControl finishedLoading];
69 | }
70 |
71 | @end
72 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/BOZAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // BOZAppDelegate.m
3 | // PongRefreshControlDemo
4 | //
5 | // Created by Ben Oztalay on 12/6/13.
6 | // Copyright (c) 2013 Ben Oztalay. All rights reserved.
7 | //
8 |
9 | #import "BOZAppDelegate.h"
10 |
11 | @implementation BOZAppDelegate
12 |
13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
14 | {
15 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
16 |
17 | UIStoryboard* storyboard = [UIStoryboard storyboardWithName:[[NSBundle mainBundle].infoDictionary objectForKey:@"UIMainStoryboardFile"] bundle:[NSBundle mainBundle]];
18 | self.window.rootViewController = [storyboard instantiateInitialViewController];
19 |
20 | self.window.backgroundColor = [UIColor whiteColor];
21 | [self.window makeKeyAndVisible];
22 | return YES;
23 | }
24 |
25 | - (void)applicationWillResignActive:(UIApplication *)application
26 | {
27 | // 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.
28 | // 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.
29 | }
30 |
31 | - (void)applicationDidEnterBackground:(UIApplication *)application
32 | {
33 | // 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.
34 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
35 | }
36 |
37 | - (void)applicationWillEnterForeground:(UIApplication *)application
38 | {
39 | // 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.
40 | }
41 |
42 | - (void)applicationDidBecomeActive:(UIApplication *)application
43 | {
44 | // 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.
45 | }
46 |
47 | - (void)applicationWillTerminate:(UIApplication *)application
48 | {
49 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
50 | }
51 |
52 | @end
53 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/BOZRegularViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // BOZRegularViewController.m
3 | // PongRefreshControlDemo
4 | //
5 | // Created by Ben Oztalay on 12/7/13.
6 | // Copyright (c) 2013 Ben Oztalay. All rights reserved.
7 | //
8 |
9 | #import "BOZRegularViewController.h"
10 |
11 | @implementation BOZRegularViewController
12 |
13 | - (void)viewDidLoad
14 | {
15 | [super viewDidLoad];
16 |
17 | /* NOTE: Do NOT attach the refresh control in viewDidLoad!
18 | * If you do this here, it'll act very funny if you have
19 | * a navigation bar or other such similar thing that iOS 7
20 | * automatically offsets content for. You have to wait for
21 | * the subviews to get laid out first so the refresh
22 | * control knows how big that offset is!
23 | */
24 | }
25 |
26 | - (void)viewDidLayoutSubviews
27 | {
28 | self.pongRefreshControl = [BOZPongRefreshControl attachToTableView:self.tableView
29 | withRefreshTarget:self
30 | andRefreshAction:@selector(refreshTriggered)];
31 | self.pongRefreshControl.backgroundColor = [UIColor whiteColor];
32 | self.pongRefreshControl.foregroundColor = [UIColor blackColor];
33 | }
34 |
35 | //Resetting the refresh control if the user leaves the screen
36 | - (void)viewWillDisappear:(BOOL)animated
37 | {
38 | [self.pongRefreshControl finishedLoading];
39 | }
40 |
41 | #pragma mark - Notifying the pong refresh control of scrolling
42 |
43 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView
44 | {
45 | [self.pongRefreshControl scrollViewDidScroll];
46 | }
47 |
48 | - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
49 | {
50 | [self.pongRefreshControl scrollViewDidEndDragging];
51 | }
52 |
53 | #pragma mark - Listening for the user to trigger a refresh
54 |
55 | - (void)refreshTriggered
56 | {
57 |
58 | }
59 |
60 | #pragma mark - Resetting the refresh control when loading is done
61 |
62 | - (IBAction)doneLoadingButtonPressed:(id)sender
63 | {
64 | [self.pongRefreshControl finishedLoading];
65 | }
66 |
67 | #pragma mark - Table view data source
68 |
69 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
70 | {
71 | return 7;
72 | }
73 |
74 | - (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
75 | {
76 | static NSString *CellIdentifier = @"Cell";
77 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
78 | if (cell == nil) {
79 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
80 | }
81 |
82 | CGFloat alphaComponent = 1.0f - (float)(indexPath.row + 1) / (float)([tableView numberOfRowsInSection:0] + 1);
83 | cell.contentView.backgroundColor = [UIColor colorWithRed:0.373f green:0.820f blue:0.294f alpha:alphaComponent];
84 | cell.backgroundColor = [UIColor whiteColor];
85 |
86 | return cell;
87 | }
88 |
89 | @end
90 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | BOZPongRefreshControl
2 | =====================
3 |
4 | A pull-down-to-refresh control for iOS that plays pong
5 |
6 | 
7 |
8 | Installation
9 | ------------
10 |
11 | It's on CocoaPods! Put ```pod 'BOZPongRefreshControl'``` in your Podfile.
12 |
13 | Alternatively, just place ```BOZPongRefreshControl.h``` and ```BOZPongRefreshControl.m``` in your project anywhere you'd like.
14 |
15 | Usage
16 | --------
17 |
18 | Attach it to a ```UITableView``` or ```UIScrollView``` like so:
19 |
20 | ```objective-c
21 | - (void)viewDidLoad
22 | {
23 | [super viewDidLoad];
24 |
25 | /* NOTE: Do NOT attach the refresh control in viewDidLoad!
26 | * If you do this here, it'll act very funny if you have
27 | * a navigation bar or other such similar thing that iOS
28 | * automatically offsets content for. You have to wait for
29 | * the subviews to get laid out first so the refresh
30 | * control knows how big that offset is!
31 | */
32 | }
33 |
34 | - (void)viewDidLayoutSubviews
35 | {
36 | self.pongRefreshControl = [BOZPongRefreshControl attachToTableView:self.tableView
37 | withRefreshTarget:self
38 | andRefreshAction:@selector(refreshTriggered)];
39 | }
40 | ```
41 |
42 | Then, implement ```UIScrollViewDelegate``` in your ```UIViewController``` if you haven't already, and pass the calls through to the refresh control:
43 |
44 | ```objective-c
45 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView
46 | {
47 | [self.pongRefreshControl scrollViewDidScroll];
48 | }
49 |
50 | - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
51 | {
52 | [self.pongRefreshControl scrollViewDidEndDragging];
53 | }
54 | ```
55 |
56 | Lastly, make sure you've implemented the ```refreshAction``` you passed it earlier to listen for refresh triggers:
57 |
58 | ```objective-c
59 | - (void)refreshTriggered
60 | {
61 | //Go and load some data
62 |
63 | //Finshed loading the data, reset the refresh control
64 | [self.pongRefreshControl finishedLoading];
65 | }
66 | ```
67 |
68 | For more details, check out the demo app's code. It has examples for using the refresh control on a ```UIScrollView``` and outside of a ```UITableViewController```.
69 |
70 | Configuration
71 | -------------
72 |
73 | - Set the foreground color with the ```foregroundColor``` property
74 | - Set the background color with the ```backgroundColor``` property
75 | - Adjust how fast it plays by changing the ```totalHorizontalTravelTimeForBall``` property
76 |
77 | Known Issues/To Do
78 | ------------------
79 |
80 | - It'll interfere with ```UIScrollView``` content that's above ```y = 0.0f```
81 | - I haven't tested it, but I'd be willing to bet it looks a bit silly on iPads
82 | - Test it out on a physical iPhone 6+
83 | - The behavior of the paddles needs a little work
84 | - The the ```UIScrollView``` that it's attached to is scrolled automatically, the refresh control may be scrolled down into view under some circumstances (expanding/collapsing ```UITableViewCell```s, for example)
85 | - Tests!
86 |
--------------------------------------------------------------------------------
/BOZPongRefreshControl/BOZPongRefreshControl.h:
--------------------------------------------------------------------------------
1 | //
2 | // BOZPongRefreshControl.h
3 | // Ben Oztalay
4 | //
5 | // Created by Ben Oztalay on 11/22/13.
6 | // Copyright (c) 2013 Ben Oztalay. All rights reserved.
7 | //
8 | // Version 1.0.0
9 | // https://www.github.com/boztalay/BOZPongRefreshControl
10 | //
11 |
12 | #import
13 |
14 | @interface BOZPongRefreshControl : UIView
15 |
16 | #pragma mark - Attaching a pong refresh control
17 |
18 | /**
19 | * This function simply calls attachToScrollView. Kept for
20 | * compatibility with earlier versions.
21 | */
22 | + (BOZPongRefreshControl*)attachToTableView:(UITableView*)tableView
23 | withRefreshTarget:(id)refreshTarget
24 | andRefreshAction:(SEL)refreshAction;
25 |
26 | /**
27 | * Call this function to attach a pong refresh control to
28 | * a UIScrollView. Keep in mind that it does this by adding
29 | * the pong refresh control as a subview above the normal
30 | * content frame (negative y value in the origin), so if you
31 | * have content up there, it'll be covered up.
32 | *
33 | * The pong refresh control will perform the refreshAction on
34 | * on the refreshTarget when the user triggers a refresh.
35 | */
36 | + (BOZPongRefreshControl*)attachToScrollView:(UIScrollView*)scrollView
37 | withRefreshTarget:(id)refreshTarget
38 | andRefreshAction:(SEL)refreshAction;
39 |
40 | #pragma mark - Functions required to use a pong refresh control
41 |
42 | /**
43 | * Calls [self beginLoadingAnimated:YES]. Kept for
44 | * backwards-compatibility.
45 | */
46 | - (void)beginLoading;
47 |
48 | /**
49 | * Call this function to programatically scroll the refresh
50 | * control into view, and begin the animation. Does not notify
51 | * target of trigger.
52 | * @param animated Dictates whether the action of scrolling to
53 | * the refresh control is animated (YES) or instant (NO).
54 | */
55 | - (void)beginLoadingAnimated:(BOOL)animated;
56 |
57 | /**
58 | * Call this function when whatever loading task you're doing
59 | * is done. This will reset the pong refresh control and hide
60 | * it. It's also a good idea to call this if your view is
61 | * going to disappear.
62 | */
63 | - (void)finishedLoading;
64 |
65 | /**
66 | * Override the implementation of scrollViewDidScroll: in
67 | * UIScrollViewDelegate and call this function inside of it.
68 | * This lets the pong refresh control know to update its
69 | * subviews as the user scrolls.
70 | */
71 | - (void)scrollViewDidScroll;
72 |
73 | /**
74 | * Override the implementation of scrollViewDidEndDragging:willDecelerate:
75 | * in UIScrollViewDelegate and call this function inside of it.
76 | * This lets the pong refresh control know the user let go
77 | * of the scroll view and causes it to check if a refresh should
78 | * be triggered.
79 | */
80 | - (void)scrollViewDidEndDragging;
81 |
82 | #pragma mark - Configurable properties
83 |
84 | /**
85 | * This controls the color of the paddles and ball. Use
86 | * the standard backgroundColor property to set the
87 | * background color.
88 | */
89 | @property (strong, nonatomic) UIColor* foregroundColor;
90 |
91 | /**
92 | * This controls how long it takes the ball to get from
93 | * one paddle to the other, regardless of floor/ceiling
94 | * bouncing
95 | */
96 | @property (nonatomic) CGFloat totalHorizontalTravelTimeForBall;
97 |
98 | @end
99 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/BOZScrollViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // BOZScrollViewController.m
3 | // PongRefreshControlDemo
4 | //
5 | // Created by Ben Oztalay on 12/7/13.
6 | // Copyright (c) 2013 Ben Oztalay. All rights reserved.
7 | //
8 |
9 | #import "BOZScrollViewController.h"
10 |
11 | #define STRIPE_HEIGHT 50.0f
12 | #define NUM_STRIPES 11
13 | #define SCROLLVIEW_CONTENT_HEIGHT (STRIPE_HEIGHT * NUM_STRIPES)
14 |
15 | @implementation BOZScrollViewController
16 |
17 | - (void)viewDidLoad
18 | {
19 | [super viewDidLoad];
20 |
21 | self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width, SCROLLVIEW_CONTENT_HEIGHT);
22 |
23 | for(int i = 0; i < NUM_STRIPES; i++) {
24 | UIView* view = [[UIView alloc] initWithFrame:CGRectMake(0.0f, i * STRIPE_HEIGHT, self.scrollView.frame.size.width, STRIPE_HEIGHT)];
25 |
26 | CGFloat proportionOfScrollViewFilled = ((float)(i + 1) / (NUM_STRIPES + 1.0f));
27 | CGFloat whiteValue = 1.0f - proportionOfScrollViewFilled;
28 |
29 | view.backgroundColor = [UIColor colorWithWhite:whiteValue alpha:1.0f];
30 |
31 | if(i == 0) {
32 | scrollMeLabel = [[UILabel alloc] initWithFrame:CGRectZero];
33 | scrollMeLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
34 | [view addSubview:scrollMeLabel];
35 | [self setScrollMeLabelText:@"Scroll Me!"];
36 | }
37 |
38 | view.autoresizingMask = UIViewAutoresizingFlexibleWidth;
39 | [self.scrollView addSubview:view];
40 | }
41 |
42 | /* NOTE: Do NOT attach the refresh control in viewDidLoad!
43 | * If you do this here, it'll act very funny if you have
44 | * a navigation bar or other such similar thing that iOS 7
45 | * automatically offsets content for. You have to wait for
46 | * the subviews to get laid out first so the refresh
47 | * control knows how big that offset is!
48 | */
49 | }
50 |
51 | - (void)setScrollMeLabelText:(NSString*)newText
52 | {
53 | scrollMeLabel.text = newText;
54 | [scrollMeLabel sizeToFit];
55 | scrollMeLabel.center = CGPointMake(scrollMeLabel.superview.frame.size.width / 2.0f,
56 | scrollMeLabel.superview.frame.size.height / 2.0f);
57 | }
58 |
59 | - (void)viewDidLayoutSubviews
60 | {
61 | self.pongRefreshControl = [BOZPongRefreshControl attachToScrollView:self.scrollView
62 | withRefreshTarget:self
63 | andRefreshAction:@selector(refreshTriggered)];
64 | self.pongRefreshControl.backgroundColor = [UIColor colorWithRed:0.000f green:0.132f blue:0.298f alpha:1.0f];
65 | self.pongRefreshControl.foregroundColor = [UIColor colorWithRed:1.000f green:0.796f blue:0.020f alpha:1.0f];
66 | }
67 |
68 | //Resetting the refresh control if the user leaves the screen
69 | - (void)viewWillDisappear:(BOOL)animated
70 | {
71 | [self.pongRefreshControl finishedLoading];
72 | }
73 |
74 |
75 | #pragma mark - Notifying the pong refresh control of scrolling
76 |
77 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView
78 | {
79 | [self.pongRefreshControl scrollViewDidScroll];
80 | }
81 |
82 | - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
83 | {
84 | [self.pongRefreshControl scrollViewDidEndDragging];
85 |
86 | [self setScrollMeLabelText:@"Scroll Me!"];
87 | }
88 |
89 | #pragma mark - Listening for the user to trigger a refresh
90 |
91 | - (void)refreshTriggered
92 | {
93 |
94 | }
95 |
96 | #pragma mark - Resetting the refresh control when loading is done
97 |
98 | - (IBAction)doneLoadingButtonPressed:(id)sender
99 | {
100 | [self.pongRefreshControl finishedLoading];
101 | }
102 |
103 | #pragma mark - Changing the "Scroll Me!" label
104 |
105 | - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
106 | {
107 | [self setScrollMeLabelText:@":D"];
108 | }
109 |
110 | @end
111 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo/Storyboard.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
--------------------------------------------------------------------------------
/BOZPongRefreshControl/BOZPongRefreshControl.m:
--------------------------------------------------------------------------------
1 | //
2 | // BOZPongRefreshControl.m
3 | // Ben Oztalay
4 | //
5 | // Created by Ben Oztalay on 11/22/13.
6 | // Copyright (c) 2013 Ben Oztalay. All rights reserved.
7 | //
8 | // Version 1.0.0
9 | // https://www.github.com/boztalay/BOZPongRefreshControl
10 | //
11 |
12 | #import "BOZPongRefreshControl.h"
13 |
14 | #define REFRESH_CONTROL_HEIGHT 65.0f
15 | #define HALF_REFRESH_CONTROL_HEIGHT (REFRESH_CONTROL_HEIGHT / 2.0f)
16 |
17 | #define DEFAULT_FOREGROUND_COLOR [UIColor whiteColor]
18 | #define DEFAULT_BACKGROUND_COLOR [UIColor colorWithWhite:0.10f alpha:1.0f]
19 |
20 | #define DEFAULT_TOTAL_HORIZONTAL_TRAVEL_TIME_FOR_BALL 0.75f
21 |
22 | #define TRANSITION_ANIMATION_DURATION 0.2f
23 |
24 | typedef enum {
25 | BOZPongRefreshControlStateIdle = 0,
26 | BOZPongRefreshControlStateRefreshing = 1,
27 | BOZPongRefreshControlStateResetting = 2
28 | } BOZPongRefreshControlState;
29 |
30 | @interface BOZPongRefreshControl() {
31 | BOZPongRefreshControlState state;
32 |
33 | CGFloat originalTopContentInset;
34 |
35 | UIView* leftPaddleView;
36 | UIView* rightPaddleView;
37 | UIView* ballView;
38 |
39 | CGPoint leftPaddleIdleOrigin;
40 | CGPoint rightPaddleIdleOrigin;
41 | CGPoint ballIdleOrigin;
42 |
43 | CGPoint ballOrigin;
44 | CGPoint ballDestination;
45 | CGPoint ballDirection;
46 |
47 | CGFloat leftPaddleOrigin;
48 | CGFloat rightPaddleOrigin;
49 | CGFloat leftPaddleDestination;
50 | CGFloat rightPaddleDestination;
51 |
52 | UIView* gameView;
53 |
54 | NSDate* currentAnimationStartTime;
55 | CGFloat currentAnimationDuration;
56 | }
57 |
58 | @property (assign, nonatomic) UIScrollView* scrollView;
59 | @property (assign, nonatomic) id refreshTarget;
60 | @property (nonatomic) SEL refreshAction;
61 | @property (nonatomic, readonly) CGFloat distanceScrolled;
62 |
63 | @end
64 |
65 | @implementation BOZPongRefreshControl
66 |
67 | #pragma mark - Attaching a pong refresh control to a UIScrollView or UITableView
68 |
69 | #pragma mark UITableView
70 |
71 | + (BOZPongRefreshControl*)attachToTableView:(UITableView*)tableView
72 | withRefreshTarget:(id)refreshTarget
73 | andRefreshAction:(SEL)refreshAction
74 | {
75 | return [self attachToScrollView:tableView
76 | withRefreshTarget:refreshTarget
77 | andRefreshAction:refreshAction];
78 | }
79 |
80 | #pragma mark UIScrollView
81 |
82 | + (BOZPongRefreshControl*)attachToScrollView:(UIScrollView*)scrollView
83 | withRefreshTarget:(id)refreshTarget
84 | andRefreshAction:(SEL)refreshAction
85 | {
86 | BOZPongRefreshControl* existingPongRefreshControl = [self findPongRefreshControlInScrollView:scrollView];
87 | if(existingPongRefreshControl != nil) {
88 | return existingPongRefreshControl;
89 | }
90 |
91 | //Initialized height to 0 to hide it
92 | BOZPongRefreshControl* pongRefreshControl = [[BOZPongRefreshControl alloc] initWithFrame:CGRectMake(0.0f, 0.0f, scrollView.frame.size.width, 0.0f)
93 | andScrollView:scrollView
94 | andRefreshTarget:refreshTarget
95 | andRefreshAction:refreshAction];
96 |
97 | [scrollView addSubview:pongRefreshControl];
98 |
99 | return pongRefreshControl;
100 | }
101 |
102 | + (BOZPongRefreshControl*)findPongRefreshControlInScrollView:(UIScrollView*)scrollView
103 | {
104 | for(UIView* subview in scrollView.subviews) {
105 | if([subview isKindOfClass:[BOZPongRefreshControl class]]) {
106 | return (BOZPongRefreshControl*)subview;
107 | }
108 | }
109 |
110 | return nil;
111 | }
112 |
113 | #pragma mark - Initializing a new pong refresh control
114 |
115 | - (id)initWithFrame:(CGRect)frame
116 | andScrollView:(UIScrollView*)scrollView
117 | andRefreshTarget:(id)refreshTarget
118 | andRefreshAction:(SEL)refreshAction
119 | {
120 | self = [super initWithFrame:frame];
121 | if (self) {
122 | self.clipsToBounds = YES;
123 |
124 | self.scrollView = scrollView;
125 | self.refreshTarget = refreshTarget;
126 | self.refreshAction = refreshAction;
127 |
128 | originalTopContentInset = scrollView.contentInset.top;
129 |
130 | [self setUpGameView];
131 | [self setUpGamePieceIdleOrigins];
132 | [self setUpPaddles];
133 | [self setUpBall];
134 |
135 | state = BOZPongRefreshControlStateIdle;
136 |
137 | self.foregroundColor = DEFAULT_FOREGROUND_COLOR;
138 | self.backgroundColor = DEFAULT_BACKGROUND_COLOR;
139 |
140 | [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
141 | [[NSNotificationCenter defaultCenter] addObserver:self
142 | selector:@selector(handleOrientationChange)
143 | name:UIDeviceOrientationDidChangeNotification
144 | object:nil];
145 |
146 | }
147 | return self;
148 | }
149 |
150 | - (void)dealloc
151 | {
152 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
153 | }
154 |
155 | - (void)setUpGameView
156 | {
157 | gameView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.frame.size.width, REFRESH_CONTROL_HEIGHT)];
158 | gameView.backgroundColor = [UIColor clearColor];
159 | [self addSubview:gameView];
160 | }
161 |
162 | - (void)setUpGamePieceIdleOrigins
163 | {
164 | leftPaddleIdleOrigin = CGPointMake(gameView.frame.size.width * 0.25f, gameView.frame.size.height);
165 | rightPaddleIdleOrigin = CGPointMake(gameView.frame.size.width * 0.75f, gameView.frame.size.height);
166 | ballIdleOrigin = CGPointMake(gameView.frame.size.width * 0.50f, 0.0f);
167 | }
168 |
169 | - (void)setUpPaddles
170 | {
171 | leftPaddleView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 2.0f, 15.0f)];
172 | leftPaddleView.center = leftPaddleIdleOrigin;
173 | leftPaddleView.backgroundColor = self.foregroundColor;
174 |
175 | rightPaddleView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 2.0f, 15.0f)];
176 | rightPaddleView.center = rightPaddleIdleOrigin;
177 | rightPaddleView.backgroundColor = self.foregroundColor;
178 |
179 | [gameView addSubview:leftPaddleView];
180 | [gameView addSubview:rightPaddleView];
181 | }
182 |
183 | - (void)setUpBall
184 | {
185 | ballView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 3.0f, 3.0f)];
186 | ballView.center = ballIdleOrigin;
187 | ballView.backgroundColor = self.foregroundColor;
188 |
189 | self.totalHorizontalTravelTimeForBall = DEFAULT_TOTAL_HORIZONTAL_TRAVEL_TIME_FOR_BALL;
190 |
191 | [gameView addSubview:ballView];
192 | }
193 |
194 | #pragma mark - Handling various configuration changes
195 |
196 | - (void)setBackgroundColor:(UIColor *)backgroundColor
197 | {
198 | [super setBackgroundColor:backgroundColor];
199 | }
200 |
201 | - (void)setForegroundColor:(UIColor*)foregroundColor
202 | {
203 | _foregroundColor = foregroundColor;
204 |
205 | leftPaddleView.backgroundColor = foregroundColor;
206 | rightPaddleView.backgroundColor = foregroundColor;
207 | ballView.backgroundColor = foregroundColor;
208 | }
209 |
210 | #pragma mark - Listening to scroll delegate events
211 |
212 | #pragma mark Actively scrolling
213 |
214 | - (void)scrollViewDidScroll
215 | {
216 | CGFloat rawOffset = -self.distanceScrolled;
217 |
218 | [self offsetGameViewBy:rawOffset];
219 |
220 | if(state == BOZPongRefreshControlStateIdle) {
221 | CGFloat ballAndPaddlesOffset = MIN(rawOffset / 2.0f, HALF_REFRESH_CONTROL_HEIGHT);
222 |
223 | [self offsetBallAndPaddlesBy:ballAndPaddlesOffset];
224 | [self rotatePaddlesAccordingToOffset:ballAndPaddlesOffset];
225 | }
226 | }
227 |
228 | - (CGFloat)distanceScrolled
229 | {
230 | return (self.scrollView.contentOffset.y + self.scrollView.contentInset.top);
231 | }
232 |
233 | - (void)offsetGameViewBy:(CGFloat)offset
234 | {
235 | CGFloat offsetConsideringState = offset;
236 | if(state != BOZPongRefreshControlStateIdle) {
237 | offsetConsideringState += REFRESH_CONTROL_HEIGHT;
238 | }
239 |
240 | [self setHeightAndOffsetOfRefreshControl:offsetConsideringState];
241 | [self stickGameViewToBottomOfRefreshControl];
242 | }
243 |
244 | - (void)setHeightAndOffsetOfRefreshControl:(CGFloat)offset
245 | {
246 | CGRect newFrame = self.frame;
247 | newFrame.size.height = offset;
248 | newFrame.origin.y = -offset;
249 | self.frame = newFrame;
250 | }
251 |
252 | - (void)stickGameViewToBottomOfRefreshControl
253 | {
254 | CGRect newGameViewFrame = gameView.frame;
255 | newGameViewFrame.origin.y = self.frame.size.height - gameView.frame.size.height;
256 | gameView.frame = newGameViewFrame;
257 | }
258 |
259 | - (void)offsetBallAndPaddlesBy:(CGFloat)offset
260 | {
261 | ballView.center = CGPointMake(ballIdleOrigin.x, ballIdleOrigin.y + offset);
262 | leftPaddleView.center = CGPointMake(leftPaddleIdleOrigin.x, leftPaddleIdleOrigin.y - offset);
263 | rightPaddleView.center = CGPointMake(rightPaddleIdleOrigin.x, rightPaddleIdleOrigin.y - offset);
264 | }
265 |
266 | - (void)rotatePaddlesAccordingToOffset:(CGFloat)offset
267 | {
268 | CGFloat proportionOfMaxOffset = (offset / HALF_REFRESH_CONTROL_HEIGHT);
269 | CGFloat angleToRotate = M_PI * proportionOfMaxOffset;
270 |
271 | leftPaddleView.transform = CGAffineTransformMakeRotation(angleToRotate);
272 | rightPaddleView.transform = CGAffineTransformMakeRotation(-angleToRotate);
273 | }
274 |
275 | #pragma mark Letting go of the scroll view, checking for refresh trigger
276 |
277 | - (void)scrollViewDidEndDragging
278 | {
279 | if(state == BOZPongRefreshControlStateIdle) {
280 | if([self didUserScrollFarEnoughToTriggerRefresh]) {
281 | [self beginLoading];
282 | [self notifyTargetOfRefreshTrigger];
283 | }
284 | }
285 | }
286 |
287 | - (BOOL)didUserScrollFarEnoughToTriggerRefresh
288 | {
289 | return (-self.distanceScrolled > REFRESH_CONTROL_HEIGHT);
290 | }
291 |
292 | - (void)notifyTargetOfRefreshTrigger
293 | {
294 | #pragma clang diagnostic push
295 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
296 |
297 | if ([self.refreshTarget respondsToSelector:self.refreshAction])
298 | [self.refreshTarget performSelector:self.refreshAction];
299 |
300 | #pragma clang diagnostic pop
301 | }
302 |
303 | #pragma mark - Manually starting a refresh
304 |
305 | - (void)beginLoading
306 | {
307 | [self beginLoadingAnimated:YES];
308 | }
309 |
310 | - (void)beginLoadingAnimated:(BOOL)animated
311 | {
312 | if (state != BOZPongRefreshControlStateRefreshing) {
313 | state = BOZPongRefreshControlStateRefreshing;
314 |
315 | [self scrollRefreshControlToVisibleAnimated:animated];
316 | [self startPong];
317 | }
318 | }
319 |
320 | - (void)scrollRefreshControlToVisibleAnimated:(BOOL)animated
321 | {
322 | CGFloat animationDuration = 0.0f;
323 | if(animated) {
324 | animationDuration = TRANSITION_ANIMATION_DURATION;
325 | }
326 |
327 |
328 | UIEdgeInsets newInsets = self.scrollView.contentInset;
329 | newInsets.top = originalTopContentInset + REFRESH_CONTROL_HEIGHT;
330 | CGPoint contentOffset = self.scrollView.contentOffset;
331 |
332 | [UIView animateWithDuration:animationDuration animations:^(void) {
333 | self.scrollView.contentInset = newInsets;
334 | self.scrollView.contentOffset = contentOffset;
335 | }];
336 | }
337 |
338 | #pragma mark - Resetting after loading finished
339 |
340 | - (void)finishedLoading
341 | {
342 | if(state != BOZPongRefreshControlStateRefreshing) {
343 | return;
344 | }
345 |
346 | state = BOZPongRefreshControlStateResetting;
347 |
348 | [UIView animateWithDuration:TRANSITION_ANIMATION_DURATION animations:^(void)
349 | {
350 | [self resetScrollViewContentInsets];
351 | [self setHeightAndOffsetOfRefreshControl:0.0f];
352 | }
353 | completion:^(BOOL finished)
354 | {
355 | [self resetPaddlesAndBall];
356 | state = BOZPongRefreshControlStateIdle;
357 | }];
358 | }
359 |
360 | - (void)resetScrollViewContentInsets
361 | {
362 | UIEdgeInsets newInsets = self.scrollView.contentInset;
363 | newInsets.top = originalTopContentInset;
364 | self.scrollView.contentInset = newInsets;
365 | }
366 |
367 | - (void)resetPaddlesAndBall
368 | {
369 | [self removeAnimations];
370 |
371 | leftPaddleView.center = leftPaddleIdleOrigin;
372 | rightPaddleView.center = rightPaddleIdleOrigin;
373 | ballView.center = ballIdleOrigin;
374 | }
375 |
376 | - (void)removeAnimations
377 | {
378 | [leftPaddleView.layer removeAllAnimations];
379 | [rightPaddleView.layer removeAllAnimations];
380 | [ballView.layer removeAllAnimations];
381 | }
382 |
383 | #pragma mark - Playing pong
384 |
385 | #pragma mark Starting the game
386 |
387 | - (void)startPong
388 | {
389 | ballOrigin = ballView.center;
390 | leftPaddleOrigin = leftPaddleIdleOrigin.y;
391 | rightPaddleOrigin = rightPaddleIdleOrigin.y;
392 |
393 | [self pickRandomStartingBallDestination];
394 | [self determineNextPaddleDestinations];
395 | [self animateBallAndPaddlesToDestinations];
396 | }
397 |
398 | - (void)pickRandomStartingBallDestination
399 | {
400 | CGFloat destinationX = [self leftPaddleContactX];
401 | if(arc4random() % 2 == 1) {
402 | destinationX = [self rightPaddleContactX];
403 | }
404 | CGFloat destinationY = (float)(arc4random() % (int)gameView.frame.size.height);
405 |
406 | ballDestination = CGPointMake(destinationX, destinationY);
407 | ballDirection = CGPointMake((ballDestination.x - ballOrigin.x), (ballDestination.y - ballOrigin.y));
408 | ballDirection = [self normalizeVector:ballDirection];
409 | }
410 |
411 | #pragma mark Playing the game
412 |
413 | #pragma mark Ball behavior
414 |
415 | - (void)determineNextBallDestination
416 | {
417 | CGFloat newBallDestinationX;
418 | CGFloat newBallDestinationY;
419 |
420 | ballDirection = [self determineReflectedDirectionOfBall];
421 |
422 | CGFloat verticalDistanceToNextWall = [self calculateVerticalDistanceFromBallToNextWall];
423 | CGFloat distanceToNextWall = verticalDistanceToNextWall / ballDirection.y;
424 | CGFloat horizontalDistanceToNextWall = distanceToNextWall * ballDirection.x;
425 |
426 | CGFloat horizontalDistanceToNextPaddle = [self calculateHorizontalDistanceFromBallToNextPaddle];
427 |
428 | if(fabs(horizontalDistanceToNextPaddle) < fabs(horizontalDistanceToNextWall)) {
429 | newBallDestinationX = ballDestination.x + horizontalDistanceToNextPaddle;
430 |
431 | CGFloat verticalDistanceToNextPaddle = fabs(horizontalDistanceToNextPaddle) * ballDirection.y;
432 | newBallDestinationY = ballDestination.y + verticalDistanceToNextPaddle;
433 | } else {
434 | newBallDestinationX = ballDestination.x + horizontalDistanceToNextWall;
435 | newBallDestinationY = ballDestination.y + verticalDistanceToNextWall;
436 | }
437 |
438 | ballOrigin = ballDestination;
439 | ballDestination = CGPointMake(newBallDestinationX, newBallDestinationY);
440 | }
441 |
442 | - (CGPoint)determineReflectedDirectionOfBall
443 | {
444 | CGPoint reflectedBallDirection = ballDirection;
445 |
446 | if([self didBallHitWall]) {
447 | reflectedBallDirection = CGPointMake(ballDirection.x, -ballDirection.y);
448 | } else if([self didBallHitPaddle]) {
449 | reflectedBallDirection = CGPointMake(-ballDirection.x, ballDirection.y);
450 | }
451 |
452 | return reflectedBallDirection;
453 | }
454 |
455 | - (BOOL)didBallHitWall
456 | {
457 | return ([self isFloat:ballDestination.y equalToFloat:[self ceilingContactY]] || [self isFloat:ballDestination.y equalToFloat:[self floorContactY]]);
458 | }
459 |
460 | - (BOOL)didBallHitPaddle
461 | {
462 | return ([self isFloat:ballDestination.x equalToFloat:[self leftPaddleContactX]] || [self isFloat:ballDestination.x equalToFloat:[self rightPaddleContactX]]);
463 | }
464 |
465 | - (CGFloat)calculateVerticalDistanceFromBallToNextWall
466 | {
467 | if(ballDirection.y > 0.0f) {
468 | return [self floorContactY] - ballDestination.y;
469 | } else {
470 | return [self ceilingContactY] - ballDestination.y;
471 | }
472 | }
473 |
474 | - (CGFloat)calculateHorizontalDistanceFromBallToNextPaddle
475 | {
476 | if(ballDirection.x < 0.0f) {
477 | return [self leftPaddleContactX] - ballDestination.x;
478 | } else {
479 | return [self rightPaddleContactX] - ballDestination.x;
480 | }
481 | }
482 |
483 | #pragma mark Paddle behavior
484 |
485 | - (void)determineNextPaddleDestinations
486 | {
487 | static CGFloat lazySpeedFactor = 0.25f;
488 | static CGFloat normalSpeedFactor = 0.5f;
489 | static CGFloat holyCrapSpeedFactor = 1.0f;
490 |
491 | CGFloat leftPaddleVerticalDistanceToBallDestination = ballDestination.y - leftPaddleView.center.y;
492 | CGFloat rightPaddleVerticalDistanceToBallDestination = ballDestination.y - rightPaddleView.center.y;
493 |
494 | CGFloat leftPaddleOffset;
495 | CGFloat rightPaddleOffset;
496 |
497 | //Determining how far each paddle will mode
498 | if(ballDirection.x < 0.0f) {
499 | //Ball is going toward the left paddle
500 |
501 | if([self isBallDestinationTheLeftPaddle]) {
502 | leftPaddleOffset = (leftPaddleVerticalDistanceToBallDestination * holyCrapSpeedFactor);
503 | rightPaddleOffset = (rightPaddleVerticalDistanceToBallDestination * lazySpeedFactor);
504 | } else {
505 | //Destination is a wall
506 | leftPaddleOffset = (leftPaddleVerticalDistanceToBallDestination * normalSpeedFactor);
507 | rightPaddleOffset = -(rightPaddleVerticalDistanceToBallDestination * normalSpeedFactor);
508 | }
509 | } else {
510 | //Ball is going toward the right paddle
511 |
512 | if([self isBallDestinationTheRightPaddle]) {
513 | leftPaddleOffset = (leftPaddleVerticalDistanceToBallDestination * lazySpeedFactor);
514 | rightPaddleOffset = (rightPaddleVerticalDistanceToBallDestination * holyCrapSpeedFactor);
515 | } else {
516 | //Destination is a wall
517 | leftPaddleOffset = -(leftPaddleVerticalDistanceToBallDestination * normalSpeedFactor);
518 | rightPaddleOffset = (rightPaddleVerticalDistanceToBallDestination * normalSpeedFactor);
519 | }
520 | }
521 | leftPaddleOrigin = leftPaddleDestination;
522 | rightPaddleOrigin = rightPaddleDestination;
523 | leftPaddleDestination = leftPaddleView.center.y + leftPaddleOffset;
524 | rightPaddleDestination = rightPaddleView.center.y + rightPaddleOffset;
525 |
526 | [self capPaddleDestinationsToWalls];
527 | }
528 |
529 | - (BOOL)isBallDestinationTheLeftPaddle
530 | {
531 | return ([self isFloat:ballDestination.x equalToFloat:[self leftPaddleContactX]]);
532 | }
533 |
534 | - (BOOL)isBallDestinationTheRightPaddle
535 | {
536 | return ([self isFloat:ballDestination.x equalToFloat:[self rightPaddleContactX]]);
537 | }
538 |
539 | - (void)capPaddleDestinationsToWalls
540 | {
541 | if(leftPaddleDestination < [self ceilingLeftPaddleContactY]) {
542 | leftPaddleDestination = [self ceilingLeftPaddleContactY];
543 | } else if(leftPaddleDestination > [self floorLeftPaddleContactY]) {
544 | leftPaddleDestination = [self floorLeftPaddleContactY];
545 | }
546 |
547 | if(rightPaddleDestination < [self ceilingRightPaddleContactY]) {
548 | rightPaddleDestination = [self ceilingRightPaddleContactY];
549 | } else if(rightPaddleDestination > [self floorRightPaddleContactY]) {
550 | rightPaddleDestination = [self floorRightPaddleContactY];
551 | }
552 | }
553 |
554 | #pragma mark Actually animating the balls and paddles to where they need to go
555 |
556 | - (void)animateBallAndPaddlesToDestinations
557 | {
558 | currentAnimationStartTime = [NSDate date];
559 | currentAnimationDuration = [self calculateAnimationDuration];
560 |
561 | [UIView animateWithDuration:currentAnimationDuration delay:0.0f options:UIViewAnimationOptionCurveLinear animations:^(void)
562 | {
563 | ballView.center = ballDestination;
564 | leftPaddleView.center = CGPointMake(leftPaddleView.center.x, leftPaddleDestination);
565 | rightPaddleView.center = CGPointMake(rightPaddleView.center.x, rightPaddleDestination);
566 | }
567 | completion:^(BOOL finished)
568 | {
569 | if(finished) {
570 | [self determineNextBallDestination];
571 | [self determineNextPaddleDestinations];
572 | [self animateBallAndPaddlesToDestinations];
573 | }
574 | }];
575 | }
576 |
577 | - (CGFloat)calculateAnimationDuration
578 | {
579 | CGFloat endToEndDistance = [self rightPaddleContactX] - [self leftPaddleContactX];
580 | CGFloat proportionOfHorizontalDistanceLeftForBallToTravel = fabsf((ballDestination.x - ballOrigin.x) / endToEndDistance);
581 | return (self.totalHorizontalTravelTimeForBall * proportionOfHorizontalDistanceLeftForBallToTravel);
582 | }
583 |
584 | #pragma mark Helper functions for collision detection
585 |
586 | #pragma mark Ball collisions
587 |
588 | - (CGFloat)leftPaddleContactX
589 | {
590 | return leftPaddleView.center.x + (ballView.frame.size.width / 2.0f);
591 | }
592 |
593 | - (CGFloat)rightPaddleContactX
594 | {
595 | return rightPaddleView.center.x - (ballView.frame.size.width / 2.0f);
596 | }
597 |
598 | - (CGFloat)ceilingContactY
599 | {
600 | return (ballView.frame.size.height / 2.0f);
601 | }
602 |
603 | - (CGFloat)floorContactY
604 | {
605 | return gameView.frame.size.height - (ballView.frame.size.height / 2.0f);
606 | }
607 |
608 | #pragma mark Paddle collisions
609 |
610 | - (CGFloat)ceilingLeftPaddleContactY
611 | {
612 | return (leftPaddleView.frame.size.height / 2.0f);
613 | }
614 |
615 | - (CGFloat)floorLeftPaddleContactY
616 | {
617 | return gameView.frame.size.height - (leftPaddleView.frame.size.height / 2.0f);
618 | }
619 |
620 | - (CGFloat)ceilingRightPaddleContactY
621 | {
622 | return (rightPaddleView.frame.size.height / 2.0f);
623 | }
624 |
625 | - (CGFloat)floorRightPaddleContactY
626 | {
627 | return gameView.frame.size.height - (rightPaddleView.frame.size.height / 2.0f);
628 | }
629 |
630 | #pragma mark - Handling orientation changes
631 |
632 | - (void)handleOrientationChange {
633 | self.frame = CGRectMake(0.0f, 0.0f, self.scrollView.frame.size.width, 0.0f);
634 | CGFloat gameViewWidthBeforeOrientationChange = gameView.frame.size.width;
635 | gameView.frame = CGRectMake(0.0f, 0.0f, self.frame.size.width, REFRESH_CONTROL_HEIGHT);
636 |
637 | originalTopContentInset = self.scrollView.contentInset.top;
638 |
639 | [self setUpGamePieceIdleOrigins];
640 |
641 | if(state == BOZPongRefreshControlStateRefreshing) {
642 | originalTopContentInset -= REFRESH_CONTROL_HEIGHT;
643 | [self setHeightAndOffsetOfRefreshControl:REFRESH_CONTROL_HEIGHT];
644 |
645 | [self removeAnimations];
646 | CGFloat horizontalScaleFactor = gameView.frame.size.width / gameViewWidthBeforeOrientationChange;
647 | [self setGamePiecePositionsForAnimationStop:horizontalScaleFactor];
648 |
649 | [self animateBallAndPaddlesToDestinations];
650 | } else {
651 | [self setGamePiecePositionsToIdle];
652 | }
653 | }
654 |
655 | - (void)setGamePiecePositionsForAnimationStop:(CGFloat)horizontalScaleFactor
656 | {
657 | //Place the game pieces as though the animation got cut off
658 |
659 | CGFloat timeSinceCurrentAnimationStarted = -[currentAnimationStartTime timeIntervalSinceNow];
660 | CGFloat proportionOfCurrentAnimationCompleted = timeSinceCurrentAnimationStarted / currentAnimationDuration;
661 |
662 | CGPoint totalBallDisplacementForCurrentAnimation = CGPointMake(ballDestination.x - ballOrigin.x, ballDestination.y - ballOrigin.y);
663 | CGFloat totalLeftPaddleDisplacementForCurrentAnimation = leftPaddleDestination - leftPaddleOrigin;
664 | CGFloat totalRightPaddleDisplacementForCurrentAnimation = rightPaddleDestination - rightPaddleOrigin;
665 |
666 | ballView.center = CGPointMake(ballOrigin.x + (totalBallDisplacementForCurrentAnimation.x * proportionOfCurrentAnimationCompleted),
667 | ballOrigin.y + (totalBallDisplacementForCurrentAnimation.y * proportionOfCurrentAnimationCompleted));
668 | leftPaddleView.center = CGPointMake(leftPaddleView.center.x,
669 | leftPaddleOrigin + (totalLeftPaddleDisplacementForCurrentAnimation * proportionOfCurrentAnimationCompleted));
670 | rightPaddleView.center = CGPointMake(rightPaddleView.center.x,
671 | rightPaddleOrigin + (totalRightPaddleDisplacementForCurrentAnimation * proportionOfCurrentAnimationCompleted));
672 |
673 | ballOrigin = ballView.center;
674 | leftPaddleOrigin = leftPaddleView.center.y;
675 | rightPaddleOrigin = rightPaddleView.center.y;
676 |
677 | //Now scale everything for the change in horizontal distance
678 |
679 | leftPaddleView.center = CGPointMake(leftPaddleView.center.x * horizontalScaleFactor, leftPaddleView.center.y);
680 | rightPaddleView.center = CGPointMake(rightPaddleView.center.x * horizontalScaleFactor, rightPaddleView.center.y);
681 |
682 | ballView.center = CGPointMake(ballView.center.x * horizontalScaleFactor, ballView.center.y);
683 | ballOrigin = CGPointMake(ballOrigin.x * horizontalScaleFactor, ballOrigin.y);
684 | ballDestination = CGPointMake(ballDestination.x * horizontalScaleFactor, ballDestination.y);
685 | ballDirection = [self normalizeVector:CGPointMake(ballDirection.x * horizontalScaleFactor, ballDirection.y)];
686 | }
687 |
688 | - (void)setGamePiecePositionsToIdle
689 | {
690 | leftPaddleView.center = leftPaddleIdleOrigin;
691 | rightPaddleView.center = rightPaddleIdleOrigin;
692 | ballView.center = ballIdleOrigin;
693 | }
694 |
695 | #pragma mark - Etc, some basic math functions
696 |
697 | - (CGPoint)normalizeVector:(CGPoint)vector
698 | {
699 | CGFloat magnitude = sqrtf(vector.x * vector.x + vector.y * vector.y);
700 | return CGPointMake(vector.x / magnitude, vector.y / magnitude);
701 | }
702 |
703 | - (BOOL)isFloat:(CGFloat)float1 equalToFloat:(CGFloat)float2
704 | {
705 | static CGFloat ellipsis = 0.01f;
706 |
707 | return (fabsf(float1 - float2) < ellipsis);
708 | }
709 |
710 | @end
711 |
--------------------------------------------------------------------------------
/PongRefreshControlDemo/PongRefreshControlDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | FBB15602185260B90072DCEC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBB15601185260B90072DCEC /* Foundation.framework */; };
11 | FBB15604185260B90072DCEC /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBB15603185260B90072DCEC /* CoreGraphics.framework */; };
12 | FBB15606185260B90072DCEC /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBB15605185260B90072DCEC /* UIKit.framework */; };
13 | FBB1560C185260B90072DCEC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FBB1560A185260B90072DCEC /* InfoPlist.strings */; };
14 | FBB1560E185260B90072DCEC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = FBB1560D185260B90072DCEC /* main.m */; };
15 | FBB15612185260B90072DCEC /* BOZAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FBB15611185260B90072DCEC /* BOZAppDelegate.m */; };
16 | FBB15614185260B90072DCEC /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FBB15613185260B90072DCEC /* Images.xcassets */; };
17 | FBB1561B185260B90072DCEC /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBB1561A185260B90072DCEC /* XCTest.framework */; };
18 | FBB1561C185260B90072DCEC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBB15601185260B90072DCEC /* Foundation.framework */; };
19 | FBB1561D185260B90072DCEC /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FBB15605185260B90072DCEC /* UIKit.framework */; };
20 | FBB15625185260B90072DCEC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FBB15623185260B90072DCEC /* InfoPlist.strings */; };
21 | FBB15627185260B90072DCEC /* PongRefreshControlDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = FBB15626185260B90072DCEC /* PongRefreshControlDemoTests.m */; };
22 | FBB15633185262A80072DCEC /* BOZPongRefreshControl.m in Sources */ = {isa = PBXBuildFile; fileRef = FBB15632185262A80072DCEC /* BOZPongRefreshControl.m */; };
23 | FBB15634185262A80072DCEC /* BOZPongRefreshControl.m in Sources */ = {isa = PBXBuildFile; fileRef = FBB15632185262A80072DCEC /* BOZPongRefreshControl.m */; };
24 | FBB1563F1852638D0072DCEC /* BOZDemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBB1563D1852638D0072DCEC /* BOZDemoViewController.m */; };
25 | FBB156401852638D0072DCEC /* BOZDemoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBB1563D1852638D0072DCEC /* BOZDemoViewController.m */; };
26 | FBB156441852C4EC0072DCEC /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FBB156431852C4EC0072DCEC /* Storyboard.storyboard */; };
27 | FBB156451852C4EC0072DCEC /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FBB156431852C4EC0072DCEC /* Storyboard.storyboard */; };
28 | FBB1564B1852D76C0072DCEC /* BOZNoNavBarViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBB156491852D76C0072DCEC /* BOZNoNavBarViewController.m */; };
29 | FBB1564C1852D76C0072DCEC /* BOZNoNavBarViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBB156491852D76C0072DCEC /* BOZNoNavBarViewController.m */; };
30 | FBB156521852F1280072DCEC /* BOZRegularViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBB156511852F1280072DCEC /* BOZRegularViewController.m */; };
31 | FBB156531852F1280072DCEC /* BOZRegularViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBB156511852F1280072DCEC /* BOZRegularViewController.m */; };
32 | FBB156571852F9BF0072DCEC /* BOZScrollViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBB156561852F9BF0072DCEC /* BOZScrollViewController.m */; };
33 | FBB156581852F9BF0072DCEC /* BOZScrollViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBB156561852F9BF0072DCEC /* BOZScrollViewController.m */; };
34 | /* End PBXBuildFile section */
35 |
36 | /* Begin PBXContainerItemProxy section */
37 | FBB1561E185260B90072DCEC /* PBXContainerItemProxy */ = {
38 | isa = PBXContainerItemProxy;
39 | containerPortal = FBB155F6185260B90072DCEC /* Project object */;
40 | proxyType = 1;
41 | remoteGlobalIDString = FBB155FD185260B90072DCEC;
42 | remoteInfo = PongRefreshControlDemo;
43 | };
44 | /* End PBXContainerItemProxy section */
45 |
46 | /* Begin PBXFileReference section */
47 | FBB155FE185260B90072DCEC /* PongRefreshControlDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PongRefreshControlDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
48 | FBB15601185260B90072DCEC /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
49 | FBB15603185260B90072DCEC /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
50 | FBB15605185260B90072DCEC /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
51 | FBB15609185260B90072DCEC /* PongRefreshControlDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "PongRefreshControlDemo-Info.plist"; sourceTree = ""; };
52 | FBB1560B185260B90072DCEC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
53 | FBB1560D185260B90072DCEC /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
54 | FBB1560F185260B90072DCEC /* PongRefreshControlDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PongRefreshControlDemo-Prefix.pch"; sourceTree = ""; };
55 | FBB15610185260B90072DCEC /* BOZAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BOZAppDelegate.h; sourceTree = ""; };
56 | FBB15611185260B90072DCEC /* BOZAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BOZAppDelegate.m; sourceTree = ""; };
57 | FBB15613185260B90072DCEC /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
58 | FBB15619185260B90072DCEC /* PongRefreshControlDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PongRefreshControlDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
59 | FBB1561A185260B90072DCEC /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
60 | FBB15622185260B90072DCEC /* PongRefreshControlDemoTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "PongRefreshControlDemoTests-Info.plist"; sourceTree = ""; };
61 | FBB15624185260B90072DCEC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
62 | FBB15626185260B90072DCEC /* PongRefreshControlDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PongRefreshControlDemoTests.m; sourceTree = ""; };
63 | FBB15631185262A80072DCEC /* BOZPongRefreshControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BOZPongRefreshControl.h; path = ../BOZPongRefreshControl/BOZPongRefreshControl.h; sourceTree = ""; };
64 | FBB15632185262A80072DCEC /* BOZPongRefreshControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BOZPongRefreshControl.m; path = ../BOZPongRefreshControl/BOZPongRefreshControl.m; sourceTree = ""; };
65 | FBB1563C1852638D0072DCEC /* BOZDemoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BOZDemoViewController.h; sourceTree = ""; };
66 | FBB1563D1852638D0072DCEC /* BOZDemoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BOZDemoViewController.m; sourceTree = ""; };
67 | FBB156431852C4EC0072DCEC /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; sourceTree = ""; };
68 | FBB156481852D76C0072DCEC /* BOZNoNavBarViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BOZNoNavBarViewController.h; sourceTree = ""; };
69 | FBB156491852D76C0072DCEC /* BOZNoNavBarViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BOZNoNavBarViewController.m; sourceTree = ""; };
70 | FBB156501852F1280072DCEC /* BOZRegularViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BOZRegularViewController.h; sourceTree = ""; };
71 | FBB156511852F1280072DCEC /* BOZRegularViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BOZRegularViewController.m; sourceTree = ""; };
72 | FBB156551852F9BF0072DCEC /* BOZScrollViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BOZScrollViewController.h; sourceTree = ""; };
73 | FBB156561852F9BF0072DCEC /* BOZScrollViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BOZScrollViewController.m; sourceTree = ""; };
74 | /* End PBXFileReference section */
75 |
76 | /* Begin PBXFrameworksBuildPhase section */
77 | FBB155FB185260B90072DCEC /* Frameworks */ = {
78 | isa = PBXFrameworksBuildPhase;
79 | buildActionMask = 2147483647;
80 | files = (
81 | FBB15604185260B90072DCEC /* CoreGraphics.framework in Frameworks */,
82 | FBB15606185260B90072DCEC /* UIKit.framework in Frameworks */,
83 | FBB15602185260B90072DCEC /* Foundation.framework in Frameworks */,
84 | );
85 | runOnlyForDeploymentPostprocessing = 0;
86 | };
87 | FBB15616185260B90072DCEC /* Frameworks */ = {
88 | isa = PBXFrameworksBuildPhase;
89 | buildActionMask = 2147483647;
90 | files = (
91 | FBB1561B185260B90072DCEC /* XCTest.framework in Frameworks */,
92 | FBB1561D185260B90072DCEC /* UIKit.framework in Frameworks */,
93 | FBB1561C185260B90072DCEC /* Foundation.framework in Frameworks */,
94 | );
95 | runOnlyForDeploymentPostprocessing = 0;
96 | };
97 | /* End PBXFrameworksBuildPhase section */
98 |
99 | /* Begin PBXGroup section */
100 | FBB155F5185260B90072DCEC = {
101 | isa = PBXGroup;
102 | children = (
103 | FBB15630185262900072DCEC /* BOZPongRefreshControl */,
104 | FBB15607185260B90072DCEC /* PongRefreshControlDemo */,
105 | FBB15620185260B90072DCEC /* PongRefreshControlDemoTests */,
106 | FBB15600185260B90072DCEC /* Frameworks */,
107 | FBB155FF185260B90072DCEC /* Products */,
108 | );
109 | sourceTree = "";
110 | };
111 | FBB155FF185260B90072DCEC /* Products */ = {
112 | isa = PBXGroup;
113 | children = (
114 | FBB155FE185260B90072DCEC /* PongRefreshControlDemo.app */,
115 | FBB15619185260B90072DCEC /* PongRefreshControlDemoTests.xctest */,
116 | );
117 | name = Products;
118 | sourceTree = "";
119 | };
120 | FBB15600185260B90072DCEC /* Frameworks */ = {
121 | isa = PBXGroup;
122 | children = (
123 | FBB15601185260B90072DCEC /* Foundation.framework */,
124 | FBB15603185260B90072DCEC /* CoreGraphics.framework */,
125 | FBB15605185260B90072DCEC /* UIKit.framework */,
126 | FBB1561A185260B90072DCEC /* XCTest.framework */,
127 | );
128 | name = Frameworks;
129 | sourceTree = "";
130 | };
131 | FBB15607185260B90072DCEC /* PongRefreshControlDemo */ = {
132 | isa = PBXGroup;
133 | children = (
134 | FBB15610185260B90072DCEC /* BOZAppDelegate.h */,
135 | FBB15611185260B90072DCEC /* BOZAppDelegate.m */,
136 | FBB156431852C4EC0072DCEC /* Storyboard.storyboard */,
137 | FBB156461852D73A0072DCEC /* Demo View Controller */,
138 | FBB156541852F9AE0072DCEC /* Scroll View Controller */,
139 | FBB1564F1852F1110072DCEC /* Regular View Controller */,
140 | FBB156471852D7500072DCEC /* No Nav Bar View Controller */,
141 | FBB15613185260B90072DCEC /* Images.xcassets */,
142 | FBB15608185260B90072DCEC /* Supporting Files */,
143 | );
144 | path = PongRefreshControlDemo;
145 | sourceTree = "";
146 | };
147 | FBB15608185260B90072DCEC /* Supporting Files */ = {
148 | isa = PBXGroup;
149 | children = (
150 | FBB15609185260B90072DCEC /* PongRefreshControlDemo-Info.plist */,
151 | FBB1560A185260B90072DCEC /* InfoPlist.strings */,
152 | FBB1560D185260B90072DCEC /* main.m */,
153 | FBB1560F185260B90072DCEC /* PongRefreshControlDemo-Prefix.pch */,
154 | );
155 | name = "Supporting Files";
156 | sourceTree = "";
157 | };
158 | FBB15620185260B90072DCEC /* PongRefreshControlDemoTests */ = {
159 | isa = PBXGroup;
160 | children = (
161 | FBB15626185260B90072DCEC /* PongRefreshControlDemoTests.m */,
162 | FBB15621185260B90072DCEC /* Supporting Files */,
163 | );
164 | path = PongRefreshControlDemoTests;
165 | sourceTree = "";
166 | };
167 | FBB15621185260B90072DCEC /* Supporting Files */ = {
168 | isa = PBXGroup;
169 | children = (
170 | FBB15622185260B90072DCEC /* PongRefreshControlDemoTests-Info.plist */,
171 | FBB15623185260B90072DCEC /* InfoPlist.strings */,
172 | );
173 | name = "Supporting Files";
174 | sourceTree = "";
175 | };
176 | FBB15630185262900072DCEC /* BOZPongRefreshControl */ = {
177 | isa = PBXGroup;
178 | children = (
179 | FBB15631185262A80072DCEC /* BOZPongRefreshControl.h */,
180 | FBB15632185262A80072DCEC /* BOZPongRefreshControl.m */,
181 | );
182 | name = BOZPongRefreshControl;
183 | sourceTree = "";
184 | };
185 | FBB156461852D73A0072DCEC /* Demo View Controller */ = {
186 | isa = PBXGroup;
187 | children = (
188 | FBB1563C1852638D0072DCEC /* BOZDemoViewController.h */,
189 | FBB1563D1852638D0072DCEC /* BOZDemoViewController.m */,
190 | );
191 | name = "Demo View Controller";
192 | sourceTree = "";
193 | };
194 | FBB156471852D7500072DCEC /* No Nav Bar View Controller */ = {
195 | isa = PBXGroup;
196 | children = (
197 | FBB156481852D76C0072DCEC /* BOZNoNavBarViewController.h */,
198 | FBB156491852D76C0072DCEC /* BOZNoNavBarViewController.m */,
199 | );
200 | name = "No Nav Bar View Controller";
201 | sourceTree = "";
202 | };
203 | FBB1564F1852F1110072DCEC /* Regular View Controller */ = {
204 | isa = PBXGroup;
205 | children = (
206 | FBB156501852F1280072DCEC /* BOZRegularViewController.h */,
207 | FBB156511852F1280072DCEC /* BOZRegularViewController.m */,
208 | );
209 | name = "Regular View Controller";
210 | sourceTree = "";
211 | };
212 | FBB156541852F9AE0072DCEC /* Scroll View Controller */ = {
213 | isa = PBXGroup;
214 | children = (
215 | FBB156551852F9BF0072DCEC /* BOZScrollViewController.h */,
216 | FBB156561852F9BF0072DCEC /* BOZScrollViewController.m */,
217 | );
218 | name = "Scroll View Controller";
219 | sourceTree = "";
220 | };
221 | /* End PBXGroup section */
222 |
223 | /* Begin PBXNativeTarget section */
224 | FBB155FD185260B90072DCEC /* PongRefreshControlDemo */ = {
225 | isa = PBXNativeTarget;
226 | buildConfigurationList = FBB1562A185260B90072DCEC /* Build configuration list for PBXNativeTarget "PongRefreshControlDemo" */;
227 | buildPhases = (
228 | FBB155FA185260B90072DCEC /* Sources */,
229 | FBB155FB185260B90072DCEC /* Frameworks */,
230 | FBB155FC185260B90072DCEC /* Resources */,
231 | );
232 | buildRules = (
233 | );
234 | dependencies = (
235 | );
236 | name = PongRefreshControlDemo;
237 | productName = PongRefreshControlDemo;
238 | productReference = FBB155FE185260B90072DCEC /* PongRefreshControlDemo.app */;
239 | productType = "com.apple.product-type.application";
240 | };
241 | FBB15618185260B90072DCEC /* PongRefreshControlDemoTests */ = {
242 | isa = PBXNativeTarget;
243 | buildConfigurationList = FBB1562D185260B90072DCEC /* Build configuration list for PBXNativeTarget "PongRefreshControlDemoTests" */;
244 | buildPhases = (
245 | FBB15615185260B90072DCEC /* Sources */,
246 | FBB15616185260B90072DCEC /* Frameworks */,
247 | FBB15617185260B90072DCEC /* Resources */,
248 | );
249 | buildRules = (
250 | );
251 | dependencies = (
252 | FBB1561F185260B90072DCEC /* PBXTargetDependency */,
253 | );
254 | name = PongRefreshControlDemoTests;
255 | productName = PongRefreshControlDemoTests;
256 | productReference = FBB15619185260B90072DCEC /* PongRefreshControlDemoTests.xctest */;
257 | productType = "com.apple.product-type.bundle.unit-test";
258 | };
259 | /* End PBXNativeTarget section */
260 |
261 | /* Begin PBXProject section */
262 | FBB155F6185260B90072DCEC /* Project object */ = {
263 | isa = PBXProject;
264 | attributes = {
265 | CLASSPREFIX = BOZ;
266 | LastUpgradeCheck = 0600;
267 | ORGANIZATIONNAME = "Ben Oztalay";
268 | TargetAttributes = {
269 | FBB15618185260B90072DCEC = {
270 | TestTargetID = FBB155FD185260B90072DCEC;
271 | };
272 | };
273 | };
274 | buildConfigurationList = FBB155F9185260B90072DCEC /* Build configuration list for PBXProject "PongRefreshControlDemo" */;
275 | compatibilityVersion = "Xcode 3.2";
276 | developmentRegion = English;
277 | hasScannedForEncodings = 0;
278 | knownRegions = (
279 | en,
280 | );
281 | mainGroup = FBB155F5185260B90072DCEC;
282 | productRefGroup = FBB155FF185260B90072DCEC /* Products */;
283 | projectDirPath = "";
284 | projectRoot = "";
285 | targets = (
286 | FBB155FD185260B90072DCEC /* PongRefreshControlDemo */,
287 | FBB15618185260B90072DCEC /* PongRefreshControlDemoTests */,
288 | );
289 | };
290 | /* End PBXProject section */
291 |
292 | /* Begin PBXResourcesBuildPhase section */
293 | FBB155FC185260B90072DCEC /* Resources */ = {
294 | isa = PBXResourcesBuildPhase;
295 | buildActionMask = 2147483647;
296 | files = (
297 | FBB1560C185260B90072DCEC /* InfoPlist.strings in Resources */,
298 | FBB15614185260B90072DCEC /* Images.xcassets in Resources */,
299 | FBB156441852C4EC0072DCEC /* Storyboard.storyboard in Resources */,
300 | );
301 | runOnlyForDeploymentPostprocessing = 0;
302 | };
303 | FBB15617185260B90072DCEC /* Resources */ = {
304 | isa = PBXResourcesBuildPhase;
305 | buildActionMask = 2147483647;
306 | files = (
307 | FBB15625185260B90072DCEC /* InfoPlist.strings in Resources */,
308 | FBB156451852C4EC0072DCEC /* Storyboard.storyboard in Resources */,
309 | );
310 | runOnlyForDeploymentPostprocessing = 0;
311 | };
312 | /* End PBXResourcesBuildPhase section */
313 |
314 | /* Begin PBXSourcesBuildPhase section */
315 | FBB155FA185260B90072DCEC /* Sources */ = {
316 | isa = PBXSourcesBuildPhase;
317 | buildActionMask = 2147483647;
318 | files = (
319 | FBB15612185260B90072DCEC /* BOZAppDelegate.m in Sources */,
320 | FBB1563F1852638D0072DCEC /* BOZDemoViewController.m in Sources */,
321 | FBB1564B1852D76C0072DCEC /* BOZNoNavBarViewController.m in Sources */,
322 | FBB156571852F9BF0072DCEC /* BOZScrollViewController.m in Sources */,
323 | FBB156521852F1280072DCEC /* BOZRegularViewController.m in Sources */,
324 | FBB1560E185260B90072DCEC /* main.m in Sources */,
325 | FBB15633185262A80072DCEC /* BOZPongRefreshControl.m in Sources */,
326 | );
327 | runOnlyForDeploymentPostprocessing = 0;
328 | };
329 | FBB15615185260B90072DCEC /* Sources */ = {
330 | isa = PBXSourcesBuildPhase;
331 | buildActionMask = 2147483647;
332 | files = (
333 | FBB15634185262A80072DCEC /* BOZPongRefreshControl.m in Sources */,
334 | FBB156401852638D0072DCEC /* BOZDemoViewController.m in Sources */,
335 | FBB15627185260B90072DCEC /* PongRefreshControlDemoTests.m in Sources */,
336 | FBB156531852F1280072DCEC /* BOZRegularViewController.m in Sources */,
337 | FBB1564C1852D76C0072DCEC /* BOZNoNavBarViewController.m in Sources */,
338 | FBB156581852F9BF0072DCEC /* BOZScrollViewController.m in Sources */,
339 | );
340 | runOnlyForDeploymentPostprocessing = 0;
341 | };
342 | /* End PBXSourcesBuildPhase section */
343 |
344 | /* Begin PBXTargetDependency section */
345 | FBB1561F185260B90072DCEC /* PBXTargetDependency */ = {
346 | isa = PBXTargetDependency;
347 | target = FBB155FD185260B90072DCEC /* PongRefreshControlDemo */;
348 | targetProxy = FBB1561E185260B90072DCEC /* PBXContainerItemProxy */;
349 | };
350 | /* End PBXTargetDependency section */
351 |
352 | /* Begin PBXVariantGroup section */
353 | FBB1560A185260B90072DCEC /* InfoPlist.strings */ = {
354 | isa = PBXVariantGroup;
355 | children = (
356 | FBB1560B185260B90072DCEC /* en */,
357 | );
358 | name = InfoPlist.strings;
359 | sourceTree = "";
360 | };
361 | FBB15623185260B90072DCEC /* InfoPlist.strings */ = {
362 | isa = PBXVariantGroup;
363 | children = (
364 | FBB15624185260B90072DCEC /* en */,
365 | );
366 | name = InfoPlist.strings;
367 | sourceTree = "";
368 | };
369 | /* End PBXVariantGroup section */
370 |
371 | /* Begin XCBuildConfiguration section */
372 | FBB15628185260B90072DCEC /* Debug */ = {
373 | isa = XCBuildConfiguration;
374 | buildSettings = {
375 | ALWAYS_SEARCH_USER_PATHS = NO;
376 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
377 | CLANG_CXX_LIBRARY = "libc++";
378 | CLANG_ENABLE_MODULES = YES;
379 | CLANG_ENABLE_OBJC_ARC = YES;
380 | CLANG_WARN_BOOL_CONVERSION = YES;
381 | CLANG_WARN_CONSTANT_CONVERSION = YES;
382 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
383 | CLANG_WARN_EMPTY_BODY = YES;
384 | CLANG_WARN_ENUM_CONVERSION = YES;
385 | CLANG_WARN_INT_CONVERSION = YES;
386 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
387 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
388 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
389 | COPY_PHASE_STRIP = NO;
390 | GCC_C_LANGUAGE_STANDARD = gnu99;
391 | GCC_DYNAMIC_NO_PIC = NO;
392 | GCC_OPTIMIZATION_LEVEL = 0;
393 | GCC_PREPROCESSOR_DEFINITIONS = (
394 | "DEBUG=1",
395 | "$(inherited)",
396 | );
397 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
398 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
399 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
400 | GCC_WARN_UNDECLARED_SELECTOR = YES;
401 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
402 | GCC_WARN_UNUSED_FUNCTION = YES;
403 | GCC_WARN_UNUSED_VARIABLE = YES;
404 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
405 | ONLY_ACTIVE_ARCH = YES;
406 | SDKROOT = iphoneos;
407 | };
408 | name = Debug;
409 | };
410 | FBB15629185260B90072DCEC /* Release */ = {
411 | isa = XCBuildConfiguration;
412 | buildSettings = {
413 | ALWAYS_SEARCH_USER_PATHS = NO;
414 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
415 | CLANG_CXX_LIBRARY = "libc++";
416 | CLANG_ENABLE_MODULES = YES;
417 | CLANG_ENABLE_OBJC_ARC = YES;
418 | CLANG_WARN_BOOL_CONVERSION = YES;
419 | CLANG_WARN_CONSTANT_CONVERSION = YES;
420 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
421 | CLANG_WARN_EMPTY_BODY = YES;
422 | CLANG_WARN_ENUM_CONVERSION = YES;
423 | CLANG_WARN_INT_CONVERSION = YES;
424 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
425 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
426 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
427 | COPY_PHASE_STRIP = YES;
428 | ENABLE_NS_ASSERTIONS = NO;
429 | GCC_C_LANGUAGE_STANDARD = gnu99;
430 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
431 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
432 | GCC_WARN_UNDECLARED_SELECTOR = YES;
433 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
434 | GCC_WARN_UNUSED_FUNCTION = YES;
435 | GCC_WARN_UNUSED_VARIABLE = YES;
436 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
437 | SDKROOT = iphoneos;
438 | VALIDATE_PRODUCT = YES;
439 | };
440 | name = Release;
441 | };
442 | FBB1562B185260B90072DCEC /* Debug */ = {
443 | isa = XCBuildConfiguration;
444 | buildSettings = {
445 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
446 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
447 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
448 | GCC_PREFIX_HEADER = "PongRefreshControlDemo/PongRefreshControlDemo-Prefix.pch";
449 | INFOPLIST_FILE = "PongRefreshControlDemo/PongRefreshControlDemo-Info.plist";
450 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
451 | PRODUCT_NAME = "$(TARGET_NAME)";
452 | WRAPPER_EXTENSION = app;
453 | };
454 | name = Debug;
455 | };
456 | FBB1562C185260B90072DCEC /* Release */ = {
457 | isa = XCBuildConfiguration;
458 | buildSettings = {
459 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
460 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
461 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
462 | GCC_PREFIX_HEADER = "PongRefreshControlDemo/PongRefreshControlDemo-Prefix.pch";
463 | INFOPLIST_FILE = "PongRefreshControlDemo/PongRefreshControlDemo-Info.plist";
464 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
465 | PRODUCT_NAME = "$(TARGET_NAME)";
466 | WRAPPER_EXTENSION = app;
467 | };
468 | name = Release;
469 | };
470 | FBB1562E185260B90072DCEC /* Debug */ = {
471 | isa = XCBuildConfiguration;
472 | buildSettings = {
473 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/PongRefreshControlDemo.app/PongRefreshControlDemo";
474 | FRAMEWORK_SEARCH_PATHS = (
475 | "$(SDKROOT)/Developer/Library/Frameworks",
476 | "$(inherited)",
477 | "$(DEVELOPER_FRAMEWORKS_DIR)",
478 | );
479 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
480 | GCC_PREFIX_HEADER = "PongRefreshControlDemo/PongRefreshControlDemo-Prefix.pch";
481 | GCC_PREPROCESSOR_DEFINITIONS = (
482 | "DEBUG=1",
483 | "$(inherited)",
484 | );
485 | INFOPLIST_FILE = "PongRefreshControlDemoTests/PongRefreshControlDemoTests-Info.plist";
486 | PRODUCT_NAME = "$(TARGET_NAME)";
487 | TEST_HOST = "$(BUNDLE_LOADER)";
488 | WRAPPER_EXTENSION = xctest;
489 | };
490 | name = Debug;
491 | };
492 | FBB1562F185260B90072DCEC /* Release */ = {
493 | isa = XCBuildConfiguration;
494 | buildSettings = {
495 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/PongRefreshControlDemo.app/PongRefreshControlDemo";
496 | FRAMEWORK_SEARCH_PATHS = (
497 | "$(SDKROOT)/Developer/Library/Frameworks",
498 | "$(inherited)",
499 | "$(DEVELOPER_FRAMEWORKS_DIR)",
500 | );
501 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
502 | GCC_PREFIX_HEADER = "PongRefreshControlDemo/PongRefreshControlDemo-Prefix.pch";
503 | INFOPLIST_FILE = "PongRefreshControlDemoTests/PongRefreshControlDemoTests-Info.plist";
504 | PRODUCT_NAME = "$(TARGET_NAME)";
505 | TEST_HOST = "$(BUNDLE_LOADER)";
506 | WRAPPER_EXTENSION = xctest;
507 | };
508 | name = Release;
509 | };
510 | /* End XCBuildConfiguration section */
511 |
512 | /* Begin XCConfigurationList section */
513 | FBB155F9185260B90072DCEC /* Build configuration list for PBXProject "PongRefreshControlDemo" */ = {
514 | isa = XCConfigurationList;
515 | buildConfigurations = (
516 | FBB15628185260B90072DCEC /* Debug */,
517 | FBB15629185260B90072DCEC /* Release */,
518 | );
519 | defaultConfigurationIsVisible = 0;
520 | defaultConfigurationName = Release;
521 | };
522 | FBB1562A185260B90072DCEC /* Build configuration list for PBXNativeTarget "PongRefreshControlDemo" */ = {
523 | isa = XCConfigurationList;
524 | buildConfigurations = (
525 | FBB1562B185260B90072DCEC /* Debug */,
526 | FBB1562C185260B90072DCEC /* Release */,
527 | );
528 | defaultConfigurationIsVisible = 0;
529 | defaultConfigurationName = Release;
530 | };
531 | FBB1562D185260B90072DCEC /* Build configuration list for PBXNativeTarget "PongRefreshControlDemoTests" */ = {
532 | isa = XCConfigurationList;
533 | buildConfigurations = (
534 | FBB1562E185260B90072DCEC /* Debug */,
535 | FBB1562F185260B90072DCEC /* Release */,
536 | );
537 | defaultConfigurationIsVisible = 0;
538 | defaultConfigurationName = Release;
539 | };
540 | /* End XCConfigurationList section */
541 | };
542 | rootObject = FBB155F6185260B90072DCEC /* Project object */;
543 | }
544 |
--------------------------------------------------------------------------------