Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 37fb05d160f33bc8173891f8b18cf5cc5aef0ea4 1 parent e37df1c
@warrenm authored
View
42 .gitignore
@@ -0,0 +1,42 @@
+# XCode 4 .gitignore Template
+# Originally created by Gary Longsine
+# Extended for XCode 4 by Tod Karpinski
+# Compiled by Warren Moore
+
+# Mac OS X Finder and whatnot
+.DS_Store
+
+# Sparkle distribution Private Key
+dsa_priv.pem
+
+# XCode (and ancestors) per-user config
+*.mode1
+*.mode1v3
+*.mode2v3
+*.perspective
+*.perspectivev3
+*.pbxuser
+*.xcworkspace/
+xcuserdata/
+
+# Generated files
+VersionX-revision.h
+
+# build products
+build/
+*.[oa]
+
+# Other source repository archive directories (protects when importing)
+.hg
+.svn
+CVS
+
+# Automatic backup files
+*~.nib
+*.swp
+*.orig
+*~
+*(Autosaved).rtfd/
+Backup[ ]of[ ]*.pages/
+Backup[ ]of[ ]*.key/
+Backup[ ]of[ ]*.numbers/
View
25 AHAlertViewSample.xcodeproj/project.pbxproj
@@ -7,15 +7,19 @@
objects = {
/* Begin PBXBuildFile section */
+ 805A82B715FFF5200024B7CC /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 805A82B615FFF5200024B7CC /* QuartzCore.framework */; };
80C6F10415FE54A900ABF313 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80C6F10315FE54A900ABF313 /* UIKit.framework */; };
80C6F10615FE54A900ABF313 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80C6F10515FE54A900ABF313 /* Foundation.framework */; };
80C6F10815FE54A900ABF313 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80C6F10715FE54A900ABF313 /* CoreGraphics.framework */; };
80C6F10E15FE54A900ABF313 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 80C6F10C15FE54A900ABF313 /* InfoPlist.strings */; };
80C6F11015FE54A900ABF313 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 80C6F10F15FE54A900ABF313 /* main.m */; };
80C6F11415FE54A900ABF313 /* AHAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 80C6F11315FE54A900ABF313 /* AHAppDelegate.m */; };
+ 80C6F11C15FE54E900ABF313 /* AHAlertSampleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 80C6F11B15FE54E900ABF313 /* AHAlertSampleViewController.m */; };
+ 80C6F12015FE551000ABF313 /* AHAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = 80C6F11F15FE551000ABF313 /* AHAlertView.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
+ 805A82B615FFF5200024B7CC /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
80C6F0FF15FE54A900ABF313 /* AHAlertViewSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AHAlertViewSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
80C6F10315FE54A900ABF313 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
80C6F10515FE54A900ABF313 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
@@ -26,6 +30,10 @@
80C6F11115FE54A900ABF313 /* AHAlertViewSample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AHAlertViewSample-Prefix.pch"; sourceTree = "<group>"; };
80C6F11215FE54A900ABF313 /* AHAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AHAppDelegate.h; sourceTree = "<group>"; };
80C6F11315FE54A900ABF313 /* AHAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AHAppDelegate.m; sourceTree = "<group>"; };
+ 80C6F11A15FE54E900ABF313 /* AHAlertSampleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AHAlertSampleViewController.h; sourceTree = "<group>"; };
+ 80C6F11B15FE54E900ABF313 /* AHAlertSampleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AHAlertSampleViewController.m; sourceTree = "<group>"; };
+ 80C6F11E15FE551000ABF313 /* AHAlertView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AHAlertView.h; sourceTree = "<group>"; };
+ 80C6F11F15FE551000ABF313 /* AHAlertView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AHAlertView.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -33,6 +41,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 805A82B715FFF5200024B7CC /* QuartzCore.framework in Frameworks */,
80C6F10415FE54A900ABF313 /* UIKit.framework in Frameworks */,
80C6F10615FE54A900ABF313 /* Foundation.framework in Frameworks */,
80C6F10815FE54A900ABF313 /* CoreGraphics.framework in Frameworks */,
@@ -65,6 +74,7 @@
80C6F10315FE54A900ABF313 /* UIKit.framework */,
80C6F10515FE54A900ABF313 /* Foundation.framework */,
80C6F10715FE54A900ABF313 /* CoreGraphics.framework */,
+ 805A82B615FFF5200024B7CC /* QuartzCore.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -72,6 +82,9 @@
80C6F10915FE54A900ABF313 /* AHAlertViewSample */ = {
isa = PBXGroup;
children = (
+ 80C6F11D15FE54FF00ABF313 /* AHAlertView */,
+ 80C6F11A15FE54E900ABF313 /* AHAlertSampleViewController.h */,
+ 80C6F11B15FE54E900ABF313 /* AHAlertSampleViewController.m */,
80C6F11215FE54A900ABF313 /* AHAppDelegate.h */,
80C6F11315FE54A900ABF313 /* AHAppDelegate.m */,
80C6F10A15FE54A900ABF313 /* Supporting Files */,
@@ -90,6 +103,15 @@
name = "Supporting Files";
sourceTree = "<group>";
};
+ 80C6F11D15FE54FF00ABF313 /* AHAlertView */ = {
+ isa = PBXGroup;
+ children = (
+ 80C6F11E15FE551000ABF313 /* AHAlertView.h */,
+ 80C6F11F15FE551000ABF313 /* AHAlertView.m */,
+ );
+ name = AHAlertView;
+ sourceTree = "<group>";
+ };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -155,6 +177,8 @@
files = (
80C6F11015FE54A900ABF313 /* main.m in Sources */,
80C6F11415FE54A900ABF313 /* AHAppDelegate.m in Sources */,
+ 80C6F11C15FE54E900ABF313 /* AHAlertSampleViewController.m in Sources */,
+ 80C6F12015FE551000ABF313 /* AHAlertView.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -262,6 +286,7 @@
80C6F11915FE54A900ABF313 /* Release */,
);
defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
View
13 AHAlertViewSample/AHAlertSampleViewController.h
@@ -0,0 +1,13 @@
+//
+// AHAlertSampleViewController.h
+// AHAlertViewSample
+//
+// Created by Warren Moore on 9/10/12.
+// Copyright (c) 2012 Auerhaus Development, LLC. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface AHAlertSampleViewController : UIViewController
+
+@end
View
66 AHAlertViewSample/AHAlertSampleViewController.m
@@ -0,0 +1,66 @@
+//
+// AHAlertSampleViewController.m
+// AHAlertViewSample
+//
+// Created by Warren Moore on 9/10/12.
+// Copyright (c) 2012 Auerhaus Development, LLC. All rights reserved.
+//
+
+#import "AHAlertSampleViewController.h"
+#import "AHAlertView.h"
+
+#define UIViewAutoresizingFlexibleMargins 45
+
+@implementation AHAlertSampleViewController
+
+- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
+{
+ self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
+ if (self) {
+ }
+ return self;
+}
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+
+ self.view.backgroundColor = [UIColor grayColor];
+
+ UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
+ button.frame = CGRectMake(85, 225, 143, 44);
+ button.autoresizingMask = UIViewAutoresizingFlexibleMargins;
+
+ [button setTitle:@"Show Alert View" forState:UIControlStateNormal];
+ [button addTarget:self action:@selector(buttonWasPressed:) forControlEvents:UIControlEventTouchUpInside];
+ [self.view addSubview:button];
+}
+
+- (IBAction)buttonWasPressed:(id)sender {
+ NSString *message = @"Doyouthinkhesawus. Lorem ipsum perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium explicabo.";
+
+ static NSInteger dismissalStyle = 1;
+
+ AHAlertView *alert = [[AHAlertView alloc] initWithTitle:@"What Do You Call a Blind Dinosaur?" message:message];
+ [alert setCancelButtonTitle:@"Cancel" block:^{
+ alert.dismissalStyle = dismissalStyle;
+ dismissalStyle = (dismissalStyle + 1) % 5;
+ }];
+ [alert addButtonWithTitle:@"OK" block:^{
+ alert.dismissalStyle = dismissalStyle;
+ dismissalStyle = (dismissalStyle + 1) % 5;
+ }];
+ [alert show];
+}
+
+- (void)viewDidAppear:(BOOL)animated
+{
+ [super viewDidAppear:animated];
+}
+
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
+{
+ return YES;
+}
+
+@end
View
75 AHAlertViewSample/AHAlertView.h
@@ -0,0 +1,75 @@
+//
+// AHAlertView.h
+// AHAlertViewSample
+//
+// Created by Warren Moore on 9/10/12.
+//
+
+#import <UIKit/UIKit.h>
+
+typedef enum {
+ AHAlertViewStyleDefault = 0,
+ AHAlertViewStyleSecureTextInput,
+ AHAlertViewStylePlainTextInput,
+ AHAlertViewStyleLoginAndPasswordInput,
+} AHAlertViewStyle;
+
+typedef enum {
+ AHAlertViewPresentationStyleNone = 0,
+ AHAlertViewPresentationStylePop,
+ AHAlertViewPresentationStyleFade,
+
+ AHAlertViewPresentationStyleDefault = AHAlertViewPresentationStylePop
+} AHAlertViewPresentationStyle;
+
+typedef enum {
+ AHAlertViewDismissalStyleNone = 0,
+ AHAlertViewDismissalStyleZoomDown,
+ AHAlertViewDismissalStyleZoomOut,
+ AHAlertViewDismissalStyleFade,
+ AHAlertViewDismissalStyleTumble,
+
+ AHAlertViewDismissalStyleDefault = AHAlertViewDismissalStyleFade
+} AHAlertViewDismissalStyle;
+
+typedef void (^AHAlertViewButtonBlock)();
+
+@interface AHAlertView : UIView
+
+@property(nonatomic, copy) NSString *title;
+@property(nonatomic, copy) NSString *message;
+@property(nonatomic, readonly, assign, getter = isVisible) BOOL visible;
+@property(nonatomic, assign) AHAlertViewStyle alertViewStyle;
+@property(nonatomic, assign) AHAlertViewPresentationStyle presentationStyle;
+@property(nonatomic, assign) AHAlertViewDismissalStyle dismissalStyle;
+
+- (id)initWithTitle:(NSString *)title message:(NSString *)message;
+
+- (void)addButtonWithTitle:(NSString *)title block:(AHAlertViewButtonBlock)block;
+- (void)setDestructiveButtonTitle:(NSString *)title block:(AHAlertViewButtonBlock)block;
+- (void)setCancelButtonTitle:(NSString *)title block:(AHAlertViewButtonBlock)block;
+
+- (void)show;
+- (void)showWithStyle:(AHAlertViewPresentationStyle)presentationStyle;
+- (void)dismiss;
+- (void)dismissWithStyle:(AHAlertViewDismissalStyle)dismissalStyle;
+
+- (UITextField *)textFieldAtIndex:(NSInteger)textFieldIndex;
+
+@property(nonatomic, strong) UIImage *backgroundImage UI_APPEARANCE_SELECTOR;
+@property(nonatomic, assign) UIEdgeInsets contentInsets UI_APPEARANCE_SELECTOR;
+
+@property(nonatomic, copy) NSDictionary *titleTextAttributes UI_APPEARANCE_SELECTOR;
+@property(nonatomic, copy) NSDictionary *messageTextAttributes UI_APPEARANCE_SELECTOR;
+@property(nonatomic, copy) NSDictionary *buttonTitleTextAttributes UI_APPEARANCE_SELECTOR;
+
+- (void)setButtonBackgroundImage:(UIImage *)backgroundImage forState:(UIControlState)state UI_APPEARANCE_SELECTOR;
+- (UIImage *)buttonBackgroundImageForState:(UIControlState)state UI_APPEARANCE_SELECTOR;
+
+- (void)setCancelButtonBackgroundImage:(UIImage *)backgroundImage forState:(UIControlState)state UI_APPEARANCE_SELECTOR;
+- (UIImage *)cancelButtonBackgroundImageForState:(UIControlState)state UI_APPEARANCE_SELECTOR;
+
+- (void)setDestructiveButtonBackgroundImage:(UIImage *)backgroundImage forState:(UIControlState)state UI_APPEARANCE_SELECTOR;
+- (UIImage *)destructiveButtonBackgroundImageForState:(UIControlState)state UI_APPEARANCE_SELECTOR;
+
+@end
View
660 AHAlertViewSample/AHAlertView.m
@@ -0,0 +1,660 @@
+//
+// AHAlertView.m
+// AHAlertViewSample
+//
+// Created by Warren Moore on 9/10/12.
+//
+
+#import "AHAlertView.h"
+#import <QuartzCore/QuartzCore.h>
+#import <objc/runtime.h>
+
+static const char * const kAHAlertViewButtonBlockKey = "AHAlertViewButtonBlock";
+
+static const CGFloat AHAlertViewDefaultWidth = 276;
+static const CGFloat AHAlertViewMinimumHeight = 132;
+static const CGFloat AHAlertViewDefaultButtonHeight = 40;
+
+CGFloat CGAffineTransformGetAbsoluteRotationAngleDifference(CGAffineTransform t1, CGAffineTransform t2)
+{
+ CGFloat dot = t1.a * t2.a + t1.c * t2.c;
+ CGFloat n1 = sqrtf(t1.a * t1.a + t1.c * t1.c);
+ CGFloat n2 = sqrtf(t2.a * t2.a + t2.c * t2.c);
+ return acosf(dot / (n1 * n2));
+}
+
+#pragma mark - Internal interface
+
+typedef void (^AHAnimationCompletionBlock)(BOOL); // Internal.
+
+@interface AHAlertView () {
+ BOOL hasLayedOut;
+}
+
+@property (nonatomic, strong) UIImageView *backgroundImageView;
+@property (nonatomic, strong) UILabel *titleLabel;
+@property (nonatomic, strong) UILabel *messageLabel;
+@property (nonatomic, strong) UITextField *plainTextField;
+@property (nonatomic, strong) UITextField *secureTextField;
+@property (nonatomic, strong) UIButton *cancelButton;
+@property (nonatomic, strong) UIButton *destructiveButton;
+@property (nonatomic, strong) NSMutableArray *otherButtons;
+@property (nonatomic, strong) NSMutableDictionary *buttonBackgroundImagesForControlStates;
+@property (nonatomic, strong) NSMutableDictionary *cancelButtonBackgroundImagesForControlStates;
+@property (nonatomic, strong) NSMutableDictionary *destructiveButtonBackgroundImagesForControlStates;
+@end
+
+#pragma mark - Implementation
+
+@implementation AHAlertView
+
+#pragma mark - Class life cycle methods
+
++ (void)initialize
+{
+ // Set up default values for all UIAppearance-compatible selectors
+
+ [[self appearance] setBackgroundImage:[self alertBackgroundImage]];
+
+ [[self appearance] setContentInsets:UIEdgeInsetsMake(16, 8, 8, 8)];
+
+ [[self appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
+ [UIFont boldSystemFontOfSize:17], UITextAttributeFont,
+ [UIColor whiteColor], UITextAttributeTextColor,
+ [UIColor blackColor], UITextAttributeTextShadowColor,
+ [NSValue valueWithCGSize:CGSizeMake(0, -1)], UITextAttributeTextShadowOffset,
+ nil]];
+
+ [[self appearance] setMessageTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
+ [UIFont systemFontOfSize:15], UITextAttributeFont,
+ [UIColor whiteColor], UITextAttributeTextColor,
+ [UIColor blackColor], UITextAttributeTextShadowColor,
+ [NSValue valueWithCGSize:CGSizeMake(0, -1)], UITextAttributeTextShadowOffset,
+ nil]];
+
+ [[self appearance] setButtonTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
+ [UIFont boldSystemFontOfSize:17], UITextAttributeFont,
+ [UIColor whiteColor], UITextAttributeTextColor,
+ [UIColor blackColor], UITextAttributeTextShadowColor,
+ [NSValue valueWithCGSize:CGSizeMake(0, -1)], UITextAttributeTextShadowOffset,
+ nil]];
+
+ [[self appearance] setButtonBackgroundImage:[self normalButtonBackgroundImage] forState:UIControlStateNormal];
+
+ [[self appearance] setCancelButtonBackgroundImage:[self cancelButtonBackgroundImage] forState:UIControlStateNormal];
+}
+
+#pragma mark - Instance life cycle methods
+
+- (id)initWithTitle:(NSString *)title message:(NSString *)message
+{
+ CGRect frame = CGRectMake(0, 0, AHAlertViewDefaultWidth, AHAlertViewMinimumHeight);
+
+ if((self = [super initWithFrame:frame]))
+ {
+ [super setBackgroundColor:[UIColor clearColor]];
+
+ _title = title;
+ _message = message;
+
+ _presentationStyle = AHAlertViewPresentationStyleDefault;
+ _dismissalStyle = AHAlertViewDismissalStyleDefault;
+
+ _otherButtons = [NSMutableArray array];
+
+ [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(deviceOrientationChanged:)
+ name:UIDeviceOrientationDidChangeNotification
+ object:nil];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ for(id button in _otherButtons)
+ objc_setAssociatedObject(button, kAHAlertViewButtonBlockKey, nil, OBJC_ASSOCIATION_RETAIN);
+
+ if(_cancelButton)
+ objc_setAssociatedObject(_cancelButton, kAHAlertViewButtonBlockKey, nil, OBJC_ASSOCIATION_RETAIN);
+
+ if(_destructiveButton)
+ objc_setAssociatedObject(_destructiveButton, kAHAlertViewButtonBlockKey, nil, OBJC_ASSOCIATION_RETAIN);
+
+ [[NSNotificationCenter defaultCenter] removeObserver:self
+ name:UIDeviceOrientationDidChangeNotification
+ object:nil];
+
+ [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
+}
+
+- (UIButton *)buttonWithTitle:(NSString *)aTitle associatedBlock:(AHAlertViewButtonBlock)block {
+ UIButton *button = [[UIButton alloc] initWithFrame:CGRectZero];
+
+ [button setTitle:aTitle forState:UIControlStateNormal];
+ [button addTarget:self action:@selector(buttonWasPressed:) forControlEvents:UIControlEventTouchUpInside];
+ objc_setAssociatedObject(button, kAHAlertViewButtonBlockKey, block, OBJC_ASSOCIATION_RETAIN);
+ return button;
+}
+
+- (void)addButtonWithTitle:(NSString *)aTitle block:(AHAlertViewButtonBlock)block {
+ if(!self.otherButtons)
+ self.otherButtons = [NSMutableArray array];
+
+ UIButton *otherButton = [self buttonWithTitle:aTitle associatedBlock:block];
+ [self.otherButtons addObject:otherButton];
+ [self addSubview:otherButton];
+}
+
+- (void)setDestructiveButtonTitle:(NSString *)aTitle block:(AHAlertViewButtonBlock)block {
+ self.destructiveButton = [self buttonWithTitle:aTitle associatedBlock:block];
+ [self addSubview:self.destructiveButton];
+}
+
+- (void)setCancelButtonTitle:(NSString *)aTitle block:(AHAlertViewButtonBlock)block {
+ self.cancelButton = [self buttonWithTitle:aTitle associatedBlock:block];
+ [self addSubview:self.cancelButton];
+}
+
+#pragma mark - Text field accessor
+
+- (UITextField *)textFieldAtIndex:(NSInteger)textFieldIndex
+{
+ return nil;
+}
+
+#pragma mark - Appearance selectors
+
+- (void)setButtonBackgroundImage:(UIImage *)backgroundImage forState:(UIControlState)state
+{
+ if(!self.buttonBackgroundImagesForControlStates)
+ self.buttonBackgroundImagesForControlStates = [NSMutableDictionary dictionary];
+
+ [self.buttonBackgroundImagesForControlStates setObject:backgroundImage
+ forKey:[NSNumber numberWithInteger:state]];
+}
+
+- (UIImage *)buttonBackgroundImageForState:(UIControlState)state
+{
+ return [self.buttonBackgroundImagesForControlStates objectForKey:[NSNumber numberWithInteger:state]];
+}
+
+- (void)setCancelButtonBackgroundImage:(UIImage *)backgroundImage forState:(UIControlState)state
+{
+ if(!self.cancelButtonBackgroundImagesForControlStates)
+ self.cancelButtonBackgroundImagesForControlStates = [NSMutableDictionary dictionary];
+
+ [self.cancelButtonBackgroundImagesForControlStates setObject:backgroundImage
+ forKey:[NSNumber numberWithInteger:state]];
+}
+
+- (UIImage *)cancelButtonBackgroundImageForState:(UIControlState)state
+{
+ return [self.cancelButtonBackgroundImagesForControlStates objectForKey:[NSNumber numberWithInteger:state]];
+}
+
+- (void)setDestructiveButtonBackgroundImage:(UIImage *)backgroundImage forState:(UIControlState)state
+{
+ if(!self.destructiveButtonBackgroundImagesForControlStates)
+ self.destructiveButtonBackgroundImagesForControlStates = [NSMutableDictionary dictionary];
+
+ [self.destructiveButtonBackgroundImagesForControlStates setObject:backgroundImage
+ forKey:[NSNumber numberWithInteger:state]];
+}
+
+- (UIImage *)destructiveButtonBackgroundImageForState:(UIControlState)state
+{
+ return [self.destructiveButtonBackgroundImagesForControlStates objectForKey:[NSNumber numberWithInteger:state]];
+}
+
+#pragma mark - Presentation and dismissal methods
+
+- (void)show {
+ [self showWithStyle:self.presentationStyle];
+}
+
+- (void)showWithStyle:(AHAlertViewPresentationStyle)style
+{
+ self.presentationStyle = style;
+
+ [self setNeedsLayout];
+
+ UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
+
+ UIImageView *dimView = [[UIImageView alloc] initWithFrame:keyWindow.bounds];
+ dimView.image = [self backgroundGradientImageWithSize:keyWindow.bounds.size];
+ dimView.userInteractionEnabled = YES;
+
+ [keyWindow addSubview:dimView];
+ [dimView addSubview:self];
+
+ [self performPresentationAnimation];
+}
+
+
+- (void)dismiss {
+ [self dismissWithStyle:self.dismissalStyle];
+}
+
+- (void)dismissWithStyle:(AHAlertViewDismissalStyle)style {
+ self.dismissalStyle = style;
+ [self performDismissalAnimation];
+}
+
+- (void)buttonWasPressed:(UIButton *)sender {
+ AHAlertViewButtonBlock block = objc_getAssociatedObject(sender, kAHAlertViewButtonBlockKey);
+ if(block) block();
+
+ [self dismissWithStyle:self.dismissalStyle];
+}
+
+#pragma mark - Presentation and dismissal animation utilities
+
+- (void)performPresentationAnimation
+{
+ if(self.presentationStyle == AHAlertViewPresentationStylePop)
+ {
+ CAKeyframeAnimation *bounceAnimation = [CAKeyframeAnimation animation];
+ bounceAnimation.duration = 0.3;
+ bounceAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
+ bounceAnimation.values = [NSArray arrayWithObjects:
+ [NSNumber numberWithFloat:0.01],
+ [NSNumber numberWithFloat:1.1],
+ [NSNumber numberWithFloat:0.9],
+ [NSNumber numberWithFloat:1.0],
+ nil];
+
+ [self.layer addAnimation:bounceAnimation forKey:@"transform.scale"];
+
+ CABasicAnimation *fadeInAnimation = [CABasicAnimation animation];
+ fadeInAnimation.duration = 0.3;
+ fadeInAnimation.fromValue = [NSNumber numberWithFloat:0];
+ fadeInAnimation.toValue = [NSNumber numberWithFloat:1];
+ [self.superview.layer addAnimation:fadeInAnimation forKey:@"opacity"];
+ }
+ else if(self.presentationStyle == AHAlertViewPresentationStyleFade)
+ {
+ self.superview.alpha = 0;
+
+ [UIView animateWithDuration:0.3
+ delay:0.0
+ options:UIViewAnimationOptionCurveEaseInOut
+ animations:^
+ {
+ self.superview.alpha = 1;
+ }
+ completion:nil];
+ }
+ else
+ {
+ // Views appear immediately when added
+ }
+}
+
+- (void)performDismissalAnimation {
+ AHAnimationCompletionBlock completionBlock = ^(BOOL finished)
+ {
+ [self.superview removeFromSuperview];
+ [self removeFromSuperview];
+ };
+
+ if(self.dismissalStyle == AHAlertViewDismissalStyleTumble)
+ {
+ [UIView animateWithDuration:0.7
+ delay:0.0
+ options:UIViewAnimationOptionCurveEaseIn
+ animations:^
+ {
+ CGPoint offset = CGPointMake(0, self.superview.bounds.size.height * 1.5);
+ offset = CGPointApplyAffineTransform(offset, self.transform);
+ self.transform = CGAffineTransformConcat(self.transform, CGAffineTransformMakeRotation(-M_PI_4));
+ self.center = CGPointMake(self.center.x + offset.x, self.center.y + offset.y);
+ self.superview.alpha = 0;
+ }
+ completion:completionBlock];
+ }
+ else if(self.dismissalStyle == AHAlertViewDismissalStyleFade)
+ {
+ [UIView animateWithDuration:0.25
+ delay:0.0
+ options:UIViewAnimationOptionCurveEaseInOut
+ animations:^
+ {
+ self.superview.alpha = 0;
+ }
+ completion:completionBlock];
+ }
+ else if(self.dismissalStyle == AHAlertViewDismissalStyleZoomDown)
+ {
+ [UIView animateWithDuration:0.3
+ delay:0.0
+ options:UIViewAnimationOptionCurveEaseIn
+ animations:^
+ {
+ self.transform = CGAffineTransformConcat(self.transform, CGAffineTransformMakeScale(0.01, 0.01));
+ self.superview.alpha = 0;
+ }
+ completion:completionBlock];
+ }
+ else if(self.dismissalStyle == AHAlertViewDismissalStyleZoomOut)
+ {
+ [UIView animateWithDuration:0.2
+ delay:0.0
+ options:UIViewAnimationOptionCurveLinear
+ animations:^
+ {
+ self.transform = CGAffineTransformConcat(self.transform, CGAffineTransformMakeScale(10, 10));
+ self.superview.alpha = 0;
+ }
+ completion:completionBlock];
+ }
+ else
+ {
+ completionBlock(YES);
+ }
+}
+
+#pragma mark - Layout calculation methods
+
+- (void)layoutSubviews {
+ [super layoutSubviews];
+
+ CGAffineTransform baseTransform = [self transformForCurrentOrientation];
+
+ CGFloat delta = CGAffineTransformGetAbsoluteRotationAngleDifference(self.transform, baseTransform);
+ BOOL isDoubleRotation = (delta > M_PI);
+
+ if(hasLayedOut)
+ {
+ CGFloat duration = [[UIApplication sharedApplication] statusBarOrientationAnimationDuration];
+ if(isDoubleRotation)
+ duration *= 2;
+
+ [UIView animateWithDuration:duration animations:^{
+ self.transform = baseTransform;
+ }];
+ }
+ else
+ self.transform = baseTransform;
+
+ hasLayedOut = YES;
+
+ CGRect boundingRect = self.bounds;
+ boundingRect.size.height = FLT_MAX;
+ boundingRect = UIEdgeInsetsInsetRect(boundingRect, self.contentInsets);
+
+ if(!self.titleLabel)
+ self.titleLabel = [self addLabelAsSubview];
+
+ [self applyTextAttributes:self.titleTextAttributes toLabel:self.titleLabel];
+ self.titleLabel.text = self.title;
+ CGSize titleSize = [self.titleLabel.text sizeWithFont:self.titleLabel.font constrainedToSize:boundingRect.size lineBreakMode:UILineBreakModeWordWrap];
+ self.titleLabel.frame = CGRectMake(boundingRect.origin.x, boundingRect.origin.y, boundingRect.size.width, titleSize.height);
+
+ const CGFloat titleLabelBottomMargin = 8;
+ CGFloat messageLabelOriginY = boundingRect.origin.y + titleSize.height + titleLabelBottomMargin;
+
+ if(!self.messageLabel)
+ self.messageLabel = [self addLabelAsSubview];
+
+ [self applyTextAttributes:self.messageTextAttributes toLabel:self.messageLabel];
+ self.messageLabel.text = self.message;
+ CGSize messageSize = [self.messageLabel.text sizeWithFont:self.messageLabel.font constrainedToSize:boundingRect.size lineBreakMode:UILineBreakModeWordWrap];
+ self.messageLabel.frame = CGRectMake(boundingRect.origin.x, messageLabelOriginY, boundingRect.size.width, messageSize.height);
+
+ const CGFloat messageLabelBottomMargin = 20;
+ CGFloat buttonOriginY = messageLabelOriginY + messageSize.height + messageLabelBottomMargin;
+
+ [self applyBackgroundImages:self.cancelButtonBackgroundImagesForControlStates toButton:self.cancelButton];
+ [self applyTextAttributes:self.buttonTitleTextAttributes toButton:self.cancelButton];
+ CGRect cancelButtonRect = CGRectMake(boundingRect.origin.x, buttonOriginY, boundingRect.size.width * 0.5 - 4, AHAlertViewDefaultButtonHeight);
+ self.cancelButton.frame = cancelButtonRect;
+
+ if([self.otherButtons count] > 0)
+ {
+ UIButton *otherButton = [self.otherButtons objectAtIndex:0];
+ [self applyBackgroundImages:self.buttonBackgroundImagesForControlStates toButton:otherButton];
+ [self applyTextAttributes:self.buttonTitleTextAttributes toButton:otherButton];
+ CGRect otherButtonRect = CGRectMake(cancelButtonRect.origin.x + cancelButtonRect.size.width + 8, buttonOriginY, boundingRect.size.width * 0.5 - 4, AHAlertViewDefaultButtonHeight);
+ otherButton.frame = otherButtonRect;
+ }
+
+ CGFloat calculatedHeight = buttonOriginY + cancelButtonRect.size.height + self.contentInsets.bottom;
+
+ CGRect newBounds = CGRectMake(0, 0, self.bounds.size.width, calculatedHeight);
+ CGPoint newCenter = CGPointMake(self.superview.bounds.size.width * 0.5, self.superview.bounds.size.height * 0.5);
+ self.bounds = newBounds;
+ self.center = newCenter;
+
+ if(!self.backgroundImageView)
+ {
+ self.backgroundImageView = [[UIImageView alloc] initWithFrame:self.bounds];
+ self.backgroundImageView.autoresizingMask = ~UIViewAutoresizingNone;
+ self.backgroundImageView.contentMode = UIViewContentModeScaleToFill;
+ [self insertSubview:self.backgroundImageView atIndex:0];
+ }
+
+ self.backgroundImageView.image = [AHAlertView alertBackgroundImage];
+}
+
+- (UILabel *)addLabelAsSubview
+{
+ UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
+ label.backgroundColor = [UIColor clearColor];
+ label.textAlignment = UITextAlignmentCenter;
+ label.numberOfLines = 0;
+ [self addSubview:label];
+
+ return label;
+}
+
+- (void)applyTextAttributes:(NSDictionary *)attributes toLabel:(UILabel *)label {
+ label.font = [attributes objectForKey:UITextAttributeFont];
+ label.textColor = [attributes objectForKey:UITextAttributeTextColor];
+ label.shadowColor = [attributes objectForKey:UITextAttributeTextShadowColor];
+ label.shadowOffset = [[attributes objectForKey:UITextAttributeTextShadowOffset] CGSizeValue];
+}
+
+- (void)applyTextAttributes:(NSDictionary *)attributes toButton:(UIButton *)button {
+ button.titleLabel.font = [attributes objectForKey:UITextAttributeFont];
+ [button setTitleColor:[attributes objectForKey:UITextAttributeTextColor] forState:UIControlStateNormal];
+ [button setTitleShadowColor:[attributes objectForKey:UITextAttributeTextShadowColor] forState:UIControlStateNormal];
+ button.titleLabel.shadowOffset = [[attributes objectForKey:UITextAttributeTextShadowOffset] CGSizeValue];
+}
+
+- (void)applyBackgroundImages:(NSDictionary *)imagesForStates toButton:(UIButton *)button {
+ [imagesForStates enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
+ [button setBackgroundImage:obj forState:[key integerValue]];
+ }];
+}
+
+#pragma mark - Orientation helpers
+
+- (CGAffineTransform)transformForCurrentOrientation
+{
+ CGAffineTransform transform = CGAffineTransformIdentity;
+ UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
+ if(orientation == UIInterfaceOrientationPortraitUpsideDown)
+ transform = CGAffineTransformMakeRotation(M_PI);
+ else if(orientation == UIInterfaceOrientationLandscapeLeft)
+ transform = CGAffineTransformMakeRotation(-M_PI_2);
+ else if(orientation == UIInterfaceOrientationLandscapeRight)
+ transform = CGAffineTransformMakeRotation(M_PI_2);
+
+ return transform;
+}
+
+- (void)deviceOrientationChanged:(NSNotification *)notification
+{
+ [self setNeedsLayout];
+}
+
+#pragma mark - Drawing utilities for implementing system control styles
+
+- (UIImage *)backgroundGradientImageWithSize:(CGSize)size
+{
+ CGPoint center = CGPointMake(size.width * 0.5, size.height * 0.5);
+ CGFloat innerRadius = 0;
+ CGFloat outerRadius = sqrtf(size.width * size.width + size.height * size.height) * 0.5;
+
+ BOOL opaque = NO;
+ UIGraphicsBeginImageContextWithOptions(size, opaque, [[UIScreen mainScreen] scale]);
+ CGContextRef context = UIGraphicsGetCurrentContext();
+
+ const size_t locationCount = 2;
+ CGFloat locations[locationCount] = { 0.0, 1.0 };
+ CGFloat components[locationCount * 4] = {
+ 0.0, 0.0, 0.0, 0.1, // More transparent black
+ 0.0, 0.0, 0.0, 0.7 // More opaque black
+ };
+
+ CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
+ CGGradientRef gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, locationCount);
+
+ CGContextDrawRadialGradient(context, gradient, center, innerRadius, center, outerRadius, 0);
+
+ UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+
+ CGColorSpaceRelease(colorspace);
+ CGGradientRelease(gradient);
+
+ return image;
+}
+
+#pragma mark - Class drawing utilities for implementing system control styles
+
++ (UIImage *)alertBackgroundImage
+{
+ CGRect rect = CGRectMake(0, 0, AHAlertViewDefaultWidth, AHAlertViewMinimumHeight);
+ const CGFloat lineWidth = 2;
+ const CGFloat cornerRadius = 8;
+
+ CGFloat shineWidth = rect.size.width * 1.33;
+ CGFloat shineHeight = rect.size.width * 0.2;
+ CGFloat shineOriginX = rect.size.width * 0.5 - shineWidth * 0.5;
+ CGFloat shineOriginY = -shineHeight * 0.45;
+ CGRect shineRect = CGRectMake(shineOriginX, shineOriginY, shineWidth, shineHeight);
+
+ UIColor *fillColor = [UIColor colorWithRed:1/255.0 green:21/255.0 blue:54/255.0 alpha:0.9];
+ UIColor *strokeColor = [UIColor colorWithWhite:1.0 alpha:0.7];
+
+ BOOL opaque = NO;
+ UIGraphicsBeginImageContextWithOptions(rect.size, opaque, [[UIScreen mainScreen] scale]);
+
+ CGRect fillRect = CGRectInset(rect, lineWidth, lineWidth);
+ UIBezierPath *fillPath = [UIBezierPath bezierPathWithRoundedRect:fillRect cornerRadius:cornerRadius];
+ [fillColor setFill];
+ [fillPath fill];
+
+ CGRect strokeRect = CGRectInset(rect, lineWidth * 0.5, lineWidth * 0.5);
+ UIBezierPath *strokePath = [UIBezierPath bezierPathWithRoundedRect:strokeRect cornerRadius:cornerRadius];
+ strokePath.lineWidth = lineWidth;
+ [strokeColor setStroke];
+ [strokePath stroke];
+
+ UIBezierPath *shinePath = [UIBezierPath bezierPathWithOvalInRect:shineRect];
+ [fillPath addClip];
+ [shinePath addClip];
+
+ const size_t locationCount = 2;
+ CGFloat locations[locationCount] = { 0.0, 1.0 };
+ CGFloat components[locationCount * 4] = {
+ 1, 1, 1, 0.75, // Translucent white
+ 1, 1, 1, 0.05 // More translucent white
+ };
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+ CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, locationCount);
+
+ CGContextRef context = UIGraphicsGetCurrentContext();
+ CGPoint startPoint = CGPointMake(CGRectGetMidX(shineRect), CGRectGetMinY(shineRect));
+ CGPoint endPoint = CGPointMake(CGRectGetMidX(shineRect), CGRectGetMaxY(shineRect));
+ CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
+
+ CGGradientRelease(gradient);
+ CGColorSpaceRelease(colorSpace);
+
+ UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+
+ CGFloat capHeight = CGRectGetMaxY(shineRect);
+ CGFloat capWidth = rect.size.width * 0.5;
+ return [image resizableImageWithCapInsets:UIEdgeInsetsMake(capHeight, capWidth, rect.size.height - capHeight, capWidth)];
+}
+
++ (UIImage *)normalButtonBackgroundImage
+{
+ const size_t locationCount = 4;
+ CGFloat opacity = 1.0;
+ CGFloat locations[locationCount] = { 0.0, 0.5, 0.5 + 0.0001, 1.0 };
+ CGFloat components[locationCount * 4] = {
+ 179/255.0, 185/255.0, 199/255.0, opacity,
+ 121/255.0, 132/255.0, 156/255.0, opacity,
+ 87/255.0, 100/255.0, 130/255.0, opacity,
+ 108/255.0, 120/255.0, 146/255.0, opacity,
+ };
+ return [self glassButtonBackgroundImageWithGradientLocations:locations
+ components:components
+ locationCount:locationCount];
+}
+
++ (UIImage *)cancelButtonBackgroundImage
+{
+ const size_t locationCount = 4;
+ CGFloat opacity = 1.0;
+ CGFloat locations[locationCount] = { 0.0, 0.5, 0.5 + 0.0001, 1.0 };
+ CGFloat components[locationCount * 4] = {
+ 164/255.0, 169/255.0, 184/255.0, opacity,
+ 77/255.0, 87/255.0, 115/255.0, opacity,
+ 51/255.0, 63/255.0, 95/255.0, opacity,
+ 78/255.0, 88/255.0, 116/255.0, opacity,
+ };
+ return [self glassButtonBackgroundImageWithGradientLocations:locations
+ components:components
+ locationCount:locationCount];
+}
+
++ (UIImage *)glassButtonBackgroundImageWithGradientLocations:(CGFloat *)locations
+ components:(CGFloat *)components
+ locationCount:(NSInteger)locationCount
+{
+ const CGFloat lineWidth = 1;
+ const CGFloat cornerRadius = 4;
+ UIColor *strokeColor = [UIColor colorWithRed:1/255.0 green:11/255.0 blue:39/255.0 alpha:1.0];
+
+ CGRect rect = CGRectMake(0, 0, cornerRadius * 2 + 1, AHAlertViewDefaultButtonHeight);
+
+ BOOL opaque = NO;
+ UIGraphicsBeginImageContextWithOptions(rect.size, opaque, [[UIScreen mainScreen] scale]);
+
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+ CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, locationCount);
+
+ CGRect strokeRect = CGRectInset(rect, lineWidth * 0.5, lineWidth * 0.5);
+ UIBezierPath *strokePath = [UIBezierPath bezierPathWithRoundedRect:strokeRect cornerRadius:cornerRadius];
+ strokePath.lineWidth = lineWidth;
+ [strokeColor setStroke];
+ [strokePath stroke];
+
+ CGRect fillRect = CGRectInset(rect, lineWidth, lineWidth);
+ UIBezierPath *fillPath = [UIBezierPath bezierPathWithRoundedRect:fillRect cornerRadius:cornerRadius];
+ [fillPath addClip];
+
+ CGContextRef context = UIGraphicsGetCurrentContext();
+ CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
+ CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
+ CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
+
+ CGGradientRelease(gradient);
+ CGColorSpaceRelease(colorSpace);
+
+ UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+
+ CGFloat capHeight = floorf(rect.size.height * 0.5);
+ return [image resizableImageWithCapInsets:UIEdgeInsetsMake(capHeight, cornerRadius, capHeight, cornerRadius)];
+}
+
+@end
View
2  AHAlertViewSample/AHAlertViewSample-Info.plist
@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
- <string>${PRODUCT_NAME}</string>
+ <string>Alert</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
View
33 AHAlertViewSample/AHAppDelegate.m
@@ -7,43 +7,18 @@
//
#import "AHAppDelegate.h"
+#import "AHAlertSampleViewController.h"
@implementation AHAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
+ AHAlertSampleViewController *vc = [[AHAlertSampleViewController alloc] init];
+
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- // Override point for customization after application launch.
- self.window.backgroundColor = [UIColor whiteColor];
+ self.window.rootViewController = vc;
[self.window makeKeyAndVisible];
return YES;
}
-- (void)applicationWillResignActive:(UIApplication *)application
-{
- // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
- // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
-}
-
-- (void)applicationDidEnterBackground:(UIApplication *)application
-{
- // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
- // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
-}
-
-- (void)applicationWillEnterForeground:(UIApplication *)application
-{
- // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
-}
-
-- (void)applicationDidBecomeActive:(UIApplication *)application
-{
- // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
-}
-
-- (void)applicationWillTerminate:(UIApplication *)application
-{
- // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
-}
-
@end
Please sign in to comment.
Something went wrong with that request. Please try again.