├── animation.gif
├── ExampleImage.png
├── PXAlertViewDemo
├── en.lproj
│ ├── InfoPlist.strings
│ └── Main.storyboard
├── PXAppDelegate.h
├── main.m
├── PXAlertViewDemo-Prefix.pch
├── PXViewController.h
├── Images.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── LaunchImage.launchimage
│ │ └── Contents.json
├── PXAlertViewDemo-Info.plist
├── LaunchScreen.storyboard
├── PXAppDelegate.m
└── PXViewController.m
├── PXAlertViewDemoTests
├── en.lproj
│ └── InfoPlist.strings
├── PXAlertViewDemoTests-Info.plist
└── PXAlertViewDemoTests.m
├── PXAlertViewDemo.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcuserdata
│ └── alex.xcuserdatad
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── PXAlertViewDemo.xcscheme
└── project.pbxproj
├── .gitignore
├── Classes
├── UIAlertView+PXAlertViewOverride.h
├── PXAlertView+Customization.h
├── PXAlertView.h
├── PXAlertView+Customization.m
├── UIAlertView+PXAlertViewOverride.m
└── PXAlertView.m
├── PXAlertView.podspec
├── LICENSE
└── README.md
/animation.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexanderjarvis/PXAlertView/HEAD/animation.gif
--------------------------------------------------------------------------------
/ExampleImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexanderjarvis/PXAlertView/HEAD/ExampleImage.png
--------------------------------------------------------------------------------
/PXAlertViewDemo/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/PXAlertViewDemoTests/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/PXAlertViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | # Xcode
3 | build/*
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | *.xcworkspace
13 | !default.xcworkspace
14 | xcuserdata
15 | profile
16 | *.moved-aside
17 |
--------------------------------------------------------------------------------
/PXAlertViewDemo/PXAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // PXAppDelegate.h
3 | // PXAlertViewDemo
4 | //
5 | // Created by Alex Jarvis on 25/09/2013.
6 | // Copyright (c) 2013 Panaxiom Ltd. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface PXAppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/PXAlertViewDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // PXAlertViewDemo
4 | //
5 | // Created by Alex Jarvis on 25/09/2013.
6 | // Copyright (c) 2013 panaxiom. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "PXAppDelegate.h"
12 |
13 | int main(int argc, char * argv[])
14 | {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([PXAppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/PXAlertViewDemo/PXAlertViewDemo-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_5_0
10 | #warning "This project uses features only available in iOS SDK 5.0 and later."
11 | #endif
12 |
13 | #ifdef __OBJC__
14 | #import
15 | #import
16 | #endif
17 |
--------------------------------------------------------------------------------
/Classes/UIAlertView+PXAlertViewOverride.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIAlertView+PXAlertViewOverride.h
3 | // PXAlertView
4 | //
5 | // Created by Bryan Way on 18/09/2014.
6 | //
7 |
8 | // Uncomment next line to enable automatic implementation or define PXALERT_SWIZZLING globally
9 | //#define PXALERT_SWIZZLING
10 |
11 | #ifdef PXALERT_SWIZZLING
12 |
13 | #import "PXAlertView.h"
14 | #import
15 |
16 | @interface UIAlertView (PXAlertViewOverride)
17 |
18 | -(void)showWithContent:(UIView*)contentView;
19 |
20 | @end
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/PXAlertViewDemo.xcodeproj/xcuserdata/alex.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | PXAlertViewDemo.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | FA11B67D17F3867100236222
16 |
17 | primary
18 |
19 |
20 | FA11B6A117F3867100236222
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/PXAlertViewDemo/PXViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // PXViewController.h
3 | // PXAlertViewDemo
4 | //
5 | // Created by Alex Jarvis on 25/09/2013.
6 | // Copyright (c) 2013 Panaxiom Ltd. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "PXAlertView.h"
12 |
13 | @interface PXViewController : UIViewController
14 |
15 | - (IBAction)showSimpleAlertView:(id)sender;
16 | - (IBAction)showLargeAlertView:(id)sender;
17 | - (IBAction)showTwoButtonAlertView:(id)sender;
18 | - (IBAction)showMultiButtonAlertView:(id)sender;
19 | - (IBAction)showAlertViewWithContentView:(id)sender;
20 | - (IBAction)show5StackedAlertViews:(id)sender;
21 | - (IBAction)showAlertInsideAlertCompletion:(id)sender;
22 |
23 | - (IBAction)showLargeUIAlertView:(id)sender;
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/PXAlertView.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'PXAlertView'
3 | s.version = '0.1.1'
4 | s.summary = 'A drop-in replacement for UIAlertView that is more customisable and skinnable'
5 | s.description = 'PXAlertView is a UIAlertView replacement similar to the style in iOS 7 but with a block based API and the ability to customise the styling and add custom views.'
6 | s.homepage = 'https://github.com/alexanderjarvis/PXAlertView'
7 | s.license = {:type => 'MIT', :file => 'LICENSE'}
8 | s.author = {'Alexander Jarvis' => 'alex@panaxiom.co.uk'}
9 | s.source = {:git => 'https://github.com/alexanderjarvis/PXAlertView.git', :tag => s.version.to_s}
10 | s.platform = :ios, '5.0'
11 | s.source_files = 'Classes', 'Classes/**/*.{h,m}'
12 | s.requires_arc = true
13 | end
14 |
--------------------------------------------------------------------------------
/PXAlertViewDemoTests/PXAlertViewDemoTests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/PXAlertViewDemoTests/PXAlertViewDemoTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // PXAlertViewDemoTests.m
3 | // PXAlertViewDemoTests
4 | //
5 | // Created by Alex Jarvis on 25/09/2013.
6 | // Copyright (c) 2013 panaxiom. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface PXAlertViewDemoTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation PXAlertViewDemoTests
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 |
--------------------------------------------------------------------------------
/PXAlertViewDemo/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 | "idiom" : "ipad",
20 | "size" : "29x29",
21 | "scale" : "1x"
22 | },
23 | {
24 | "idiom" : "ipad",
25 | "size" : "29x29",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "ipad",
30 | "size" : "40x40",
31 | "scale" : "1x"
32 | },
33 | {
34 | "idiom" : "ipad",
35 | "size" : "40x40",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "ipad",
40 | "size" : "76x76",
41 | "scale" : "1x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "76x76",
46 | "scale" : "2x"
47 | }
48 | ],
49 | "info" : {
50 | "version" : 1,
51 | "author" : "xcode"
52 | }
53 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Panaxiom Ltd and Alexander Jarvis (@alexanderjarvis)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all 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,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/Classes/PXAlertView+Customization.h:
--------------------------------------------------------------------------------
1 | //
2 | // PXAlertView+Customization.h
3 | // PXAlertViewDemo
4 | //
5 | // Created by Michal Zygar on 21.10.2013.
6 | // Copyright (c) 2013 panaxiom. All rights reserved.
7 | //
8 |
9 | #import "PXAlertView.h"
10 |
11 | @interface PXAlertView (Customization)
12 |
13 | - (void)setWindowTintColor:(UIColor *)color;
14 | - (void)setBackgroundColor:(UIColor *)color;
15 |
16 | - (void)setTitleColor:(UIColor *)color;
17 | - (void)setTitleFont:(UIFont *)font;
18 |
19 | - (void)setMessageColor:(UIColor *)color;
20 | - (void)setMessageFont:(UIFont *)font;
21 |
22 | - (void)setCancelButtonBackgroundColor:(UIColor *)color;
23 | - (void)setOtherButtonBackgroundColor:(UIColor *)color;
24 | - (void)setAllButtonsBackgroundColor:(UIColor *)color;
25 |
26 | - (void)setCancelButtonNonSelectedBackgroundColor:(UIColor *)color;
27 | - (void)setOtherButtonNonSelectedBackgroundColor:(UIColor *)color;
28 | - (void)setAllButtonsNonSelectedBackgroundColor:(UIColor *)color;
29 |
30 | - (void)setCancelButtonTextColor:(UIColor *)color;
31 | - (void)setAllButtonsTextColor:(UIColor *)color;
32 | - (void)setOtherButtonTextColor:(UIColor *)color;
33 |
34 | - (void)useDefaultIOS7Style;
35 |
36 | - (void)setCornerRadius:(CGFloat)radius;
37 | - (void)setCenter:(CGPoint)center;
38 |
39 | @end
--------------------------------------------------------------------------------
/PXAlertViewDemo/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 | "orientation" : "portrait",
20 | "idiom" : "ipad",
21 | "extent" : "full-screen",
22 | "minimum-system-version" : "7.0",
23 | "scale" : "1x"
24 | },
25 | {
26 | "orientation" : "landscape",
27 | "idiom" : "ipad",
28 | "extent" : "full-screen",
29 | "minimum-system-version" : "7.0",
30 | "scale" : "1x"
31 | },
32 | {
33 | "orientation" : "portrait",
34 | "idiom" : "ipad",
35 | "extent" : "full-screen",
36 | "minimum-system-version" : "7.0",
37 | "scale" : "2x"
38 | },
39 | {
40 | "orientation" : "landscape",
41 | "idiom" : "ipad",
42 | "extent" : "full-screen",
43 | "minimum-system-version" : "7.0",
44 | "scale" : "2x"
45 | }
46 | ],
47 | "info" : {
48 | "version" : 1,
49 | "author" : "xcode"
50 | }
51 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PXAlertView
2 |
3 | PXAlertView is a UIAlertView replacement similar to the style in iOS 7 but with a block based API and the ability to customise the styling and add custom views.
4 |
5 | ## Preview
6 | 
7 |
8 | ## Features
9 |
10 | * Simple block syntax instead of delegates
11 | * Animations that match UIAlertView in iOS 7
12 | * Fully customisable
13 | * Add your own UIView beneath the title
14 |
15 | ## Installation
16 |
17 | Add the following to your [CocoaPods](http://cocoapods.org/) Podfile
18 |
19 | pod 'PXAlertView', '~> 0.1.0'
20 |
21 | or clone as a git submodule,
22 |
23 | or just copy ```PXAlertView.h``` and ```.m``` into your project.
24 |
25 | ## Usage
26 |
27 | See [PXAlertView.h](Classes/PXAlertView.h) for the complete API.
28 |
29 | ### An Example
30 |
31 | ```Objective-C
32 | [PXAlertView showAlertWithTitle:@"The Matrix"
33 | message:@"Pick the Red pill, or the blue pill"
34 | cancelTitle:@"Blue"
35 | otherTitle:@"Red"
36 | completion:^(BOOL cancelled, NSInteger buttonIndex) {
37 | if (cancelled) {
38 | NSLog(@"Cancel (Blue) button pressed");
39 | } else {
40 | NSLog(@"Other (Red) button pressed");
41 | }
42 | }];
43 | ```
44 |
45 | ## TODO
46 |
47 | * Add style that matches iOS 7 exactly
48 | * Ability to dynamically specify the styling of AlertView: default/dark
49 |
50 | ## License
51 |
52 | PXAlertView is available under the MIT license. See the LICENSE file for more info.
53 |
--------------------------------------------------------------------------------
/PXAlertViewDemo/PXAlertViewDemo-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | APPL
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 0.1.0
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIMainStoryboardFile~ipad
30 | Main_iPhone
31 | UIRequiredDeviceCapabilities
32 |
33 | armv7
34 |
35 | UISupportedInterfaceOrientations
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationLandscapeLeft
39 | UIInterfaceOrientationLandscapeRight
40 |
41 | UISupportedInterfaceOrientations~ipad
42 |
43 | UIInterfaceOrientationPortrait
44 | UIInterfaceOrientationPortraitUpsideDown
45 | UIInterfaceOrientationLandscapeLeft
46 | UIInterfaceOrientationLandscapeRight
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/PXAlertViewDemo/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
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 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/PXAlertViewDemo/PXAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // PXAppDelegate.m
3 | // PXAlertViewDemo
4 | //
5 | // Created by Alex Jarvis on 25/09/2013.
6 | // Copyright (c) 2013 Panaxiom Ltd. All rights reserved.
7 | //
8 |
9 | #import "PXAppDelegate.h"
10 |
11 | @implementation PXAppDelegate
12 |
13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
14 | {
15 | // Override point for customization after application launch.
16 | return YES;
17 | }
18 |
19 | - (void)applicationWillResignActive:(UIApplication *)application
20 | {
21 | // 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.
22 | // 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.
23 | }
24 |
25 | - (void)applicationDidEnterBackground:(UIApplication *)application
26 | {
27 | // 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.
28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
29 | }
30 |
31 | - (void)applicationWillEnterForeground:(UIApplication *)application
32 | {
33 | // 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.
34 | }
35 |
36 | - (void)applicationDidBecomeActive:(UIApplication *)application
37 | {
38 | // 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.
39 | }
40 |
41 | - (void)applicationWillTerminate:(UIApplication *)application
42 | {
43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
44 | }
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/Classes/PXAlertView.h:
--------------------------------------------------------------------------------
1 | //
2 | // PXAlertView.h
3 | // PXAlertViewDemo
4 | //
5 | // Created by Alex Jarvis on 25/09/2013.
6 | // Copyright (c) 2013 Panaxiom Ltd. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | typedef void(^PXAlertViewCompletionBlock)(BOOL cancelled, NSInteger buttonIndex);
12 |
13 | @interface PXAlertView : UIViewController
14 |
15 | @property (nonatomic, getter = isVisible) BOOL visible;
16 |
17 | + (instancetype)showAlertWithTitle:(NSString *)title;
18 |
19 | + (instancetype)showAlertWithTitle:(NSString *)title
20 | message:(NSString *)message;
21 |
22 | + (instancetype)showAlertWithTitle:(NSString *)title
23 | message:(NSString *)message
24 | completion:(PXAlertViewCompletionBlock)completion;
25 |
26 | + (instancetype)showAlertWithTitle:(NSString *)title
27 | message:(NSString *)message
28 | cancelTitle:(NSString *)cancelTitle
29 | completion:(PXAlertViewCompletionBlock)completion;
30 |
31 | + (instancetype)showAlertWithTitle:(NSString *)title
32 | message:(NSString *)message
33 | cancelTitle:(NSString *)cancelTitle
34 | otherTitle:(NSString *)otherTitle
35 | completion:(PXAlertViewCompletionBlock)completion;
36 |
37 | + (instancetype)showAlertWithTitle:(NSString *)title
38 | message:(NSString *)message
39 | cancelTitle:(NSString *)cancelTitle
40 | otherTitle:(NSString *)otherTitle
41 | buttonsShouldStack:(BOOL)shouldStack
42 | completion:(PXAlertViewCompletionBlock)completion;
43 |
44 | /**
45 | * @param otherTitles Must be a NSArray containing type NSString, or set to nil for no otherTitles.
46 | */
47 | + (instancetype)showAlertWithTitle:(NSString *)title
48 | message:(NSString *)message
49 | cancelTitle:(NSString *)cancelTitle
50 | otherTitles:(NSArray *)otherTitles
51 | completion:(PXAlertViewCompletionBlock)completion;
52 |
53 |
54 | + (instancetype)showAlertWithTitle:(NSString *)title
55 | message:(NSString *)message
56 | cancelTitle:(NSString *)cancelTitle
57 | otherTitle:(NSString *)otherTitle
58 | contentView:(UIView *)view
59 | completion:(PXAlertViewCompletionBlock)completion;
60 |
61 | + (instancetype)showAlertWithTitle:(NSString *)title
62 | message:(NSString *)message
63 | cancelTitle:(NSString *)cancelTitle
64 | otherTitle:(NSString *)otherTitle
65 | buttonsShouldStack:(BOOL)shouldStack
66 | contentView:(UIView *)view
67 | completion:(PXAlertViewCompletionBlock)completion;
68 |
69 | /**
70 | * @param otherTitles Must be a NSArray containing type NSString, or set to nil for no otherTitles.
71 | */
72 | + (instancetype)showAlertWithTitle:(NSString *)title
73 | message:(NSString *)message
74 | cancelTitle:(NSString *)cancelTitle
75 | otherTitles:(NSArray *)otherTitles
76 | contentView:(UIView *)view
77 | completion:(PXAlertViewCompletionBlock)completion;
78 |
79 | /**
80 | * Adds a button to the receiver with the given title.
81 | * @param title The title of the new button
82 | * @return The index of the new button. Button indices start at 0 and increase in the order they are added.
83 | */
84 | - (NSInteger)addButtonWithTitle:(NSString *)title;
85 |
86 | /**
87 | * Dismisses the receiver
88 | */
89 | - (void)dismiss;
90 |
91 | /**
92 | * Dismisses the receiver, optionally with animation.
93 | */
94 | - (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated;
95 |
96 | /**
97 | * By default the alert allows you to tap anywhere around the alert to dismiss it.
98 | * This method enables or disables this feature.
99 | */
100 | - (void)setTapToDismissEnabled:(BOOL)enabled;
101 |
102 | @end
103 |
--------------------------------------------------------------------------------
/PXAlertViewDemo.xcodeproj/xcuserdata/alex.xcuserdatad/xcschemes/PXAlertViewDemo.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
64 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
85 |
91 |
92 |
93 |
94 |
96 |
97 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/Classes/PXAlertView+Customization.m:
--------------------------------------------------------------------------------
1 | //
2 | // PXAlertView+Customization.m
3 | // PXAlertViewDemo
4 | //
5 | // Created by Michal Zygar on 21.10.2013.
6 | // Copyright (c) 2013 panaxiom. All rights reserved.
7 | //
8 |
9 | #import "PXAlertView+Customization.h"
10 | #import
11 |
12 | void * const kCancelBGKey = (void * const) &kCancelBGKey;
13 | void * const kNonSelectedCancelBGKey = (void * const) &kNonSelectedCancelBGKey;
14 | void * const kOtherBGKey = (void * const) &kOtherBGKey;
15 | void * const kNonSelectedOtherBGKey = (void * const) &kNonSelectedOtherBGKey;
16 | void * const kAllBGKey = (void * const) &kAllBGKey;
17 | void * const kNonSelectedAllBGKey = (void * const) &kNonSelectedAllBGKey;
18 |
19 | @interface PXAlertView ()
20 |
21 | @property (nonatomic) UIView *backgroundView;
22 | @property (nonatomic) UIView *alertView;
23 | @property (nonatomic) UILabel *titleLabel;
24 | @property (nonatomic) UILabel *messageLabel;
25 | @property (nonatomic) UIButton *cancelButton;
26 | @property (nonatomic) UIButton *otherButton;
27 | @property (nonatomic) NSArray *buttons;
28 |
29 | @end
30 |
31 | @implementation PXAlertView (Customization)
32 |
33 | - (void)useDefaultIOS7Style {
34 | [self setTapToDismissEnabled:NO];
35 | UIColor *ios7BlueColor = [UIColor colorWithRed:0.0 green:122.0/255.0 blue:1.0 alpha:1.0];
36 | [self setAllButtonsTextColor:ios7BlueColor];
37 | [self setTitleColor:[UIColor blackColor]];
38 | [self setMessageColor:[UIColor blackColor]];
39 | UIColor *defaultBackgroundColor = [UIColor colorWithRed:217/255.0 green:217/255.0 blue:217/255.0 alpha:1.0];
40 | [self setAllButtonsBackgroundColor:defaultBackgroundColor];
41 | [self setBackgroundColor:[UIColor whiteColor]];
42 | }
43 |
44 | - (void)setCornerRadius:(CGFloat)radius
45 | {
46 | self.alertView.layer.cornerRadius = radius;
47 | }
48 |
49 | - (void)setCenter:(CGPoint)center
50 | {
51 | self.alertView.center = center;
52 | }
53 |
54 | - (void)setWindowTintColor:(UIColor *)color
55 | {
56 | self.backgroundView.backgroundColor = color;
57 | }
58 |
59 | - (void)setBackgroundColor:(UIColor *)color
60 | {
61 | self.alertView.backgroundColor = color;
62 | }
63 |
64 | - (void)setTitleColor:(UIColor *)color
65 | {
66 | self.titleLabel.textColor = color;
67 | }
68 |
69 | - (void)setTitleFont:(UIFont *)font
70 | {
71 | self.titleLabel.font = font;
72 | }
73 |
74 | - (void)setMessageColor:(UIColor *)color
75 | {
76 | self.messageLabel.textColor = color;
77 | }
78 |
79 | - (void)setMessageFont:(UIFont *)font
80 | {
81 | self.messageLabel.font = font;
82 | }
83 |
84 | #pragma mark -
85 | #pragma mark Buttons Customization
86 | #pragma mark Buttons Background Colors
87 | - (void)setCustomBackgroundColorForButton:(id)sender
88 | {
89 | if (sender == self.cancelButton && [self cancelButtonBackgroundColor]) {
90 | self.cancelButton.backgroundColor = [self cancelButtonBackgroundColor];
91 | } else if (sender == self.otherButton && [self otherButtonBackgroundColor]) {
92 | self.otherButton.backgroundColor = [self otherButtonBackgroundColor];
93 | } else if ([self allButtonsBackgroundColor]) {
94 | [sender setBackgroundColor:[self allButtonsBackgroundColor]];
95 | } else {
96 | [sender setBackgroundColor:[UIColor colorWithRed:94/255.0 green:196/255.0 blue:221/255.0 alpha:1]];
97 | }
98 | }
99 |
100 | - (void)setNonSelectedCustomBackgroundColorForButton:(id)sender
101 | {
102 | if (sender == self.cancelButton && [self nonSelectedCancelButtonBackgroundColor]) {
103 | self.cancelButton.backgroundColor = [self nonSelectedCancelButtonBackgroundColor];
104 | } else if (sender == self.otherButton && [self nonSelectedOtherButtonBackgroundColor]) {
105 | self.otherButton.backgroundColor = [self nonSelectedOtherButtonBackgroundColor];
106 | } else if ([self nonSelectedAllButtonsBackgroundColor]) {
107 | [sender setBackgroundColor:[self nonSelectedAllButtonsBackgroundColor]];
108 | } else {
109 | [sender setBackgroundColor:[UIColor clearColor]];
110 | }
111 | }
112 |
113 | - (void)setCancelButtonBackgroundColor:(UIColor *)color
114 | {
115 | objc_setAssociatedObject(self, kCancelBGKey, color, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
116 | [self.cancelButton addTarget:self action:@selector(setCustomBackgroundColorForButton:) forControlEvents:UIControlEventTouchDown];
117 | [self.cancelButton addTarget:self action:@selector(setCustomBackgroundColorForButton:) forControlEvents:UIControlEventTouchDragEnter];
118 | [self.cancelButton addTarget:self action:@selector(setNonSelectedCustomBackgroundColorForButton:) forControlEvents:UIControlEventTouchDragExit];
119 | }
120 |
121 | - (UIColor *)cancelButtonBackgroundColor
122 | {
123 | return objc_getAssociatedObject(self, kCancelBGKey);
124 | }
125 |
126 | - (void)setCancelButtonNonSelectedBackgroundColor:(UIColor *)color
127 | {
128 | objc_setAssociatedObject(self, kNonSelectedCancelBGKey, color, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
129 | self.cancelButton.backgroundColor = color;
130 | }
131 |
132 | - (UIColor *)nonSelectedCancelButtonBackgroundColor
133 | {
134 | return objc_getAssociatedObject(self, kNonSelectedCancelBGKey);
135 | }
136 |
137 | - (void)setAllButtonsBackgroundColor:(UIColor *)color
138 | {
139 | objc_setAssociatedObject(self, kOtherBGKey, color, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
140 | objc_setAssociatedObject(self, kCancelBGKey, color, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
141 | objc_setAssociatedObject(self, kAllBGKey, color, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
142 | for (UIButton *button in self.buttons) {
143 | [button addTarget:self action:@selector(setCustomBackgroundColorForButton:) forControlEvents:UIControlEventTouchDown];
144 | [button addTarget:self action:@selector(setCustomBackgroundColorForButton:) forControlEvents:UIControlEventTouchDragEnter];
145 | [button addTarget:self action:@selector(setNonSelectedCustomBackgroundColorForButton:) forControlEvents:UIControlEventTouchDragExit];
146 | }
147 | }
148 |
149 | - (UIColor *)allButtonsBackgroundColor
150 | {
151 | return objc_getAssociatedObject(self, kAllBGKey);
152 | }
153 |
154 | - (void)setAllButtonsNonSelectedBackgroundColor:(UIColor *)color
155 | {
156 | objc_setAssociatedObject(self, kNonSelectedOtherBGKey, color, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
157 | objc_setAssociatedObject(self, kNonSelectedCancelBGKey, color, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
158 | objc_setAssociatedObject(self, kNonSelectedAllBGKey, color, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
159 | for (UIButton *button in self.buttons) {
160 | button.backgroundColor = color;
161 | }
162 | }
163 |
164 | - (UIColor *)nonSelectedAllButtonsBackgroundColor
165 | {
166 | return objc_getAssociatedObject(self, kNonSelectedAllBGKey);
167 | }
168 |
169 | - (void)setOtherButtonBackgroundColor:(UIColor *)color
170 | {
171 | objc_setAssociatedObject(self, kOtherBGKey, color, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
172 | [self.otherButton addTarget:self action:@selector(setCustomBackgroundColorForButton:) forControlEvents:UIControlEventTouchDown];
173 | [self.otherButton addTarget:self action:@selector(setCustomBackgroundColorForButton:) forControlEvents:UIControlEventTouchDragEnter];
174 | [self.otherButton addTarget:self action:@selector(setNonSelectedCustomBackgroundColorForButton:) forControlEvents:UIControlEventTouchDragExit];
175 | }
176 |
177 | - (UIColor *)otherButtonBackgroundColor
178 | {
179 | return objc_getAssociatedObject(self, kOtherBGKey);
180 | }
181 |
182 | - (void)setOtherButtonNonSelectedBackgroundColor:(UIColor *)color
183 | {
184 | objc_setAssociatedObject(self, kNonSelectedOtherBGKey, color, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
185 | self.otherButton.backgroundColor = color;
186 | }
187 |
188 | - (UIColor *)nonSelectedOtherButtonBackgroundColor
189 | {
190 | return objc_getAssociatedObject(self, kNonSelectedOtherBGKey);
191 | }
192 |
193 | #pragma mark Buttons Text Colors
194 | - (void)setCancelButtonTextColor:(UIColor *)color
195 | {
196 | [self.cancelButton setTitleColor:color forState:UIControlStateNormal];
197 | [self.cancelButton setTitleColor:color forState:UIControlStateHighlighted];
198 | }
199 |
200 | - (void)setAllButtonsTextColor:(UIColor *)color
201 | {
202 | for (UIButton *button in self.buttons) {
203 | [button setTitleColor:color forState:UIControlStateNormal];
204 | [button setTitleColor:color forState:UIControlStateHighlighted];
205 | }
206 | }
207 |
208 | - (void)setOtherButtonTextColor:(UIColor *)color
209 | {
210 | [self.otherButton setTitleColor:color forState:UIControlStateNormal];
211 | [self.otherButton setTitleColor:color forState:UIControlStateHighlighted];
212 | }
213 | @end
214 |
--------------------------------------------------------------------------------
/PXAlertViewDemo/PXViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // PXViewController.m
3 | // PXAlertViewDemo
4 | //
5 | // Created by Alex Jarvis on 25/09/2013.
6 | // Copyright (c) 2013 Panaxiom Ltd. All rights reserved.
7 | //
8 |
9 | #import "PXViewController.h"
10 | #import "PXAlertView+Customization.h"
11 |
12 | @interface PXViewController ()
13 |
14 | @end
15 |
16 | @implementation PXViewController
17 |
18 | - (void)viewDidLoad
19 | {
20 | [super viewDidLoad];
21 | // Do any additional setup after loading the view, typically from a nib.
22 | }
23 |
24 | - (void)didReceiveMemoryWarning
25 | {
26 | [super didReceiveMemoryWarning];
27 | // Dispose of any resources that can be recreated.
28 | }
29 |
30 | - (BOOL)shouldAutorotate
31 | {
32 | return YES;
33 | }
34 |
35 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
36 | {
37 | return YES;
38 | }
39 |
40 | - (IBAction)showSimpleAlertView:(id)sender
41 | {
42 | [PXAlertView showAlertWithTitle:@"Hello World"
43 | message:@"Oh my this looks like a nice message."
44 | cancelTitle:@"Ok"
45 | completion:^(BOOL cancelled, NSInteger buttonIndex) {
46 | if (cancelled) {
47 | NSLog(@"Simple Alert View cancelled");
48 | } else {
49 | NSLog(@"Simple Alert View dismissed, but not cancelled");
50 | }
51 | }];
52 | }
53 |
54 | - (IBAction)showSimpleCustomizedAlertView:(id)sender
55 | {
56 | PXAlertView *alert = [PXAlertView showAlertWithTitle:@"Hello World"
57 | message:@"Oh my this looks like a nice message."
58 | cancelTitle:@"Ok"
59 | completion:^(BOOL cancelled, NSInteger buttonIndex) {
60 | if (cancelled) {
61 | NSLog(@"Simple Customised Alert View cancelled");
62 | } else {
63 | NSLog(@"Simple Customised Alert View dismissed, but not cancelled");
64 | }
65 | }];
66 | [alert setWindowTintColor:[UIColor colorWithRed:94/255.0 green:196/255.0 blue:221/255.0 alpha:0.25]];
67 | [alert setBackgroundColor:[UIColor colorWithRed:255/255.0 green:206/255.0 blue:13/255.0 alpha:1.0]];
68 | [alert setCancelButtonBackgroundColor:[UIColor redColor]];
69 | [alert setTitleFont:[UIFont fontWithName:@"Zapfino" size:15.0f]];
70 | [alert setTitleColor:[UIColor darkGrayColor]];
71 | [alert setCancelButtonBackgroundColor:[UIColor redColor]];
72 | }
73 |
74 |
75 | - (IBAction)showLargeAlertView:(id)sender
76 | {
77 | [PXAlertView showAlertWithTitle:@"Why this is a larger title! Even larger than the largest large thing that ever was large in a very large way."
78 | message:@"Oh my this looks like a nice message. Yes it does, and it can span multiple lines... all the way down.\n\nBut what's this? Even more lines? Why yes, now we can have even more content to show the world. Why? Because now you don't have to worry about the text overflowing off the screen. If text becomes too long to fit on the users display, it'll simply overflow and allow for the user to scroll. So now you're free to write however much you wish to write in an alert. A novel? An epic? Doesn't matter, because it can all now fit*. \n\n\n*Disclaimer: Within hardware and technical limitations, of course.\n\n To demonstrate, watch here:\nHere is a line.\nAnd here is another.\nAnd another.\nAnd another.\nAaaaaaand another.\nOh lookie here, AND another.\nAnd here's one more.\nFor good measure.\nAnd hello, newline.\n\n\nFeel free to expand your textual minds."
79 | cancelTitle:@"Ok thanks, that's grand"
80 | completion:^(BOOL cancelled, NSInteger buttonIndex) {
81 | if (cancelled) {
82 | NSLog(@"Larger Alert View cancelled");
83 | } else {
84 | NSLog(@"Larger Alert View dismissed, but not cancelled");
85 | }
86 | }];
87 | }
88 |
89 | - (IBAction)showTwoButtonAlertView:(id)sender
90 | {
91 | PXAlertView *alert = [PXAlertView showAlertWithTitle:@"The Matrix"
92 | message:@"Pick the Red pill, or the blue pill"
93 | cancelTitle:@"Blue"
94 | otherTitle:@"Red"
95 | completion:^(BOOL cancelled, NSInteger buttonIndex) {
96 | if (cancelled) {
97 | NSLog(@"Cancel (Blue) button pressed");
98 | } else {
99 | NSLog(@"Other (Red) button pressed");
100 | }
101 | }];
102 |
103 | UIColor *blueNormal = [UIColor blueColor];
104 | UIColor *blueSelected = [UIColor colorWithRed:0.5 green:0.5 blue:1 alpha:1];
105 | [alert setCancelButtonNonSelectedBackgroundColor:blueNormal];
106 | [alert setCancelButtonBackgroundColor:blueSelected];
107 |
108 | UIColor *redNormal = [UIColor redColor];
109 | UIColor *redSelected = [UIColor colorWithRed:1 green:0.5 blue:0.5 alpha:1];
110 | [alert setOtherButtonNonSelectedBackgroundColor:redNormal];
111 | [alert setOtherButtonBackgroundColor:redSelected];
112 |
113 | [alert setAllButtonsTextColor:[UIColor whiteColor]];
114 | }
115 |
116 | - (IBAction)showTwoStackedButtonAlertView:(id)sender
117 | {
118 | PXAlertView *alert = [PXAlertView showAlertWithTitle:@"The Matrix"
119 | message:@"Pick the Red pill, or the blue pill"
120 | cancelTitle:@"Blue"
121 | otherTitle:@"Red"
122 | buttonsShouldStack:YES
123 | completion:^(BOOL cancelled, NSInteger buttonIndex) {
124 | if (cancelled) {
125 | NSLog(@"Cancel (Blue) button pressed");
126 | } else {
127 | NSLog(@"Other (Red) button pressed");
128 | }
129 | }];
130 |
131 | UIColor *blueNormal = [UIColor blueColor];
132 | UIColor *blueSelected = [UIColor colorWithRed:0.5 green:0.5 blue:1 alpha:1];
133 | [alert setCancelButtonNonSelectedBackgroundColor:blueNormal];
134 | [alert setCancelButtonBackgroundColor:blueSelected];
135 |
136 | UIColor *redNormal = [UIColor redColor];
137 | UIColor *redSelected = [UIColor colorWithRed:1 green:0.5 blue:0.5 alpha:1];
138 | [alert setOtherButtonNonSelectedBackgroundColor:redNormal];
139 | [alert setOtherButtonBackgroundColor:redSelected];
140 |
141 | [alert setAllButtonsTextColor:[UIColor whiteColor]];
142 | }
143 |
144 | - (IBAction)showMultiButtonAlertView:(id)sender
145 | {
146 | PXAlertView *alert = [PXAlertView showAlertWithTitle:@"Porridge"
147 | message:@"How would you like it?"
148 | cancelTitle:@"No thanks"
149 | otherTitles:@[ @"Too Hot", @"Luke Warm", @"Quite nippy" ]
150 | completion:^(BOOL cancelled, NSInteger buttonIndex) {
151 | if (cancelled) {
152 | NSLog(@"Cancel button pressed");
153 | } else {
154 | NSLog(@"Button with index %li pressed", (long)buttonIndex);
155 | }
156 | }];
157 | [alert setAllButtonsBackgroundColor:[UIColor greenColor]];
158 | }
159 |
160 | - (IBAction)showAlertViewWithContentView:(id)sender
161 | {
162 | [PXAlertView showAlertWithTitle:@"A picture should appear below"
163 | message:@"Yay, it works!"
164 | cancelTitle:@"Ok"
165 | otherTitle:nil
166 | contentView:[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"ExampleImage.png"]]
167 | completion:^(BOOL cancelled, NSInteger buttonIndex) {
168 | }];
169 | }
170 |
171 | - (IBAction)show5StackedAlertViews:(id)sender
172 | {
173 | for (int i = 1; i <= 5; i++) {
174 | [PXAlertView showAlertWithTitle:[NSString stringWithFormat:@"Hello %@", @(i)]
175 | message:@"Oh my this looks like a nice message."
176 | cancelTitle:@"Ok"
177 | completion:^(BOOL cancelled, NSInteger buttonIndex) {}];
178 | }
179 | }
180 |
181 | - (IBAction)showNoTapToDismiss:(id)sender
182 | {
183 | PXAlertView *alertView = [PXAlertView showAlertWithTitle:@"Tap"
184 | message:@"Try tapping around the alert view to dismiss it. This should NOT work on this alert."];
185 | [alertView setTapToDismissEnabled:NO];
186 | }
187 |
188 | - (IBAction)dismissWithNoAnimationAfter1Second:(id)sender
189 | {
190 | PXAlertView *alertView = [PXAlertView showAlertWithTitle:@"No Animation" message:@"When dismissed"];
191 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC));
192 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
193 | [alertView dismissWithClickedButtonIndex:0 animated:NO];
194 | });
195 | }
196 |
197 | - (IBAction)showAlertInsideAlertCompletion:(id)sender
198 | {
199 | [PXAlertView showAlertWithTitle:@"Alert Inception"
200 | message:@"After pressing ok, another alert should appear"
201 | completion:^(BOOL cancelled, NSInteger buttonIndex) {
202 | [PXAlertView showAlertWithTitle:@"Woohoo"];
203 | }];
204 | }
205 |
206 | - (IBAction)showCopyOfUIAlertView:(id)sender
207 | {
208 | PXAlertView *alertView = [PXAlertView showAlertWithTitle:@"Some really long title that should wrap to two lines at least. But does it cut off after a certain number of lines? Does it? Does it really? And then what? Does it truncate? Nooo it still hasn't cut off yet. Wow this AlertView can take a lot of characters."
209 | message:@"How long does the standard UIAlertView stretch to? This should give a good estimation"
210 | cancelTitle:@"Cancel"
211 | otherTitle:@"Ok"
212 | contentView:nil
213 | completion:nil];
214 | [alertView useDefaultIOS7Style];
215 | }
216 |
217 | - (IBAction)showLargeUIAlertView:(id)sender
218 | {
219 | UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Some really long title that should wrap to two lines at least. But does it cut off after a certain number of lines? Does it? Does it really? And then what? Does it truncate? Nooo it still hasn't cut off yet. Wow this AlertView can take a lot of characters."
220 | message:@"How long does the standard UIAlertView stretch to? This should give a good estimation"
221 | delegate:self
222 | cancelButtonTitle:@"Cancel"
223 | otherButtonTitles:@"Ok", nil];
224 | [alertView show];
225 | }
226 |
227 | @end
228 |
--------------------------------------------------------------------------------
/Classes/UIAlertView+PXAlertViewOverride.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIAlertView+PXAlertViewOverride.m
3 | // PXAlertView
4 | //
5 | // Created by Bryan Way on 18/09/2014
6 | //
7 |
8 | #import "UIAlertView+PXAlertViewOverride.h"
9 |
10 | #ifdef PXALERT_SWIZZLING
11 |
12 | #pragma clang diagnostic push
13 | #pragma clang diagnostic ignored "-Wundeclared-selector"
14 | @implementation UIAlertView (PXAlertViewOverride)
15 |
16 | + (void)load {
17 | static dispatch_once_t dispatchOnceToken;
18 | dispatch_once(&dispatchOnceToken, ^{
19 | Class class = [self class];
20 |
21 | SEL originalInitWithTitleSelector = @selector(initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles:);
22 | SEL swizzledInitWithTitleSelector = @selector(swizzled_initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles:);
23 | SEL originalShowSelector = @selector(show);
24 | SEL swizzledShowSelector = @selector(swizzled_show);
25 | SEL originalAddButtonWithTitleSelector = @selector(addButtonWithTitle:);
26 | SEL swizzledAddButtonWithTitleSelector = @selector(swizzled_addButtonWithTitle:);
27 | SEL originalGetVisibleSelector = @selector(getVisible);
28 | SEL swizzledGetVisibleSelector = @selector(swizzled_getVisible);
29 | SEL originalGetFirstOtherButtonIndexSelector = @selector(getFirstOtherButtonIndex);
30 | SEL swizzledGetFirstOtherButtonIndexSelector = @selector(swizzled_getFirstOtherButtonIndex);
31 | SEL originalGetNumberOfButtonsSelector = @selector(getNumberOfButtons);
32 | SEL swizzledGetNumberOfButtonsSelector = @selector(swizzled_getNumberOfButtons);
33 | SEL originalButtonTitleAtIndexSelector = @selector(getNumberOfButtons);
34 | SEL swizzledButtonTitleAtIndexSelector = @selector(swizzled_getNumberOfButtons);
35 | SEL originalDismissWithClickedButtonIndexSelector = @selector(dismissWithClickedButtonIndex:animated:);
36 | SEL swizzledDismissWithClickedButtonIndexSelector = @selector(swizzled_dismissWithClickedButtonIndex:animated:);
37 | SEL originalTextFieldAtIndexSelector = @selector(textFieldAtIndex:);
38 | SEL swizzledTextFieldAtIndexSelector = @selector(swizzled_textFieldAtIndex:);
39 |
40 | Method originalInitWithTitleMethod = class_getInstanceMethod(class, originalInitWithTitleSelector);
41 | Method swizzledInitWithTitleMethod = class_getInstanceMethod(class, swizzledInitWithTitleSelector);
42 | Method originalShowMethod = class_getInstanceMethod(class, originalShowSelector);
43 | Method swizzledShowMethod = class_getInstanceMethod(class, swizzledShowSelector);
44 | Method originalAddButtonWithTitleMethod = class_getInstanceMethod(class, originalAddButtonWithTitleSelector);
45 | Method swizzledAddBUttonWithTitleMethod = class_getInstanceMethod(class, swizzledAddButtonWithTitleSelector);
46 | Method originalGetVisibleMethod = class_getInstanceMethod(class, originalGetVisibleSelector);
47 | Method swizzledGetVisibleMethod = class_getInstanceMethod(class, swizzledGetVisibleSelector);
48 | Method originalGetFirstOtherButtonIndexMethod = class_getInstanceMethod(class, originalGetFirstOtherButtonIndexSelector);
49 | Method swizzledGetFirstOtherButtonIndexMethod = class_getInstanceMethod(class, swizzledGetFirstOtherButtonIndexSelector);
50 | Method originalGetNumberOfButtonsMethod = class_getInstanceMethod(class, originalGetNumberOfButtonsSelector);
51 | Method swizzledGetNumberOfButtonsMethod = class_getInstanceMethod(class, swizzledGetNumberOfButtonsSelector);
52 | Method originalButtonTitleAtIndexMethod = class_getInstanceMethod(class, originalButtonTitleAtIndexSelector);
53 | Method swizzledButtonTitleAtIndexMethod = class_getInstanceMethod(class, swizzledButtonTitleAtIndexSelector);
54 | Method originalDismissWithClickedButtonIndexMethod = class_getInstanceMethod(class, originalDismissWithClickedButtonIndexSelector);
55 | Method swizzledDismissWithClickedButtonIndexMethod = class_getInstanceMethod(class, swizzledDismissWithClickedButtonIndexSelector);
56 | Method originalTextFieldAtIndexMethod = class_getInstanceMethod(class, originalTextFieldAtIndexSelector);
57 | Method swizzledTextFieldAtIndexMethod = class_getInstanceMethod(class, swizzledTextFieldAtIndexSelector);
58 |
59 | if(class_addMethod(class, originalInitWithTitleSelector, method_getImplementation(swizzledInitWithTitleMethod), method_getTypeEncoding(swizzledInitWithTitleMethod)))
60 | {
61 | class_replaceMethod(class, swizzledInitWithTitleSelector, method_getImplementation(originalInitWithTitleMethod), method_getTypeEncoding(originalInitWithTitleMethod));
62 | }
63 | else
64 | {
65 | method_exchangeImplementations(originalInitWithTitleMethod, swizzledInitWithTitleMethod);
66 | }
67 |
68 | if(class_addMethod(class, originalShowSelector, method_getImplementation(swizzledShowMethod), method_getTypeEncoding(swizzledShowMethod)))
69 | {
70 | class_replaceMethod(class, swizzledShowSelector, method_getImplementation(originalShowMethod), method_getTypeEncoding(originalShowMethod));
71 | }
72 | else
73 | {
74 | method_exchangeImplementations(originalShowMethod, swizzledShowMethod);
75 | }
76 |
77 | if(class_addMethod(class, originalAddButtonWithTitleSelector, method_getImplementation(swizzledAddBUttonWithTitleMethod), method_getTypeEncoding(swizzledAddBUttonWithTitleMethod)))
78 | {
79 | class_replaceMethod(class, swizzledAddButtonWithTitleSelector, method_getImplementation(originalAddButtonWithTitleMethod), method_getTypeEncoding(originalAddButtonWithTitleMethod));
80 | }
81 | else
82 | {
83 | method_exchangeImplementations(originalAddButtonWithTitleMethod, swizzledAddBUttonWithTitleMethod);
84 | }
85 |
86 | if(class_addMethod(class, originalGetVisibleSelector, method_getImplementation(swizzledGetVisibleMethod), method_getTypeEncoding(swizzledGetVisibleMethod)))
87 | {
88 | class_replaceMethod(class, swizzledGetVisibleSelector, method_getImplementation(originalGetVisibleMethod), method_getTypeEncoding(originalGetVisibleMethod));
89 | }
90 | else
91 | {
92 | method_exchangeImplementations(originalGetVisibleMethod, swizzledGetVisibleMethod);
93 | }
94 |
95 | if(class_addMethod(class, originalGetFirstOtherButtonIndexSelector, method_getImplementation(swizzledGetFirstOtherButtonIndexMethod), method_getTypeEncoding(swizzledGetFirstOtherButtonIndexMethod)))
96 | {
97 | class_replaceMethod(class, swizzledGetFirstOtherButtonIndexSelector, method_getImplementation(originalGetNumberOfButtonsMethod), method_getTypeEncoding(originalGetNumberOfButtonsMethod));
98 | }
99 | else
100 | {
101 | method_exchangeImplementations(originalGetFirstOtherButtonIndexMethod, swizzledGetFirstOtherButtonIndexMethod);
102 | }
103 |
104 | if(class_addMethod(class, originalGetNumberOfButtonsSelector, method_getImplementation(swizzledGetNumberOfButtonsMethod), method_getTypeEncoding(swizzledGetNumberOfButtonsMethod)))
105 | {
106 | class_replaceMethod(class, swizzledGetNumberOfButtonsSelector, method_getImplementation(originalGetFirstOtherButtonIndexMethod), method_getTypeEncoding(originalGetFirstOtherButtonIndexMethod));
107 | }
108 | else
109 | {
110 | method_exchangeImplementations(originalGetNumberOfButtonsMethod, swizzledGetNumberOfButtonsMethod);
111 | }
112 |
113 | if(class_addMethod(class, originalButtonTitleAtIndexSelector, method_getImplementation(swizzledButtonTitleAtIndexMethod), method_getTypeEncoding(swizzledButtonTitleAtIndexMethod)))
114 | {
115 | class_replaceMethod(class, swizzledButtonTitleAtIndexSelector, method_getImplementation(originalButtonTitleAtIndexMethod), method_getTypeEncoding(originalButtonTitleAtIndexMethod));
116 | }
117 | else
118 | {
119 | method_exchangeImplementations(originalButtonTitleAtIndexMethod, swizzledButtonTitleAtIndexMethod);
120 | }
121 |
122 | if(class_addMethod(class, originalDismissWithClickedButtonIndexSelector, method_getImplementation(swizzledDismissWithClickedButtonIndexMethod), method_getTypeEncoding(swizzledDismissWithClickedButtonIndexMethod)))
123 | {
124 | class_replaceMethod(class, swizzledDismissWithClickedButtonIndexSelector, method_getImplementation(originalDismissWithClickedButtonIndexMethod), method_getTypeEncoding(originalDismissWithClickedButtonIndexMethod));
125 | }
126 | else
127 | {
128 | method_exchangeImplementations(originalDismissWithClickedButtonIndexMethod, swizzledDismissWithClickedButtonIndexMethod);
129 | }
130 |
131 | if(class_addMethod(class, originalTextFieldAtIndexSelector, method_getImplementation(swizzledTextFieldAtIndexMethod), method_getTypeEncoding(swizzledTextFieldAtIndexMethod)))
132 | {
133 | class_replaceMethod(class, swizzledTextFieldAtIndexSelector, method_getImplementation(originalTextFieldAtIndexMethod), method_getTypeEncoding(originalTextFieldAtIndexMethod));
134 | }
135 | else
136 | {
137 | method_exchangeImplementations(originalTextFieldAtIndexMethod, swizzledTextFieldAtIndexMethod);
138 | }
139 | });
140 | }
141 |
142 | // Swizzle methods
143 |
144 | - (id)swizzled_initWithTitle:(NSString *)title message:(NSString *)message delegate:(id)delegate cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSString *)otherButtonTitles, ...
145 | {
146 | if([super init])
147 | {
148 | self.delegate = delegate;
149 | self.title = title;
150 | self.message = message;
151 |
152 | self.cancelButtonIndex = 0;
153 | objc_setAssociatedObject(self, "cancelButtonTitle", cancelButtonTitle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
154 |
155 | NSMutableArray *otherButtonTitleList = [[NSMutableArray alloc] init];
156 |
157 | if(otherButtonTitles)
158 | {
159 | [otherButtonTitleList addObject:otherButtonTitles];
160 |
161 | va_list args;
162 | va_start(args, otherButtonTitles);
163 |
164 | NSString *otherButtonTitleEntry = nil;
165 | while((otherButtonTitleEntry = va_arg(args, NSString*)))
166 | {
167 | [otherButtonTitleList addObject:otherButtonTitleEntry];
168 | }
169 | va_end(args);
170 | }
171 |
172 | objc_setAssociatedObject(self, "otherButtonTitles", otherButtonTitleList, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
173 | }
174 | return self;
175 | }
176 |
177 | -(void)swizzled_show
178 | {
179 | [self showWithContent:nil];
180 | }
181 |
182 | -(void)showWithContent:(UIView*)contentView
183 | {
184 | if(self.alertViewStyle != UIAlertViewStyleDefault)
185 | {
186 | if(contentView)
187 | {
188 | NSLog(@"Warning: Unable to display contentView when alertViewStyle != UIAlertViewStyleDefault. contentView will not be displayed.");
189 | }
190 | contentView = [[UIView alloc] initWithFrame:(CGRect){0, 0, 270.0, (UIAlertViewStyleLoginAndPasswordInput ? 77.0 : 36.0)}];
191 |
192 | UITextField *textField = nil;
193 |
194 | NSMutableArray *alertBoxTextFields = [[NSMutableArray alloc] init];
195 | if(self.alertViewStyle == UIAlertViewStylePlainTextInput || self.alertViewStyle == UIAlertViewStyleLoginAndPasswordInput)
196 | {
197 | textField = [[UITextField alloc] initWithFrame:(CGRect){20.0, 0, 230.0, 26.0}];
198 | textField.backgroundColor = [UIColor whiteColor];
199 | [alertBoxTextFields addObject:textField];
200 | [contentView addSubview:textField];
201 | }
202 |
203 | if(self.alertViewStyle == UIAlertViewStyleSecureTextInput || self.alertViewStyle == UIAlertViewStyleLoginAndPasswordInput)
204 | {
205 | textField = [[UITextField alloc] initWithFrame:(CGRect){20.0, (UIAlertViewStyleLoginAndPasswordInput ? 36.0 : 0), 230.0, 31.0}];
206 | textField.backgroundColor = [UIColor whiteColor];
207 | if(UIAlertViewStyleSecureTextInput)
208 | {
209 | textField.secureTextEntry = YES;
210 | }
211 | [alertBoxTextFields addObject:textField];
212 | [contentView addSubview:textField];
213 | }
214 | objc_setAssociatedObject(self, "alertBoxTextFields", alertBoxTextFields, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
215 | }
216 |
217 | if(self.delegate)
218 | {
219 | if([self.delegate respondsToSelector:@selector(alertViewShouldEnableFirstOtherButton:)])
220 | {
221 | [self.delegate alertViewShouldEnableFirstOtherButton:self]; // This has no correspondence with PXAlertView. Calling incase any code must be executed in this delegated method.
222 | }
223 |
224 | if([self.delegate respondsToSelector:@selector(willPresentAlertView:)])
225 | {
226 | [self.delegate willPresentAlertView:self];
227 | }
228 | }
229 |
230 | PXAlertView* alertView = [PXAlertView showAlertWithTitle:self.title message:self.message cancelTitle:(NSString*)objc_getAssociatedObject(self, "cancelButtonTitle") otherTitles:(NSMutableArray*)objc_getAssociatedObject(self, "otherButtonTitles") contentView:contentView completion:^(BOOL cancelled, NSInteger buttonIndex) {
231 | if(self.delegate)
232 | {
233 | if(cancelled && [self.delegate respondsToSelector:@selector(alertViewCancel:)])
234 | {
235 | [self.delegate alertViewCancel:self];
236 | }
237 | if([self.delegate respondsToSelector:@selector(alertView:clickedButtonAtIndex:)])
238 | {
239 | [self.delegate alertView:self clickedButtonAtIndex:buttonIndex];
240 | }
241 | if([self.delegate respondsToSelector:@selector(alertView:willDismissWithButtonIndex:)])
242 | {
243 | [self.delegate alertView:self willDismissWithButtonIndex:buttonIndex];
244 | }
245 | if([self.delegate respondsToSelector:@selector(alertView:didDismissWithButtonIndex:)])
246 | {
247 | [self.delegate alertView:self didDismissWithButtonIndex:buttonIndex];
248 | }
249 | }
250 |
251 | objc_setAssociatedObject(self, "PXAlertViewInstance", nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
252 | }];
253 | [alertView setTapToDismissEnabled:NO]; // Default behavior like iOS. Best compatibility.
254 |
255 | objc_setAssociatedObject(self, "PXAlertViewInstance", alertView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
256 |
257 | if(self.delegate && [self.delegate respondsToSelector:@selector(didPresentAlertView::)])
258 | {
259 | [self.delegate didPresentAlertView:self];
260 | }
261 | }
262 |
263 | - (NSInteger)swizzled_addButtonWithTitle:(NSString *)title
264 | {
265 | PXAlertView* alertView = objc_getAssociatedObject(self, "PXAlertViewInstance");
266 | if(alertView)
267 | {
268 | return [alertView addButtonWithTitle:title];
269 | }
270 | else
271 | {
272 | if(!self.message)
273 | {
274 | self.message = title;
275 | return 0;
276 | }
277 | else
278 | {
279 | NSMutableArray* otherButtonTitles = objc_getAssociatedObject(self, "otherButtonTitles");
280 | if(!otherButtonTitles)
281 | {
282 | otherButtonTitles = [[NSMutableArray alloc] init];
283 | objc_setAssociatedObject(self, "otherButtonTitles", otherButtonTitles, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
284 | }
285 |
286 | [otherButtonTitles addObject:title];
287 | return [otherButtonTitles count];
288 | }
289 | }
290 | return -1;
291 | }
292 |
293 | - (NSString*)swizzled_buttonTitleAtIndex:(NSInteger)buttonIndex
294 | {
295 | id tmpObj = objc_getAssociatedObject(self, "cancelButtonTitle");
296 | if(buttonIndex == 0 && tmpObj)
297 | {
298 | return (NSString*)tmpObj;
299 | }
300 | else if(buttonIndex > 0)
301 | {
302 | buttonIndex--;
303 | NSMutableArray* otherButtonTitles = objc_getAssociatedObject(self, "otherButtonTitles");
304 | if(buttonIndex < [otherButtonTitles count])
305 | {
306 | return [otherButtonTitles objectAtIndex:buttonIndex];
307 | }
308 | }
309 | return nil;
310 | }
311 |
312 | - (void)swizzled_dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated
313 | {
314 | PXAlertView* alertView = objc_getAssociatedObject(self, "PXAlertViewInstance");
315 | if(alertView)
316 | {
317 | [alertView dismissWithClickedButtonIndex:buttonIndex animated:animated];
318 | }
319 | }
320 |
321 | -(BOOL)swizzled_getVisible
322 | {
323 | if(objc_getAssociatedObject(self, "PXAlertViewInstance"))
324 | {
325 | return YES;
326 | }
327 | return NO;
328 | }
329 |
330 | -(NSInteger)swizzled_getFirstOtherButtonIndex
331 | {
332 | NSMutableArray *array = objc_getAssociatedObject(self, "otherButtonTitles");
333 | if(array && [array count] > 0)
334 | {
335 | return 0;
336 | }
337 | return -1;
338 | }
339 |
340 | -(NSInteger)swizzled_getNumberOfButtons
341 | {
342 | NSMutableArray *array = objc_getAssociatedObject(self, "otherButtonTitles");
343 | if(array)
344 | {
345 | return 1 + [array count];
346 | }
347 | return 1;
348 | }
349 |
350 | - (UITextField *)swizzled_textFieldAtIndex:(NSInteger)textFieldIndex
351 | {
352 | NSMutableArray *alertBoxTextFields = objc_getAssociatedObject(self, "alertBoxTextFields");
353 | if(alertBoxTextFields && [alertBoxTextFields count] > textFieldIndex)
354 | {
355 | return [alertBoxTextFields objectAtIndex:textFieldIndex];
356 | }
357 | return nil;
358 | }
359 |
360 | @end
361 |
362 | #pragma clang diagnostic pop
363 |
364 | #endif
365 |
--------------------------------------------------------------------------------
/PXAlertViewDemo/en.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
33 |
43 |
56 |
69 |
79 |
89 |
99 |
112 |
122 |
132 |
145 |
158 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
--------------------------------------------------------------------------------
/PXAlertViewDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 37CD3A5A181526A1009FC40D /* PXAlertView+Customization.m in Sources */ = {isa = PBXBuildFile; fileRef = 37CD3A59181526A1009FC40D /* PXAlertView+Customization.m */; };
11 | 37CD3A5B181526A1009FC40D /* PXAlertView+Customization.m in Sources */ = {isa = PBXBuildFile; fileRef = 37CD3A59181526A1009FC40D /* PXAlertView+Customization.m */; };
12 | 7F99B3721A1BF53400E09D88 /* UIAlertView+PXAlertViewOverride.m in Sources */ = {isa = PBXBuildFile; fileRef = 7F99B3711A1BF53400E09D88 /* UIAlertView+PXAlertViewOverride.m */; };
13 | FA11B68217F3867100236222 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA11B68117F3867100236222 /* Foundation.framework */; };
14 | FA11B68417F3867100236222 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA11B68317F3867100236222 /* CoreGraphics.framework */; };
15 | FA11B68617F3867100236222 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA11B68517F3867100236222 /* UIKit.framework */; };
16 | FA11B68C17F3867100236222 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FA11B68A17F3867100236222 /* InfoPlist.strings */; };
17 | FA11B68E17F3867100236222 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = FA11B68D17F3867100236222 /* main.m */; };
18 | FA11B69217F3867100236222 /* PXAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FA11B69117F3867100236222 /* PXAppDelegate.m */; };
19 | FA11B69517F3867100236222 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FA11B69317F3867100236222 /* Main.storyboard */; };
20 | FA11B69B17F3867100236222 /* PXViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FA11B69A17F3867100236222 /* PXViewController.m */; };
21 | FA11B69D17F3867100236222 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FA11B69C17F3867100236222 /* Images.xcassets */; };
22 | FA11B6A417F3867100236222 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA11B6A317F3867100236222 /* XCTest.framework */; };
23 | FA11B6A517F3867100236222 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA11B68117F3867100236222 /* Foundation.framework */; };
24 | FA11B6A617F3867100236222 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA11B68517F3867100236222 /* UIKit.framework */; };
25 | FA11B6AE17F3867100236222 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FA11B6AC17F3867100236222 /* InfoPlist.strings */; };
26 | FA11B6B017F3867100236222 /* PXAlertViewDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = FA11B6AF17F3867100236222 /* PXAlertViewDemoTests.m */; };
27 | FA53E9561809B3BC001E6B60 /* PXAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = FA53E9551809B3BC001E6B60 /* PXAlertView.m */; };
28 | FA54BA551BE6B733002F6411 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FA54BA541BE6B733002F6411 /* LaunchScreen.storyboard */; };
29 | FADF87D717F99E950059B2B8 /* ExampleImage.png in Resources */ = {isa = PBXBuildFile; fileRef = FADF87D617F99E950059B2B8 /* ExampleImage.png */; };
30 | /* End PBXBuildFile section */
31 |
32 | /* Begin PBXContainerItemProxy section */
33 | FA11B6A717F3867100236222 /* PBXContainerItemProxy */ = {
34 | isa = PBXContainerItemProxy;
35 | containerPortal = FA11B67617F3867100236222 /* Project object */;
36 | proxyType = 1;
37 | remoteGlobalIDString = FA11B67D17F3867100236222;
38 | remoteInfo = PXAlertViewDemo;
39 | };
40 | /* End PBXContainerItemProxy section */
41 |
42 | /* Begin PBXFileReference section */
43 | 37CD3A58181526A1009FC40D /* PXAlertView+Customization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "PXAlertView+Customization.h"; sourceTree = ""; };
44 | 37CD3A59181526A1009FC40D /* PXAlertView+Customization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "PXAlertView+Customization.m"; sourceTree = ""; };
45 | 7F99B3701A1BF53400E09D88 /* UIAlertView+PXAlertViewOverride.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertView+PXAlertViewOverride.h"; sourceTree = ""; };
46 | 7F99B3711A1BF53400E09D88 /* UIAlertView+PXAlertViewOverride.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertView+PXAlertViewOverride.m"; sourceTree = ""; };
47 | FA11B67E17F3867100236222 /* PXAlertViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PXAlertViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
48 | FA11B68117F3867100236222 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
49 | FA11B68317F3867100236222 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
50 | FA11B68517F3867100236222 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
51 | FA11B68917F3867100236222 /* PXAlertViewDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "PXAlertViewDemo-Info.plist"; sourceTree = ""; };
52 | FA11B68B17F3867100236222 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
53 | FA11B68D17F3867100236222 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
54 | FA11B68F17F3867100236222 /* PXAlertViewDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PXAlertViewDemo-Prefix.pch"; sourceTree = ""; };
55 | FA11B69017F3867100236222 /* PXAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PXAppDelegate.h; sourceTree = ""; };
56 | FA11B69117F3867100236222 /* PXAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PXAppDelegate.m; sourceTree = ""; };
57 | FA11B69917F3867100236222 /* PXViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PXViewController.h; sourceTree = ""; };
58 | FA11B69A17F3867100236222 /* PXViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PXViewController.m; sourceTree = ""; };
59 | FA11B69C17F3867100236222 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
60 | FA11B6A217F3867100236222 /* PXAlertViewDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PXAlertViewDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
61 | FA11B6A317F3867100236222 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
62 | FA11B6AB17F3867100236222 /* PXAlertViewDemoTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "PXAlertViewDemoTests-Info.plist"; sourceTree = ""; };
63 | FA11B6AD17F3867100236222 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; };
64 | FA11B6AF17F3867100236222 /* PXAlertViewDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PXAlertViewDemoTests.m; sourceTree = ""; };
65 | FA53E9511809A8FB001E6B60 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/Main.storyboard; sourceTree = ""; };
66 | FA53E9541809B3BC001E6B60 /* PXAlertView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PXAlertView.h; sourceTree = ""; };
67 | FA53E9551809B3BC001E6B60 /* PXAlertView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PXAlertView.m; sourceTree = ""; };
68 | FA54BA541BE6B733002F6411 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; };
69 | FADF87D617F99E950059B2B8 /* ExampleImage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ExampleImage.png; sourceTree = SOURCE_ROOT; };
70 | /* End PBXFileReference section */
71 |
72 | /* Begin PBXFrameworksBuildPhase section */
73 | FA11B67B17F3867100236222 /* Frameworks */ = {
74 | isa = PBXFrameworksBuildPhase;
75 | buildActionMask = 2147483647;
76 | files = (
77 | FA11B68417F3867100236222 /* CoreGraphics.framework in Frameworks */,
78 | FA11B68617F3867100236222 /* UIKit.framework in Frameworks */,
79 | FA11B68217F3867100236222 /* Foundation.framework in Frameworks */,
80 | );
81 | runOnlyForDeploymentPostprocessing = 0;
82 | };
83 | FA11B69F17F3867100236222 /* Frameworks */ = {
84 | isa = PBXFrameworksBuildPhase;
85 | buildActionMask = 2147483647;
86 | files = (
87 | FA11B6A417F3867100236222 /* XCTest.framework in Frameworks */,
88 | FA11B6A617F3867100236222 /* UIKit.framework in Frameworks */,
89 | FA11B6A517F3867100236222 /* Foundation.framework in Frameworks */,
90 | );
91 | runOnlyForDeploymentPostprocessing = 0;
92 | };
93 | /* End PBXFrameworksBuildPhase section */
94 |
95 | /* Begin PBXGroup section */
96 | FA11B67517F3867100236222 = {
97 | isa = PBXGroup;
98 | children = (
99 | FA53E9531809B3BC001E6B60 /* Classes */,
100 | FA11B68717F3867100236222 /* PXAlertViewDemo */,
101 | FA11B6A917F3867100236222 /* PXAlertViewDemoTests */,
102 | FA11B68017F3867100236222 /* Frameworks */,
103 | FA11B67F17F3867100236222 /* Products */,
104 | );
105 | sourceTree = "";
106 | };
107 | FA11B67F17F3867100236222 /* Products */ = {
108 | isa = PBXGroup;
109 | children = (
110 | FA11B67E17F3867100236222 /* PXAlertViewDemo.app */,
111 | FA11B6A217F3867100236222 /* PXAlertViewDemoTests.xctest */,
112 | );
113 | name = Products;
114 | sourceTree = "";
115 | };
116 | FA11B68017F3867100236222 /* Frameworks */ = {
117 | isa = PBXGroup;
118 | children = (
119 | FA11B68117F3867100236222 /* Foundation.framework */,
120 | FA11B68317F3867100236222 /* CoreGraphics.framework */,
121 | FA11B68517F3867100236222 /* UIKit.framework */,
122 | FA11B6A317F3867100236222 /* XCTest.framework */,
123 | );
124 | name = Frameworks;
125 | sourceTree = "";
126 | };
127 | FA11B68717F3867100236222 /* PXAlertViewDemo */ = {
128 | isa = PBXGroup;
129 | children = (
130 | FA11B69017F3867100236222 /* PXAppDelegate.h */,
131 | FA11B69117F3867100236222 /* PXAppDelegate.m */,
132 | FA54BA541BE6B733002F6411 /* LaunchScreen.storyboard */,
133 | FA11B69317F3867100236222 /* Main.storyboard */,
134 | FA11B69917F3867100236222 /* PXViewController.h */,
135 | FA11B69A17F3867100236222 /* PXViewController.m */,
136 | FA11B69C17F3867100236222 /* Images.xcassets */,
137 | FADF87D617F99E950059B2B8 /* ExampleImage.png */,
138 | FA11B68817F3867100236222 /* Supporting Files */,
139 | );
140 | path = PXAlertViewDemo;
141 | sourceTree = "";
142 | };
143 | FA11B68817F3867100236222 /* Supporting Files */ = {
144 | isa = PBXGroup;
145 | children = (
146 | FA11B68917F3867100236222 /* PXAlertViewDemo-Info.plist */,
147 | FA11B68A17F3867100236222 /* InfoPlist.strings */,
148 | FA11B68D17F3867100236222 /* main.m */,
149 | FA11B68F17F3867100236222 /* PXAlertViewDemo-Prefix.pch */,
150 | );
151 | name = "Supporting Files";
152 | sourceTree = "";
153 | };
154 | FA11B6A917F3867100236222 /* PXAlertViewDemoTests */ = {
155 | isa = PBXGroup;
156 | children = (
157 | FA11B6AF17F3867100236222 /* PXAlertViewDemoTests.m */,
158 | FA11B6AA17F3867100236222 /* Supporting Files */,
159 | );
160 | path = PXAlertViewDemoTests;
161 | sourceTree = "";
162 | };
163 | FA11B6AA17F3867100236222 /* Supporting Files */ = {
164 | isa = PBXGroup;
165 | children = (
166 | FA11B6AB17F3867100236222 /* PXAlertViewDemoTests-Info.plist */,
167 | FA11B6AC17F3867100236222 /* InfoPlist.strings */,
168 | );
169 | name = "Supporting Files";
170 | sourceTree = "";
171 | };
172 | FA53E9531809B3BC001E6B60 /* Classes */ = {
173 | isa = PBXGroup;
174 | children = (
175 | 7F99B3701A1BF53400E09D88 /* UIAlertView+PXAlertViewOverride.h */,
176 | 7F99B3711A1BF53400E09D88 /* UIAlertView+PXAlertViewOverride.m */,
177 | 37CD3A58181526A1009FC40D /* PXAlertView+Customization.h */,
178 | 37CD3A59181526A1009FC40D /* PXAlertView+Customization.m */,
179 | FA53E9541809B3BC001E6B60 /* PXAlertView.h */,
180 | FA53E9551809B3BC001E6B60 /* PXAlertView.m */,
181 | );
182 | path = Classes;
183 | sourceTree = "";
184 | };
185 | /* End PBXGroup section */
186 |
187 | /* Begin PBXNativeTarget section */
188 | FA11B67D17F3867100236222 /* PXAlertViewDemo */ = {
189 | isa = PBXNativeTarget;
190 | buildConfigurationList = FA11B6B317F3867100236222 /* Build configuration list for PBXNativeTarget "PXAlertViewDemo" */;
191 | buildPhases = (
192 | FA11B67A17F3867100236222 /* Sources */,
193 | FA11B67B17F3867100236222 /* Frameworks */,
194 | FA11B67C17F3867100236222 /* Resources */,
195 | );
196 | buildRules = (
197 | );
198 | dependencies = (
199 | );
200 | name = PXAlertViewDemo;
201 | productName = PXAlertViewDemo;
202 | productReference = FA11B67E17F3867100236222 /* PXAlertViewDemo.app */;
203 | productType = "com.apple.product-type.application";
204 | };
205 | FA11B6A117F3867100236222 /* PXAlertViewDemoTests */ = {
206 | isa = PBXNativeTarget;
207 | buildConfigurationList = FA11B6B617F3867100236222 /* Build configuration list for PBXNativeTarget "PXAlertViewDemoTests" */;
208 | buildPhases = (
209 | FA11B69E17F3867100236222 /* Sources */,
210 | FA11B69F17F3867100236222 /* Frameworks */,
211 | FA11B6A017F3867100236222 /* Resources */,
212 | );
213 | buildRules = (
214 | );
215 | dependencies = (
216 | FA11B6A817F3867100236222 /* PBXTargetDependency */,
217 | );
218 | name = PXAlertViewDemoTests;
219 | productName = PXAlertViewDemoTests;
220 | productReference = FA11B6A217F3867100236222 /* PXAlertViewDemoTests.xctest */;
221 | productType = "com.apple.product-type.bundle.unit-test";
222 | };
223 | /* End PBXNativeTarget section */
224 |
225 | /* Begin PBXProject section */
226 | FA11B67617F3867100236222 /* Project object */ = {
227 | isa = PBXProject;
228 | attributes = {
229 | CLASSPREFIX = PX;
230 | LastUpgradeCheck = 0710;
231 | ORGANIZATIONNAME = panaxiom;
232 | TargetAttributes = {
233 | FA11B6A117F3867100236222 = {
234 | TestTargetID = FA11B67D17F3867100236222;
235 | };
236 | };
237 | };
238 | buildConfigurationList = FA11B67917F3867100236222 /* Build configuration list for PBXProject "PXAlertViewDemo" */;
239 | compatibilityVersion = "Xcode 3.2";
240 | developmentRegion = English;
241 | hasScannedForEncodings = 0;
242 | knownRegions = (
243 | en,
244 | Base,
245 | );
246 | mainGroup = FA11B67517F3867100236222;
247 | productRefGroup = FA11B67F17F3867100236222 /* Products */;
248 | projectDirPath = "";
249 | projectRoot = "";
250 | targets = (
251 | FA11B67D17F3867100236222 /* PXAlertViewDemo */,
252 | FA11B6A117F3867100236222 /* PXAlertViewDemoTests */,
253 | );
254 | };
255 | /* End PBXProject section */
256 |
257 | /* Begin PBXResourcesBuildPhase section */
258 | FA11B67C17F3867100236222 /* Resources */ = {
259 | isa = PBXResourcesBuildPhase;
260 | buildActionMask = 2147483647;
261 | files = (
262 | FA11B69D17F3867100236222 /* Images.xcassets in Resources */,
263 | FADF87D717F99E950059B2B8 /* ExampleImage.png in Resources */,
264 | FA11B69517F3867100236222 /* Main.storyboard in Resources */,
265 | FA54BA551BE6B733002F6411 /* LaunchScreen.storyboard in Resources */,
266 | FA11B68C17F3867100236222 /* InfoPlist.strings in Resources */,
267 | );
268 | runOnlyForDeploymentPostprocessing = 0;
269 | };
270 | FA11B6A017F3867100236222 /* Resources */ = {
271 | isa = PBXResourcesBuildPhase;
272 | buildActionMask = 2147483647;
273 | files = (
274 | FA11B6AE17F3867100236222 /* InfoPlist.strings in Resources */,
275 | );
276 | runOnlyForDeploymentPostprocessing = 0;
277 | };
278 | /* End PBXResourcesBuildPhase section */
279 |
280 | /* Begin PBXSourcesBuildPhase section */
281 | FA11B67A17F3867100236222 /* Sources */ = {
282 | isa = PBXSourcesBuildPhase;
283 | buildActionMask = 2147483647;
284 | files = (
285 | FA11B69B17F3867100236222 /* PXViewController.m in Sources */,
286 | 7F99B3721A1BF53400E09D88 /* UIAlertView+PXAlertViewOverride.m in Sources */,
287 | FA11B69217F3867100236222 /* PXAppDelegate.m in Sources */,
288 | FA11B68E17F3867100236222 /* main.m in Sources */,
289 | FA53E9561809B3BC001E6B60 /* PXAlertView.m in Sources */,
290 | 37CD3A5A181526A1009FC40D /* PXAlertView+Customization.m in Sources */,
291 | );
292 | runOnlyForDeploymentPostprocessing = 0;
293 | };
294 | FA11B69E17F3867100236222 /* Sources */ = {
295 | isa = PBXSourcesBuildPhase;
296 | buildActionMask = 2147483647;
297 | files = (
298 | FA11B6B017F3867100236222 /* PXAlertViewDemoTests.m in Sources */,
299 | 37CD3A5B181526A1009FC40D /* PXAlertView+Customization.m in Sources */,
300 | );
301 | runOnlyForDeploymentPostprocessing = 0;
302 | };
303 | /* End PBXSourcesBuildPhase section */
304 |
305 | /* Begin PBXTargetDependency section */
306 | FA11B6A817F3867100236222 /* PBXTargetDependency */ = {
307 | isa = PBXTargetDependency;
308 | target = FA11B67D17F3867100236222 /* PXAlertViewDemo */;
309 | targetProxy = FA11B6A717F3867100236222 /* PBXContainerItemProxy */;
310 | };
311 | /* End PBXTargetDependency section */
312 |
313 | /* Begin PBXVariantGroup section */
314 | FA11B68A17F3867100236222 /* InfoPlist.strings */ = {
315 | isa = PBXVariantGroup;
316 | children = (
317 | FA11B68B17F3867100236222 /* en */,
318 | );
319 | name = InfoPlist.strings;
320 | sourceTree = "";
321 | };
322 | FA11B69317F3867100236222 /* Main.storyboard */ = {
323 | isa = PBXVariantGroup;
324 | children = (
325 | FA53E9511809A8FB001E6B60 /* en */,
326 | );
327 | name = Main.storyboard;
328 | sourceTree = "";
329 | };
330 | FA11B6AC17F3867100236222 /* InfoPlist.strings */ = {
331 | isa = PBXVariantGroup;
332 | children = (
333 | FA11B6AD17F3867100236222 /* en */,
334 | );
335 | name = InfoPlist.strings;
336 | sourceTree = "";
337 | };
338 | /* End PBXVariantGroup section */
339 |
340 | /* Begin XCBuildConfiguration section */
341 | FA11B6B117F3867100236222 /* Debug */ = {
342 | isa = XCBuildConfiguration;
343 | buildSettings = {
344 | ALWAYS_SEARCH_USER_PATHS = NO;
345 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
346 | CLANG_CXX_LIBRARY = "libc++";
347 | CLANG_ENABLE_MODULES = YES;
348 | CLANG_ENABLE_OBJC_ARC = YES;
349 | CLANG_WARN_BOOL_CONVERSION = YES;
350 | CLANG_WARN_CONSTANT_CONVERSION = YES;
351 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
352 | CLANG_WARN_EMPTY_BODY = YES;
353 | CLANG_WARN_ENUM_CONVERSION = YES;
354 | CLANG_WARN_INT_CONVERSION = YES;
355 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
356 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
357 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
358 | COPY_PHASE_STRIP = NO;
359 | ENABLE_TESTABILITY = YES;
360 | GCC_C_LANGUAGE_STANDARD = gnu99;
361 | GCC_DYNAMIC_NO_PIC = NO;
362 | GCC_OPTIMIZATION_LEVEL = 0;
363 | GCC_PREPROCESSOR_DEFINITIONS = (
364 | "DEBUG=1",
365 | "$(inherited)",
366 | );
367 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
368 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
369 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
370 | GCC_WARN_UNDECLARED_SELECTOR = YES;
371 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
372 | GCC_WARN_UNUSED_FUNCTION = YES;
373 | GCC_WARN_UNUSED_VARIABLE = YES;
374 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
375 | ONLY_ACTIVE_ARCH = YES;
376 | SDKROOT = iphoneos;
377 | TARGETED_DEVICE_FAMILY = "1,2";
378 | };
379 | name = Debug;
380 | };
381 | FA11B6B217F3867100236222 /* Release */ = {
382 | isa = XCBuildConfiguration;
383 | buildSettings = {
384 | ALWAYS_SEARCH_USER_PATHS = NO;
385 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
386 | CLANG_CXX_LIBRARY = "libc++";
387 | CLANG_ENABLE_MODULES = YES;
388 | CLANG_ENABLE_OBJC_ARC = YES;
389 | CLANG_WARN_BOOL_CONVERSION = YES;
390 | CLANG_WARN_CONSTANT_CONVERSION = YES;
391 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
392 | CLANG_WARN_EMPTY_BODY = YES;
393 | CLANG_WARN_ENUM_CONVERSION = YES;
394 | CLANG_WARN_INT_CONVERSION = YES;
395 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
396 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
397 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
398 | COPY_PHASE_STRIP = YES;
399 | ENABLE_NS_ASSERTIONS = NO;
400 | GCC_C_LANGUAGE_STANDARD = gnu99;
401 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
402 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
403 | GCC_WARN_UNDECLARED_SELECTOR = YES;
404 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
405 | GCC_WARN_UNUSED_FUNCTION = YES;
406 | GCC_WARN_UNUSED_VARIABLE = YES;
407 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
408 | SDKROOT = iphoneos;
409 | TARGETED_DEVICE_FAMILY = "1,2";
410 | VALIDATE_PRODUCT = YES;
411 | };
412 | name = Release;
413 | };
414 | FA11B6B417F3867100236222 /* Debug */ = {
415 | isa = XCBuildConfiguration;
416 | buildSettings = {
417 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
418 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
419 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
420 | GCC_PREFIX_HEADER = "PXAlertViewDemo/PXAlertViewDemo-Prefix.pch";
421 | INFOPLIST_FILE = "PXAlertViewDemo/PXAlertViewDemo-Info.plist";
422 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
423 | PRODUCT_BUNDLE_IDENTIFIER = "uk.co.panaxiom.${PRODUCT_NAME:rfc1034identifier}";
424 | PRODUCT_NAME = "$(TARGET_NAME)";
425 | WRAPPER_EXTENSION = app;
426 | };
427 | name = Debug;
428 | };
429 | FA11B6B517F3867100236222 /* Release */ = {
430 | isa = XCBuildConfiguration;
431 | buildSettings = {
432 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
433 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
434 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
435 | GCC_PREFIX_HEADER = "PXAlertViewDemo/PXAlertViewDemo-Prefix.pch";
436 | INFOPLIST_FILE = "PXAlertViewDemo/PXAlertViewDemo-Info.plist";
437 | IPHONEOS_DEPLOYMENT_TARGET = 7.0;
438 | PRODUCT_BUNDLE_IDENTIFIER = "uk.co.panaxiom.${PRODUCT_NAME:rfc1034identifier}";
439 | PRODUCT_NAME = "$(TARGET_NAME)";
440 | WRAPPER_EXTENSION = app;
441 | };
442 | name = Release;
443 | };
444 | FA11B6B717F3867100236222 /* Debug */ = {
445 | isa = XCBuildConfiguration;
446 | buildSettings = {
447 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/PXAlertViewDemo.app/PXAlertViewDemo";
448 | FRAMEWORK_SEARCH_PATHS = (
449 | "$(SDKROOT)/Developer/Library/Frameworks",
450 | "$(inherited)",
451 | "$(DEVELOPER_FRAMEWORKS_DIR)",
452 | );
453 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
454 | GCC_PREFIX_HEADER = "PXAlertViewDemo/PXAlertViewDemo-Prefix.pch";
455 | GCC_PREPROCESSOR_DEFINITIONS = (
456 | "DEBUG=1",
457 | "$(inherited)",
458 | );
459 | INFOPLIST_FILE = "PXAlertViewDemoTests/PXAlertViewDemoTests-Info.plist";
460 | PRODUCT_BUNDLE_IDENTIFIER = "uk.co.panaxiom.${PRODUCT_NAME:rfc1034identifier}";
461 | PRODUCT_NAME = "$(TARGET_NAME)";
462 | TEST_HOST = "$(BUNDLE_LOADER)";
463 | WRAPPER_EXTENSION = xctest;
464 | };
465 | name = Debug;
466 | };
467 | FA11B6B817F3867100236222 /* Release */ = {
468 | isa = XCBuildConfiguration;
469 | buildSettings = {
470 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/PXAlertViewDemo.app/PXAlertViewDemo";
471 | FRAMEWORK_SEARCH_PATHS = (
472 | "$(SDKROOT)/Developer/Library/Frameworks",
473 | "$(inherited)",
474 | "$(DEVELOPER_FRAMEWORKS_DIR)",
475 | );
476 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
477 | GCC_PREFIX_HEADER = "PXAlertViewDemo/PXAlertViewDemo-Prefix.pch";
478 | INFOPLIST_FILE = "PXAlertViewDemoTests/PXAlertViewDemoTests-Info.plist";
479 | PRODUCT_BUNDLE_IDENTIFIER = "uk.co.panaxiom.${PRODUCT_NAME:rfc1034identifier}";
480 | PRODUCT_NAME = "$(TARGET_NAME)";
481 | TEST_HOST = "$(BUNDLE_LOADER)";
482 | WRAPPER_EXTENSION = xctest;
483 | };
484 | name = Release;
485 | };
486 | /* End XCBuildConfiguration section */
487 |
488 | /* Begin XCConfigurationList section */
489 | FA11B67917F3867100236222 /* Build configuration list for PBXProject "PXAlertViewDemo" */ = {
490 | isa = XCConfigurationList;
491 | buildConfigurations = (
492 | FA11B6B117F3867100236222 /* Debug */,
493 | FA11B6B217F3867100236222 /* Release */,
494 | );
495 | defaultConfigurationIsVisible = 0;
496 | defaultConfigurationName = Release;
497 | };
498 | FA11B6B317F3867100236222 /* Build configuration list for PBXNativeTarget "PXAlertViewDemo" */ = {
499 | isa = XCConfigurationList;
500 | buildConfigurations = (
501 | FA11B6B417F3867100236222 /* Debug */,
502 | FA11B6B517F3867100236222 /* Release */,
503 | );
504 | defaultConfigurationIsVisible = 0;
505 | defaultConfigurationName = Release;
506 | };
507 | FA11B6B617F3867100236222 /* Build configuration list for PBXNativeTarget "PXAlertViewDemoTests" */ = {
508 | isa = XCConfigurationList;
509 | buildConfigurations = (
510 | FA11B6B717F3867100236222 /* Debug */,
511 | FA11B6B817F3867100236222 /* Release */,
512 | );
513 | defaultConfigurationIsVisible = 0;
514 | defaultConfigurationName = Release;
515 | };
516 | /* End XCConfigurationList section */
517 | };
518 | rootObject = FA11B67617F3867100236222 /* Project object */;
519 | }
520 |
--------------------------------------------------------------------------------
/Classes/PXAlertView.m:
--------------------------------------------------------------------------------
1 | //
2 | // PXAlertView.m
3 | // PXAlertViewDemo
4 | //
5 | // Created by Alex Jarvis on 25/09/2013.
6 | // Copyright (c) 2013 Panaxiom Ltd. All rights reserved.
7 | //
8 |
9 | #import "PXAlertView.h"
10 |
11 | @interface PXAlertViewStack : NSObject
12 |
13 | @property (nonatomic) NSMutableArray *alertViews;
14 |
15 | + (PXAlertViewStack *)sharedInstance;
16 |
17 | - (void)push:(PXAlertView *)alertView;
18 | - (void)pop:(PXAlertView *)alertView;
19 |
20 | @end
21 |
22 | static const CGFloat AlertViewWidth = 270.0;
23 | static const CGFloat AlertViewContentMargin = 9;
24 | static const CGFloat AlertViewVerticalElementSpace = 10;
25 | static const CGFloat AlertViewButtonHeight = 44;
26 | static const CGFloat AlertViewLineLayerWidth = 0.5;
27 | static const CGFloat AlertViewVerticalEdgeMinMargin = 25;
28 |
29 |
30 | @interface PXAlertView ()
31 |
32 | @property (nonatomic) BOOL buttonsShouldStack;
33 | @property (nonatomic) UIWindow *mainWindow;
34 | @property (nonatomic) UIWindow *alertWindow;
35 | @property (nonatomic) UIView *backgroundView;
36 | @property (nonatomic) UIView *alertView;
37 | @property (nonatomic) UILabel *titleLabel;
38 | @property (nonatomic) UIView *contentView;
39 | @property (nonatomic) UIScrollView *messageScrollView;
40 | @property (nonatomic) UILabel *messageLabel;
41 | @property (nonatomic) UIButton *cancelButton;
42 | @property (nonatomic) UIButton *otherButton;
43 | @property (nonatomic) NSArray *buttons;
44 | @property (nonatomic) CGFloat buttonsY;
45 | @property (nonatomic) CALayer *verticalLine;
46 | @property (nonatomic) UITapGestureRecognizer *tap;
47 | @property (nonatomic, copy) void (^completion)(BOOL cancelled, NSInteger buttonIndex);
48 |
49 | @end
50 |
51 | @implementation PXAlertView
52 |
53 | - (UIWindow *)windowWithLevel:(UIWindowLevel)windowLevel
54 | {
55 | NSArray *windows = [[UIApplication sharedApplication] windows];
56 | for (UIWindow *window in windows) {
57 | if (window.windowLevel == windowLevel) {
58 | return window;
59 | }
60 | }
61 | return nil;
62 | }
63 |
64 | - (id)initWithTitle:(NSString *)title
65 | message:(NSString *)message
66 | cancelTitle:(NSString *)cancelTitle
67 | otherTitle:(NSString *)otherTitle
68 | buttonsShouldStack:(BOOL)shouldstack
69 | contentView:(UIView *)contentView
70 | completion:(PXAlertViewCompletionBlock)completion
71 | {
72 | return [self initWithTitle:title
73 | message:message
74 | cancelTitle:cancelTitle
75 | otherTitles:(otherTitle) ? @[ otherTitle ] : nil
76 | buttonsShouldStack:(BOOL)shouldstack
77 | contentView:contentView
78 | completion:completion];
79 | }
80 |
81 | - (id)initWithTitle:(NSString *)title
82 | message:(NSString *)message
83 | cancelTitle:(NSString *)cancelTitle
84 | otherTitles:(NSArray *)otherTitles
85 | buttonsShouldStack:(BOOL)shouldstack
86 | contentView:(UIView *)contentView
87 | completion:(PXAlertViewCompletionBlock)completion
88 | {
89 | self = [super init];
90 | if (self) {
91 | self.mainWindow = [self windowWithLevel:UIWindowLevelNormal];
92 |
93 | self.alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
94 | self.alertWindow.windowLevel = UIWindowLevelAlert;
95 | self.alertWindow.backgroundColor = [UIColor clearColor];
96 | self.alertWindow.rootViewController = self;
97 |
98 | CGRect frame = [self frameForOrientation];
99 | self.view.frame = frame;
100 |
101 | self.backgroundView = [[UIView alloc] initWithFrame:frame];
102 | self.backgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.25];
103 | self.backgroundView.alpha = 0;
104 | [self.view addSubview:self.backgroundView];
105 |
106 | self.alertView = [[UIView alloc] init];
107 | self.alertView.backgroundColor = [UIColor colorWithWhite:0.25 alpha:1];
108 | self.alertView.layer.cornerRadius = 8.0;
109 | self.alertView.layer.opacity = .95;
110 | self.alertView.clipsToBounds = YES;
111 | [self.view addSubview:self.alertView];
112 |
113 | // Title
114 | self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(AlertViewContentMargin,
115 | AlertViewVerticalElementSpace,
116 | AlertViewWidth - AlertViewContentMargin*2,
117 | 44)];
118 | self.titleLabel.text = title;
119 | self.titleLabel.backgroundColor = [UIColor clearColor];
120 | self.titleLabel.textColor = [UIColor whiteColor];
121 | self.titleLabel.textAlignment = NSTextAlignmentCenter;
122 | self.titleLabel.font = [UIFont boldSystemFontOfSize:17];
123 | self.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
124 | self.titleLabel.numberOfLines = 0;
125 | self.titleLabel.frame = [self adjustLabelFrameHeight:self.titleLabel];
126 | [self.alertView addSubview:self.titleLabel];
127 |
128 | CGFloat messageLabelY = self.titleLabel.frame.origin.y + self.titleLabel.frame.size.height + AlertViewVerticalElementSpace;
129 |
130 | // Optional Content View
131 | if (contentView) {
132 | self.contentView = contentView;
133 | self.contentView.frame = CGRectMake(0,
134 | messageLabelY,
135 | self.contentView.frame.size.width,
136 | self.contentView.frame.size.height);
137 | self.contentView.center = CGPointMake(AlertViewWidth/2, self.contentView.center.y);
138 | [self.alertView addSubview:self.contentView];
139 | messageLabelY += contentView.frame.size.height + AlertViewVerticalElementSpace;
140 | }
141 |
142 | // Message
143 | self.messageScrollView = [[UIScrollView alloc] initWithFrame:(CGRect){
144 | AlertViewContentMargin,
145 | messageLabelY,
146 | AlertViewWidth - AlertViewContentMargin*2,
147 | 44}];
148 | self.messageScrollView.scrollEnabled = YES;
149 |
150 | self.messageLabel = [[UILabel alloc] initWithFrame:(CGRect){0, 0,
151 | self.messageScrollView.frame.size}];
152 | self.messageLabel.text = message;
153 | self.messageLabel.backgroundColor = [UIColor clearColor];
154 | self.messageLabel.textColor = [UIColor whiteColor];
155 | self.messageLabel.textAlignment = NSTextAlignmentCenter;
156 | self.messageLabel.font = [UIFont systemFontOfSize:15];
157 | self.messageLabel.lineBreakMode = NSLineBreakByWordWrapping;
158 | self.messageLabel.numberOfLines = 0;
159 | self.messageLabel.frame = [self adjustLabelFrameHeight:self.messageLabel];
160 | self.messageScrollView.contentSize = self.messageLabel.frame.size;
161 |
162 | [self.messageScrollView addSubview:self.messageLabel];
163 | [self.alertView addSubview:self.messageScrollView];
164 |
165 | // Get total button height
166 | CGFloat totalBottomHeight = AlertViewLineLayerWidth;
167 | if(self.buttonsShouldStack)
168 | {
169 | if(cancelTitle)
170 | {
171 | totalBottomHeight += AlertViewButtonHeight;
172 | }
173 | if (otherTitles && [otherTitles count] > 0)
174 | {
175 | totalBottomHeight += (AlertViewButtonHeight + AlertViewLineLayerWidth) * [otherTitles count];
176 | }
177 | }
178 | else
179 | {
180 | totalBottomHeight += AlertViewButtonHeight;
181 | }
182 |
183 | self.messageScrollView.frame = (CGRect) {
184 | self.messageScrollView.frame.origin,
185 | self.messageScrollView.frame.size.width,
186 | MIN(self.messageLabel.frame.size.height, self.alertWindow.frame.size.height - self.messageScrollView.frame.origin.y - totalBottomHeight - AlertViewVerticalEdgeMinMargin * 2)
187 | };
188 |
189 | // Line
190 | CALayer *lineLayer = [self lineLayer];
191 | lineLayer.frame = CGRectMake(0, self.messageScrollView.frame.origin.y + self.messageScrollView.frame.size.height + AlertViewVerticalElementSpace, AlertViewWidth, AlertViewLineLayerWidth);
192 | [self.alertView.layer addSublayer:lineLayer];
193 |
194 | self.buttonsY = lineLayer.frame.origin.y + lineLayer.frame.size.height;
195 |
196 | // Buttons
197 | self.buttonsShouldStack = shouldstack;
198 |
199 | if (cancelTitle) {
200 | [self addButtonWithTitle:cancelTitle];
201 | } else {
202 | [self addButtonWithTitle:NSLocalizedString(@"Ok", nil)];
203 | }
204 |
205 | if (otherTitles && [otherTitles count] > 0) {
206 | for (id otherTitle in otherTitles) {
207 | NSParameterAssert([otherTitle isKindOfClass:[NSString class]]);
208 | [self addButtonWithTitle:(NSString *)otherTitle];
209 | }
210 | }
211 |
212 | self.alertView.bounds = CGRectMake(0, 0, AlertViewWidth, 150);
213 |
214 | if (completion) {
215 | self.completion = completion;
216 | }
217 |
218 | [self resizeViews];
219 |
220 | self.alertView.center = [self centerWithFrame:frame];
221 |
222 | [self setupGestures];
223 |
224 | if ((self = [super init])) {
225 | NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
226 | [center addObserver:self selector:@selector(keyboardWillShown:) name:UIKeyboardWillShowNotification object:nil];
227 | [center addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
228 | }
229 | return self;
230 | }
231 | return self;
232 | }
233 |
234 | - (void)keyboardWillShown:(NSNotification*)notification
235 | {
236 | if(self.isVisible)
237 | {
238 | CGRect keyboardFrameBeginRect = [[[notification userInfo] valueForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
239 | if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8 && (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft || self.interfaceOrientation == UIInterfaceOrientationLandscapeRight)) {
240 | keyboardFrameBeginRect = (CGRect){keyboardFrameBeginRect.origin.y, keyboardFrameBeginRect.origin.x, keyboardFrameBeginRect.size.height, keyboardFrameBeginRect.size.width};
241 | }
242 | CGRect interfaceFrame = [self frameForOrientation];
243 |
244 | if(interfaceFrame.size.height - keyboardFrameBeginRect.size.height <= _alertView.frame.size.height + _alertView.frame.origin.y)
245 | {
246 | [UIView animateWithDuration:.35 delay:0 options:0x70000 animations:^(void)
247 | {
248 | _alertView.frame = (CGRect){_alertView.frame.origin.x, interfaceFrame.size.height - keyboardFrameBeginRect.size.height - _alertView.frame.size.height - 20, _alertView.frame.size};
249 | } completion:nil];
250 | }
251 | }
252 | }
253 |
254 | - (void)keyboardWillHide:(NSNotification*)notification
255 | {
256 | if(self.isVisible)
257 | {
258 | [UIView animateWithDuration:.35 delay:0 options:0x70000 animations:^(void)
259 | {
260 | _alertView.center = [self centerWithFrame:[self frameForOrientation]];
261 | } completion:nil];
262 | }
263 | }
264 |
265 | - (CGRect)frameForOrientation
266 | {
267 | UIWindow *window = [[UIApplication sharedApplication].windows count] > 0 ? [[UIApplication sharedApplication].windows objectAtIndex:0] : nil;
268 | if (!window)
269 | window = [UIApplication sharedApplication].keyWindow;
270 | if([[window subviews] count] > 0)
271 | {
272 | return [[[window subviews] objectAtIndex:0] bounds];
273 | }
274 | return [[self windowWithLevel:UIWindowLevelNormal] bounds];
275 | }
276 |
277 | - (CGRect)adjustLabelFrameHeight:(UILabel *)label
278 | {
279 | CGFloat height;
280 |
281 | if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
282 | #pragma clang diagnostic push
283 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
284 | CGSize size = [label.text sizeWithFont:label.font
285 | constrainedToSize:CGSizeMake(label.frame.size.width, FLT_MAX)
286 | lineBreakMode:NSLineBreakByWordWrapping];
287 |
288 | height = size.height;
289 | #pragma clang diagnostic pop
290 | } else {
291 | NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
292 | context.minimumScaleFactor = 1.0;
293 | CGRect bounds = [label.text boundingRectWithSize:CGSizeMake(label.frame.size.width, FLT_MAX)
294 | options:NSStringDrawingUsesLineFragmentOrigin
295 | attributes:@{NSFontAttributeName:label.font}
296 | context:context];
297 | height = bounds.size.height;
298 | }
299 |
300 | return CGRectMake(label.frame.origin.x, label.frame.origin.y, label.frame.size.width, height);
301 | }
302 |
303 | - (UIButton *)genericButton
304 | {
305 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
306 | button.backgroundColor = [UIColor clearColor];
307 | button.titleLabel.font = [UIFont systemFontOfSize:17];
308 | button.titleLabel.adjustsFontSizeToFitWidth = YES;
309 | button.titleEdgeInsets = UIEdgeInsetsMake(2, 2, 2, 2);
310 | [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
311 | [button setTitleColor:[UIColor colorWithWhite:0.25 alpha:1] forState:UIControlStateHighlighted];
312 | [button addTarget:self action:@selector(dismiss:) forControlEvents:UIControlEventTouchUpInside];
313 | [button addTarget:self action:@selector(setBackgroundColorForButton:) forControlEvents:UIControlEventTouchDown];
314 | [button addTarget:self action:@selector(setBackgroundColorForButton:) forControlEvents:UIControlEventTouchDragEnter];
315 | [button addTarget:self action:@selector(clearBackgroundColorForButton:) forControlEvents:UIControlEventTouchDragExit];
316 | return button;
317 | }
318 |
319 | - (CGPoint)centerWithFrame:(CGRect)frame
320 | {
321 | return CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame) - [self statusBarOffset]);
322 | }
323 |
324 | - (CGFloat)statusBarOffset
325 | {
326 | CGFloat statusBarOffset = 0;
327 | if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
328 | statusBarOffset = 20;
329 | }
330 | return statusBarOffset;
331 | }
332 |
333 | - (void)setupGestures
334 | {
335 | self.tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismiss:)];
336 | [self.tap setNumberOfTapsRequired:1];
337 | [self.backgroundView setUserInteractionEnabled:YES];
338 | [self.backgroundView setMultipleTouchEnabled:NO];
339 | [self.backgroundView addGestureRecognizer:self.tap];
340 | }
341 |
342 | - (void)resizeViews
343 | {
344 | CGFloat totalHeight = 0;
345 | for (UIView *view in [self.alertView subviews]) {
346 | if ([view class] != [UIButton class]) {
347 | totalHeight += view.frame.size.height + AlertViewVerticalElementSpace;
348 | }
349 | }
350 | if (self.buttons) {
351 | NSUInteger otherButtonsCount = [self.buttons count];
352 | if (self.buttonsShouldStack) {
353 | totalHeight += AlertViewButtonHeight * otherButtonsCount;
354 | } else {
355 | totalHeight += AlertViewButtonHeight * (otherButtonsCount > 2 ? otherButtonsCount : 1);
356 | }
357 | }
358 | totalHeight += AlertViewVerticalElementSpace;
359 |
360 | self.alertView.frame = CGRectMake(self.alertView.frame.origin.x,
361 | self.alertView.frame.origin.y,
362 | self.alertView.frame.size.width,
363 | MIN(totalHeight, self.alertWindow.frame.size.height));
364 | }
365 |
366 | - (void)setBackgroundColorForButton:(id)sender
367 | {
368 | [sender setBackgroundColor:[UIColor colorWithRed:94/255.0 green:196/255.0 blue:221/255.0 alpha:1.0]];
369 | }
370 |
371 | - (void)clearBackgroundColorForButton:(id)sender
372 | {
373 | [sender setBackgroundColor:[UIColor clearColor]];
374 | }
375 |
376 | - (void)show
377 | {
378 | [[PXAlertViewStack sharedInstance] push:self];
379 | }
380 |
381 | - (void)showInternal
382 | {
383 | [self.alertWindow addSubview:self.view];
384 | [self.alertWindow makeKeyAndVisible];
385 | self.visible = YES;
386 | [self showBackgroundView];
387 | [self showAlertAnimation];
388 | }
389 |
390 | - (void)showBackgroundView
391 | {
392 | if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
393 | self.mainWindow.tintAdjustmentMode = UIViewTintAdjustmentModeDimmed;
394 | [self.mainWindow tintColorDidChange];
395 | }
396 | [UIView animateWithDuration:0.3 animations:^{
397 | self.backgroundView.alpha = 1;
398 | }];
399 | }
400 |
401 | - (void)hide
402 | {
403 | [self.view removeFromSuperview];
404 | }
405 |
406 | - (void)dismiss
407 | {
408 | [self dismiss:nil];
409 | }
410 |
411 | - (void)dismiss:(id)sender
412 | {
413 | [self dismiss:sender animated:YES];
414 | }
415 |
416 | - (void)dismiss:(id)sender animated:(BOOL)animated
417 | {
418 | self.visible = NO;
419 |
420 | [UIView animateWithDuration:(animated ? 0.2 : 0) animations:^{
421 | self.alertView.alpha = 0;
422 | self.alertWindow.alpha = 0;
423 | } completion:^(BOOL finished) {
424 | if (self.completion) {
425 | BOOL cancelled = NO;
426 | if (sender == self.cancelButton || sender == self.tap) {
427 | cancelled = YES;
428 | }
429 | NSInteger buttonIndex = -1;
430 | if (self.buttons) {
431 | NSUInteger index = [self.buttons indexOfObject:sender];
432 | if (index != NSNotFound) {
433 | buttonIndex = index;
434 | }
435 | }
436 | if (sender) {
437 | self.completion(cancelled, buttonIndex);
438 | }
439 | }
440 |
441 | if ([[[PXAlertViewStack sharedInstance] alertViews] count] == 1) {
442 | if (animated) {
443 | [self dismissAlertAnimation];
444 | }
445 | if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
446 | self.mainWindow.tintAdjustmentMode = UIViewTintAdjustmentModeAutomatic;
447 | [self.mainWindow tintColorDidChange];
448 | }
449 | [UIView animateWithDuration:(animated ? 0.2 : 0) animations:^{
450 | self.backgroundView.alpha = 0;
451 | [self.alertWindow setHidden:YES];
452 | [self.alertWindow removeFromSuperview];
453 | self.alertWindow.rootViewController = nil;
454 | self.alertWindow = nil;
455 | } completion:^(BOOL finished) {
456 | [self.mainWindow makeKeyAndVisible];
457 | }];
458 | }
459 |
460 | [[PXAlertViewStack sharedInstance] pop:self];
461 | }];
462 | }
463 |
464 | - (void)showAlertAnimation
465 | {
466 | CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
467 |
468 | animation.values = @[[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.2, 1.2, 1)],
469 | [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.05, 1.05, 1)],
470 | [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 1)]];
471 | animation.keyTimes = @[ @0, @0.5, @1 ];
472 | animation.fillMode = kCAFillModeForwards;
473 | animation.removedOnCompletion = NO;
474 | animation.duration = .3;
475 |
476 | [self.alertView.layer addAnimation:animation forKey:@"showAlert"];
477 | }
478 |
479 | - (void)dismissAlertAnimation
480 | {
481 | CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
482 |
483 | animation.values = @[[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 1)],
484 | [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.95, 0.95, 1)],
485 | [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.8, 0.8, 1)]];
486 | animation.keyTimes = @[ @0, @0.5, @1 ];
487 | animation.fillMode = kCAFillModeRemoved;
488 | animation.duration = .2;
489 |
490 | [self.alertView.layer addAnimation:animation forKey:@"dismissAlert"];
491 | }
492 |
493 | - (CALayer *)lineLayer
494 | {
495 | CALayer *lineLayer = [CALayer layer];
496 | lineLayer.backgroundColor = [[UIColor colorWithWhite:0.90 alpha:0.3] CGColor];
497 | return lineLayer;
498 | }
499 |
500 | #pragma mark -
501 | #pragma mark UIViewController
502 |
503 | - (BOOL)prefersStatusBarHidden
504 | {
505 | return [UIApplication sharedApplication].statusBarHidden;
506 | }
507 |
508 | - (BOOL)shouldAutorotate
509 | {
510 | return YES;
511 | }
512 |
513 | - (UIInterfaceOrientationMask)supportedInterfaceOrientations
514 | {
515 | return UIInterfaceOrientationMaskAll;
516 | }
517 |
518 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
519 | {
520 | return YES;
521 | }
522 |
523 | - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
524 | {
525 | CGRect frame = [self frameForOrientation];
526 | self.backgroundView.frame = frame;
527 | self.alertView.center = [self centerWithFrame:frame];
528 | }
529 |
530 | #pragma mark -
531 | #pragma mark Public
532 |
533 | + (instancetype)showAlertWithTitle:(NSString *)title
534 | {
535 | return [[self class] showAlertWithTitle:title message:nil cancelTitle:NSLocalizedString(@"Ok", nil) completion:nil];
536 | }
537 |
538 | + (instancetype)showAlertWithTitle:(NSString *)title
539 | message:(NSString *)message
540 | {
541 | return [[self class] showAlertWithTitle:title message:message cancelTitle:NSLocalizedString(@"Ok", nil) completion:nil];
542 | }
543 |
544 | + (instancetype)showAlertWithTitle:(NSString *)title
545 | message:(NSString *)message
546 | completion:(PXAlertViewCompletionBlock)completion
547 | {
548 | return [[self class] showAlertWithTitle:title message:message cancelTitle:NSLocalizedString(@"Ok", nil) completion:completion];
549 | }
550 |
551 | + (instancetype)showAlertWithTitle:(NSString *)title
552 | message:(NSString *)message
553 | cancelTitle:(NSString *)cancelTitle
554 | completion:(PXAlertViewCompletionBlock)completion
555 | {
556 | PXAlertView *alertView = [[self alloc] initWithTitle:title
557 | message:message
558 | cancelTitle:cancelTitle
559 | otherTitle:nil
560 | buttonsShouldStack:NO
561 | contentView:nil
562 | completion:completion];
563 | [alertView show];
564 | return alertView;
565 | }
566 |
567 | + (instancetype)showAlertWithTitle:(NSString *)title
568 | message:(NSString *)message
569 | cancelTitle:(NSString *)cancelTitle
570 | otherTitle:(NSString *)otherTitle
571 | completion:(PXAlertViewCompletionBlock)completion
572 | {
573 | PXAlertView *alertView = [[self alloc] initWithTitle:title
574 | message:message
575 | cancelTitle:cancelTitle
576 | otherTitle:otherTitle
577 | buttonsShouldStack:NO
578 | contentView:nil
579 | completion:completion];
580 | [alertView show];
581 | return alertView;
582 | }
583 |
584 | + (instancetype)showAlertWithTitle:(NSString *)title
585 | message:(NSString *)message
586 | cancelTitle:(NSString *)cancelTitle
587 | otherTitle:(NSString *)otherTitle
588 | buttonsShouldStack:(BOOL)shouldStack
589 | completion:(PXAlertViewCompletionBlock)completion
590 | {
591 | PXAlertView *alertView = [[self alloc] initWithTitle:title
592 | message:message
593 | cancelTitle:cancelTitle
594 | otherTitle:otherTitle
595 | buttonsShouldStack:shouldStack
596 | contentView:nil
597 | completion:completion];
598 | [alertView show];
599 | return alertView;
600 | }
601 |
602 | + (instancetype)showAlertWithTitle:(NSString *)title
603 | message:(NSString *)message
604 | cancelTitle:(NSString *)cancelTitle
605 | otherTitles:(NSArray *)otherTitles
606 | completion:(PXAlertViewCompletionBlock)completion
607 | {
608 | PXAlertView *alertView = [[self alloc] initWithTitle:title
609 | message:message
610 | cancelTitle:cancelTitle
611 | otherTitles:otherTitles
612 | buttonsShouldStack:NO
613 | contentView:nil
614 | completion:completion];
615 | [alertView show];
616 | return alertView;
617 | }
618 |
619 | + (instancetype)showAlertWithTitle:(NSString *)title
620 | message:(NSString *)message
621 | cancelTitle:(NSString *)cancelTitle
622 | otherTitle:(NSString *)otherTitle
623 | contentView:(UIView *)view
624 | completion:(PXAlertViewCompletionBlock)completion
625 | {
626 | PXAlertView *alertView = [[self alloc] initWithTitle:title
627 | message:message
628 | cancelTitle:cancelTitle
629 | otherTitle:otherTitle
630 | buttonsShouldStack:NO
631 | contentView:view
632 | completion:completion];
633 | [alertView show];
634 | return alertView;
635 | }
636 |
637 | + (instancetype)showAlertWithTitle:(NSString *)title
638 | message:(NSString *)message
639 | cancelTitle:(NSString *)cancelTitle
640 | otherTitle:(NSString *)otherTitle
641 | buttonsShouldStack:(BOOL)shouldStack
642 | contentView:(UIView *)view
643 | completion:(PXAlertViewCompletionBlock)completion
644 | {
645 | PXAlertView *alertView = [[self alloc] initWithTitle:title
646 | message:message
647 | cancelTitle:cancelTitle
648 | otherTitle:otherTitle
649 | buttonsShouldStack:shouldStack
650 | contentView:view
651 | completion:completion];
652 | [alertView show];
653 | return alertView;
654 | }
655 |
656 |
657 | + (instancetype)showAlertWithTitle:(NSString *)title
658 | message:(NSString *)message
659 | cancelTitle:(NSString *)cancelTitle
660 | otherTitles:(NSArray *)otherTitles
661 | contentView:(UIView *)view
662 | completion:(PXAlertViewCompletionBlock)completion
663 | {
664 | PXAlertView *alertView = [[self alloc] initWithTitle:title
665 | message:message
666 | cancelTitle:cancelTitle
667 | otherTitles:otherTitles
668 | buttonsShouldStack:NO
669 | contentView:view
670 | completion:completion];
671 | [alertView show];
672 | return alertView;
673 | }
674 |
675 | - (NSInteger)addButtonWithTitle:(NSString *)title
676 | {
677 | UIButton *button = [self genericButton];
678 | [button setTitle:title forState:UIControlStateNormal];
679 |
680 | if (!self.cancelButton) {
681 | button.titleLabel.font = [UIFont boldSystemFontOfSize:17];
682 | self.cancelButton = button;
683 | self.cancelButton.frame = CGRectMake(0, self.buttonsY, AlertViewWidth, AlertViewButtonHeight);
684 | } else if (self.buttonsShouldStack) {
685 | button.titleLabel.font = [UIFont systemFontOfSize:17];
686 | self.otherButton = button;
687 |
688 | button.frame = self.cancelButton.frame;
689 |
690 | CGFloat lastButtonYOffset = self.cancelButton.frame.origin.y + AlertViewButtonHeight;
691 | self.cancelButton.frame = CGRectMake(0, lastButtonYOffset, AlertViewWidth, AlertViewButtonHeight);
692 |
693 | CALayer *lineLayer = [self lineLayer];
694 | lineLayer.frame = CGRectMake(0, lastButtonYOffset, AlertViewWidth, AlertViewLineLayerWidth);
695 | [self.alertView.layer addSublayer:lineLayer];
696 | } else if (self.buttons && [self.buttons count] > 1) {
697 | UIButton *lastButton = (UIButton *)[self.buttons lastObject];
698 | lastButton.titleLabel.font = [UIFont systemFontOfSize:17];
699 | if ([self.buttons count] == 2) {
700 | [self.verticalLine removeFromSuperlayer];
701 | CALayer *lineLayer = [self lineLayer];
702 | lineLayer.frame = CGRectMake(0, self.buttonsY + AlertViewButtonHeight, AlertViewWidth, AlertViewLineLayerWidth);
703 | [self.alertView.layer addSublayer:lineLayer];
704 | lastButton.frame = CGRectMake(0, self.buttonsY + AlertViewButtonHeight, AlertViewWidth, AlertViewButtonHeight);
705 | self.cancelButton.frame = CGRectMake(0, self.buttonsY, AlertViewWidth, AlertViewButtonHeight);
706 | }
707 | CGFloat lastButtonYOffset = lastButton.frame.origin.y + AlertViewButtonHeight;
708 | button.frame = CGRectMake(0, lastButtonYOffset, AlertViewWidth, AlertViewButtonHeight);
709 | } else {
710 | self.verticalLine = [self lineLayer];
711 | self.verticalLine.frame = CGRectMake(AlertViewWidth/2, self.buttonsY, AlertViewLineLayerWidth, AlertViewButtonHeight);
712 | [self.alertView.layer addSublayer:self.verticalLine];
713 | button.frame = CGRectMake(AlertViewWidth/2, self.buttonsY, AlertViewWidth/2, AlertViewButtonHeight);
714 | self.otherButton = button;
715 | self.cancelButton.frame = CGRectMake(0, self.buttonsY, AlertViewWidth/2, AlertViewButtonHeight);
716 | self.cancelButton.titleLabel.font = [UIFont systemFontOfSize:17];
717 | }
718 |
719 | [self.alertView addSubview:button];
720 | self.buttons = (self.buttons) ? [self.buttons arrayByAddingObject:button] : @[ button ];
721 | return [self.buttons count] - 1;
722 | }
723 |
724 | - (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated
725 | {
726 | if (buttonIndex >= 0 && buttonIndex < [self.buttons count]) {
727 | [self dismiss:self.buttons[buttonIndex] animated:animated];
728 | }
729 | }
730 |
731 | - (void)setTapToDismissEnabled:(BOOL)enabled
732 | {
733 | self.tap.enabled = enabled;
734 | }
735 |
736 | @end
737 |
738 | @implementation PXAlertViewStack
739 |
740 | + (instancetype)sharedInstance
741 | {
742 | static PXAlertViewStack *_sharedInstance = nil;
743 | static dispatch_once_t onceToken;
744 | dispatch_once(&onceToken, ^{
745 | _sharedInstance = [[PXAlertViewStack alloc] init];
746 | _sharedInstance.alertViews = [NSMutableArray array];
747 | });
748 |
749 | return _sharedInstance;
750 | }
751 |
752 | - (void)push:(PXAlertView *)alertView
753 | {
754 | for (PXAlertView *av in self.alertViews) {
755 | if (av != alertView) {
756 | [av hide];
757 | }
758 | else {
759 | return;
760 | }
761 | }
762 | [self.alertViews addObject:alertView];
763 | [alertView showInternal];
764 | }
765 |
766 | - (void)pop:(PXAlertView *)alertView
767 | {
768 | [alertView hide];
769 | [self.alertViews removeObject:alertView];
770 | PXAlertView *last = [self.alertViews lastObject];
771 | if (last && !last.view.superview) {
772 | [last showInternal];
773 | }
774 | }
775 |
776 | @end
777 |
--------------------------------------------------------------------------------