├── .gitignore ├── Classes ├── PXAlertView+Customization.h ├── PXAlertView+Customization.m ├── PXAlertView.h ├── PXAlertView.m ├── UIAlertView+PXAlertViewOverride.h └── UIAlertView+PXAlertViewOverride.m ├── ExampleImage.png ├── LICENSE ├── PXAlertView.podspec ├── PXAlertViewDemo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── alex.xcuserdatad │ └── xcschemes │ ├── PXAlertViewDemo.xcscheme │ └── xcschememanagement.plist ├── PXAlertViewDemo ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json ├── LaunchScreen.storyboard ├── PXAlertViewDemo-Info.plist ├── PXAlertViewDemo-Prefix.pch ├── PXAppDelegate.h ├── PXAppDelegate.m ├── PXViewController.h ├── PXViewController.m ├── en.lproj │ ├── InfoPlist.strings │ └── Main.storyboard └── main.m ├── PXAlertViewDemoTests ├── PXAlertViewDemoTests-Info.plist ├── PXAlertViewDemoTests.m └── en.lproj │ └── InfoPlist.strings ├── README.md └── animation.gif /.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 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ExampleImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderjarvis/PXAlertView/f2635c0b0cafdcf1069914ce04c55ecff31eb6a5/ExampleImage.png -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /PXAlertViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | } -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /PXAlertViewDemo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /PXAlertViewDemoTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /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 | ![Demo Animation](animation.gif) 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 | -------------------------------------------------------------------------------- /animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderjarvis/PXAlertView/f2635c0b0cafdcf1069914ce04c55ecff31eb6a5/animation.gif --------------------------------------------------------------------------------