├── .gitignore ├── ExampleApp ├── Default-568h@2x.png ├── Default.png ├── Default@2x.png ├── KGAppDelegate.h ├── KGAppDelegate.m ├── KGModalExample-Info.plist ├── KGModalExample.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── KGModalExample.xccheckout └── main.m ├── KGModal.h ├── KGModal.m ├── KGModal.podspec ├── Screenshot.jpg ├── license.txt └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | xcuserdata 2 | .DS_Store 3 | html 4 | appledoc 5 | *.pyc 6 | user.*.espressostorage 7 | Sparkle/*.app 8 | *.zip 9 | PXListView 10 | -------------------------------------------------------------------------------- /ExampleApp/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgn/KGModal/cf976893fc4581b4ac654a9a7010aab6f3544015/ExampleApp/Default-568h@2x.png -------------------------------------------------------------------------------- /ExampleApp/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgn/KGModal/cf976893fc4581b4ac654a9a7010aab6f3544015/ExampleApp/Default.png -------------------------------------------------------------------------------- /ExampleApp/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgn/KGModal/cf976893fc4581b4ac654a9a7010aab6f3544015/ExampleApp/Default@2x.png -------------------------------------------------------------------------------- /ExampleApp/KGAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // KGAppDelegate.h 3 | // KGModal 4 | // 5 | // Created by David Keegan on 10/5/12. 6 | // Copyright (c) 2012 David Keegan. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface KGAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ExampleApp/KGAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // KGAppDelegate.m 3 | // KGModal 4 | // 5 | // Created by David Keegan on 10/5/12. 6 | // Copyright (c) 2012 David Keegan. All rights reserved. 7 | // 8 | 9 | #import "KGAppDelegate.h" 10 | #import "KGModal.h" 11 | 12 | @implementation KGAppDelegate 13 | 14 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ 15 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 16 | self.window.rootViewController = [[UIViewController alloc] init]; 17 | self.window.rootViewController.view.backgroundColor = [UIColor colorWithRed:0.441 green:0.466 blue:1.000 alpha:1.000]; 18 | 19 | CGRect showButtonRect = CGRectZero; 20 | showButtonRect.size = CGSizeMake(200, 62); 21 | showButtonRect.origin.x = round(CGRectGetMidX(self.window.rootViewController.view.bounds)-CGRectGetMidX(showButtonRect)); 22 | showButtonRect.origin.y = CGRectGetHeight(self.window.rootViewController.view.bounds)-CGRectGetHeight(showButtonRect)-10; 23 | UIButton *showButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 24 | showButton.frame = showButtonRect; 25 | showButton.autoresizingMask = 26 | UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin; 27 | [showButton setTitle:@"Show Modal" forState:UIControlStateNormal]; 28 | [showButton addTarget:self action:@selector(showAction:) forControlEvents:UIControlEventTouchUpInside]; 29 | [self.window.rootViewController.view addSubview:showButton]; 30 | 31 | [KGModal sharedInstance].closeButtonType = KGModalCloseButtonTypeRight; 32 | 33 | [self.window makeKeyAndVisible]; 34 | 35 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willShow:) name:KGModalWillShowNotification object:nil]; 36 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didShow:) name:KGModalDidShowNotification object:nil]; 37 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willHide:) name:KGModalWillHideNotification object:nil]; 38 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didHide:) name:KGModalDidHideNotification object:nil]; 39 | 40 | return YES; 41 | } 42 | 43 | - (void)showAction:(id)sender{ 44 | UIView *contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 280, 250)]; 45 | 46 | CGRect welcomeLabelRect = contentView.bounds; 47 | welcomeLabelRect.origin.y = 20; 48 | welcomeLabelRect.size.height = 20; 49 | UIFont *welcomeLabelFont = [UIFont boldSystemFontOfSize:17]; 50 | UILabel *welcomeLabel = [[UILabel alloc] initWithFrame:welcomeLabelRect]; 51 | welcomeLabel.text = @"Welcome to KGModal!"; 52 | welcomeLabel.font = welcomeLabelFont; 53 | welcomeLabel.textColor = [UIColor whiteColor]; 54 | welcomeLabel.textAlignment = NSTextAlignmentCenter; 55 | welcomeLabel.backgroundColor = [UIColor clearColor]; 56 | welcomeLabel.shadowColor = [UIColor blackColor]; 57 | welcomeLabel.shadowOffset = CGSizeMake(0, 1); 58 | [contentView addSubview:welcomeLabel]; 59 | 60 | CGRect infoLabelRect = CGRectInset(contentView.bounds, 5, 5); 61 | infoLabelRect.origin.y = CGRectGetMaxY(welcomeLabelRect)+5; 62 | infoLabelRect.size.height -= CGRectGetMinY(infoLabelRect) + 50; 63 | UILabel *infoLabel = [[UILabel alloc] initWithFrame:infoLabelRect]; 64 | infoLabel.text = @"KGModal is an easy drop in control that allows you to display any view " 65 | "in a modal popup. The modal will automatically scale to fit the content view " 66 | "and center it on screen with nice animations!"; 67 | infoLabel.numberOfLines = 6; 68 | infoLabel.textColor = [UIColor whiteColor]; 69 | infoLabel.textAlignment = NSTextAlignmentCenter; 70 | infoLabel.backgroundColor = [UIColor clearColor]; 71 | infoLabel.shadowColor = [UIColor blackColor]; 72 | infoLabel.shadowOffset = CGSizeMake(0, 1); 73 | [contentView addSubview:infoLabel]; 74 | 75 | CGFloat btnY = CGRectGetMaxY(infoLabelRect)+5; 76 | CGFloat btnH = CGRectGetMaxY(contentView.frame)-5 - btnY; 77 | UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 78 | btn.frame = CGRectMake(infoLabelRect.origin.x, btnY, infoLabelRect.size.width, btnH); 79 | [btn setTitle:@"Close Button Right" forState:UIControlStateNormal]; 80 | [btn addTarget:self action:@selector(changeCloseButtonType:) forControlEvents:UIControlEventTouchUpInside]; 81 | [contentView addSubview:btn]; 82 | 83 | // [[KGModal sharedInstance] setCloseButtonLocation:KGModalCloseButtonLocationRight]; 84 | [[KGModal sharedInstance] showWithContentView:contentView andAnimated:YES]; 85 | } 86 | 87 | - (void)willShow:(NSNotification *)notification{ 88 | NSLog(@"will show"); 89 | } 90 | 91 | - (void)didShow:(NSNotification *)notification{ 92 | NSLog(@"did show"); 93 | } 94 | 95 | - (void)willHide:(NSNotification *)notification{ 96 | NSLog(@"will hide"); 97 | } 98 | 99 | - (void)didHide:(NSNotification *)notification{ 100 | NSLog(@"did hide"); 101 | } 102 | 103 | - (void)changeCloseButtonType:(id)sender{ 104 | UIButton *button = (UIButton *)sender; 105 | KGModal *modal = [KGModal sharedInstance]; 106 | KGModalCloseButtonType type = modal.closeButtonType; 107 | 108 | if(type == KGModalCloseButtonTypeLeft){ 109 | modal.closeButtonType = KGModalCloseButtonTypeRight; 110 | [button setTitle:@"Close Button Right" forState:UIControlStateNormal]; 111 | }else if(type == KGModalCloseButtonTypeRight){ 112 | modal.closeButtonType = KGModalCloseButtonTypeNone; 113 | [button setTitle:@"Close Button None" forState:UIControlStateNormal]; 114 | }else{ 115 | modal.closeButtonType = KGModalCloseButtonTypeLeft; 116 | [button setTitle:@"Close Button Left" forState:UIControlStateNormal]; 117 | } 118 | } 119 | 120 | @end 121 | -------------------------------------------------------------------------------- /ExampleApp/KGModalExample-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | com.davidkeegan.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ExampleApp/KGModalExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 731C4416161F94B300FFF7A2 /* KGModal.m in Sources */ = {isa = PBXBuildFile; fileRef = 731C4415161F94B300FFF7A2 /* KGModal.m */; }; 11 | 731C441B161F94C000FFF7A2 /* KGAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 731C4418161F94C000FFF7A2 /* KGAppDelegate.m */; }; 12 | 731C441C161F94C000FFF7A2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 731C441A161F94C000FFF7A2 /* main.m */; }; 13 | 731C4420161F958600FFF7A2 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 731C441D161F958600FFF7A2 /* Default-568h@2x.png */; }; 14 | 731C4421161F958600FFF7A2 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 731C441E161F958600FFF7A2 /* Default.png */; }; 15 | 731C4422161F958600FFF7A2 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 731C441F161F958600FFF7A2 /* Default@2x.png */; }; 16 | 73C8D4DF161F70CA007F378A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73C8D4DE161F70CA007F378A /* UIKit.framework */; }; 17 | 73C8D4E1161F70CA007F378A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73C8D4E0161F70CA007F378A /* Foundation.framework */; }; 18 | 73C8D4E3161F70CA007F378A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73C8D4E2161F70CA007F378A /* CoreGraphics.framework */; }; 19 | 73C8D4FF161F7EC1007F378A /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73C8D4FE161F7EC1007F378A /* QuartzCore.framework */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | 731C4414161F94B300FFF7A2 /* KGModal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KGModal.h; path = ../KGModal.h; sourceTree = ""; }; 24 | 731C4415161F94B300FFF7A2 /* KGModal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KGModal.m; path = ../KGModal.m; sourceTree = ""; }; 25 | 731C4417161F94C000FFF7A2 /* KGAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KGAppDelegate.h; sourceTree = ""; }; 26 | 731C4418161F94C000FFF7A2 /* KGAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KGAppDelegate.m; sourceTree = ""; }; 27 | 731C441A161F94C000FFF7A2 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 28 | 731C441D161F958600FFF7A2 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 29 | 731C441E161F958600FFF7A2 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 30 | 731C441F161F958600FFF7A2 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 31 | 73C8D4DA161F70CA007F378A /* KGModalExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KGModalExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 32 | 73C8D4DE161F70CA007F378A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 33 | 73C8D4E0161F70CA007F378A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 34 | 73C8D4E2161F70CA007F378A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 35 | 73C8D4FE161F7EC1007F378A /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 36 | /* End PBXFileReference section */ 37 | 38 | /* Begin PBXFrameworksBuildPhase section */ 39 | 73C8D4D7161F70CA007F378A /* Frameworks */ = { 40 | isa = PBXFrameworksBuildPhase; 41 | buildActionMask = 2147483647; 42 | files = ( 43 | 73C8D4FF161F7EC1007F378A /* QuartzCore.framework in Frameworks */, 44 | 73C8D4DF161F70CA007F378A /* UIKit.framework in Frameworks */, 45 | 73C8D4E1161F70CA007F378A /* Foundation.framework in Frameworks */, 46 | 73C8D4E3161F70CA007F378A /* CoreGraphics.framework in Frameworks */, 47 | ); 48 | runOnlyForDeploymentPostprocessing = 0; 49 | }; 50 | /* End PBXFrameworksBuildPhase section */ 51 | 52 | /* Begin PBXGroup section */ 53 | 739DCD921639BBBE00FCD11E /* KGModalExample */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | 731C4417161F94C000FFF7A2 /* KGAppDelegate.h */, 57 | 731C4418161F94C000FFF7A2 /* KGAppDelegate.m */, 58 | 731C441A161F94C000FFF7A2 /* main.m */, 59 | 73B7BEEE161F95D000024C46 /* Resources */, 60 | ); 61 | name = KGModalExample; 62 | sourceTree = ""; 63 | }; 64 | 73B7BEEE161F95D000024C46 /* Resources */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 731C441D161F958600FFF7A2 /* Default-568h@2x.png */, 68 | 731C441E161F958600FFF7A2 /* Default.png */, 69 | 731C441F161F958600FFF7A2 /* Default@2x.png */, 70 | ); 71 | name = Resources; 72 | sourceTree = ""; 73 | }; 74 | 73C8D4CF161F70CA007F378A = { 75 | isa = PBXGroup; 76 | children = ( 77 | 731C4414161F94B300FFF7A2 /* KGModal.h */, 78 | 731C4415161F94B300FFF7A2 /* KGModal.m */, 79 | 739DCD921639BBBE00FCD11E /* KGModalExample */, 80 | 73C8D4DD161F70CA007F378A /* Frameworks */, 81 | 73C8D4DB161F70CA007F378A /* Products */, 82 | ); 83 | sourceTree = ""; 84 | }; 85 | 73C8D4DB161F70CA007F378A /* Products */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | 73C8D4DA161F70CA007F378A /* KGModalExample.app */, 89 | ); 90 | name = Products; 91 | sourceTree = ""; 92 | }; 93 | 73C8D4DD161F70CA007F378A /* Frameworks */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 73C8D4DE161F70CA007F378A /* UIKit.framework */, 97 | 73C8D4E0161F70CA007F378A /* Foundation.framework */, 98 | 73C8D4E2161F70CA007F378A /* CoreGraphics.framework */, 99 | 73C8D4FE161F7EC1007F378A /* QuartzCore.framework */, 100 | ); 101 | name = Frameworks; 102 | sourceTree = ""; 103 | }; 104 | /* End PBXGroup section */ 105 | 106 | /* Begin PBXNativeTarget section */ 107 | 73C8D4D9161F70CA007F378A /* KGModalExample */ = { 108 | isa = PBXNativeTarget; 109 | buildConfigurationList = 73C8D4F8161F70CA007F378A /* Build configuration list for PBXNativeTarget "KGModalExample" */; 110 | buildPhases = ( 111 | 73C8D4D6161F70CA007F378A /* Sources */, 112 | 73C8D4D7161F70CA007F378A /* Frameworks */, 113 | 73C8D4D8161F70CA007F378A /* Resources */, 114 | ); 115 | buildRules = ( 116 | ); 117 | dependencies = ( 118 | ); 119 | name = KGModalExample; 120 | productName = KGModal; 121 | productReference = 73C8D4DA161F70CA007F378A /* KGModalExample.app */; 122 | productType = "com.apple.product-type.application"; 123 | }; 124 | /* End PBXNativeTarget section */ 125 | 126 | /* Begin PBXProject section */ 127 | 73C8D4D1161F70CA007F378A /* Project object */ = { 128 | isa = PBXProject; 129 | attributes = { 130 | CLASSPREFIX = KG; 131 | LastUpgradeCheck = 0500; 132 | ORGANIZATIONNAME = "David Keegan"; 133 | }; 134 | buildConfigurationList = 73C8D4D4161F70CA007F378A /* Build configuration list for PBXProject "KGModalExample" */; 135 | compatibilityVersion = "Xcode 3.2"; 136 | developmentRegion = English; 137 | hasScannedForEncodings = 0; 138 | knownRegions = ( 139 | en, 140 | ); 141 | mainGroup = 73C8D4CF161F70CA007F378A; 142 | productRefGroup = 73C8D4DB161F70CA007F378A /* Products */; 143 | projectDirPath = ""; 144 | projectRoot = ""; 145 | targets = ( 146 | 73C8D4D9161F70CA007F378A /* KGModalExample */, 147 | ); 148 | }; 149 | /* End PBXProject section */ 150 | 151 | /* Begin PBXResourcesBuildPhase section */ 152 | 73C8D4D8161F70CA007F378A /* Resources */ = { 153 | isa = PBXResourcesBuildPhase; 154 | buildActionMask = 2147483647; 155 | files = ( 156 | 731C4420161F958600FFF7A2 /* Default-568h@2x.png in Resources */, 157 | 731C4421161F958600FFF7A2 /* Default.png in Resources */, 158 | 731C4422161F958600FFF7A2 /* Default@2x.png in Resources */, 159 | ); 160 | runOnlyForDeploymentPostprocessing = 0; 161 | }; 162 | /* End PBXResourcesBuildPhase section */ 163 | 164 | /* Begin PBXSourcesBuildPhase section */ 165 | 73C8D4D6161F70CA007F378A /* Sources */ = { 166 | isa = PBXSourcesBuildPhase; 167 | buildActionMask = 2147483647; 168 | files = ( 169 | 731C4416161F94B300FFF7A2 /* KGModal.m in Sources */, 170 | 731C441B161F94C000FFF7A2 /* KGAppDelegate.m in Sources */, 171 | 731C441C161F94C000FFF7A2 /* main.m in Sources */, 172 | ); 173 | runOnlyForDeploymentPostprocessing = 0; 174 | }; 175 | /* End PBXSourcesBuildPhase section */ 176 | 177 | /* Begin XCBuildConfiguration section */ 178 | 73C8D4F6161F70CA007F378A /* Debug */ = { 179 | isa = XCBuildConfiguration; 180 | buildSettings = { 181 | ALWAYS_SEARCH_USER_PATHS = NO; 182 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 183 | CLANG_CXX_LIBRARY = "libc++"; 184 | CLANG_ENABLE_OBJC_ARC = YES; 185 | CLANG_WARN_EMPTY_BODY = YES; 186 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 187 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 188 | COPY_PHASE_STRIP = NO; 189 | GCC_C_LANGUAGE_STANDARD = gnu99; 190 | GCC_DYNAMIC_NO_PIC = NO; 191 | GCC_OPTIMIZATION_LEVEL = 0; 192 | GCC_PREPROCESSOR_DEFINITIONS = ( 193 | "DEBUG=1", 194 | "$(inherited)", 195 | ); 196 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 197 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 198 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 199 | GCC_WARN_UNUSED_VARIABLE = YES; 200 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 201 | ONLY_ACTIVE_ARCH = YES; 202 | SDKROOT = iphoneos; 203 | TARGETED_DEVICE_FAMILY = "1,2"; 204 | }; 205 | name = Debug; 206 | }; 207 | 73C8D4F7161F70CA007F378A /* Release */ = { 208 | isa = XCBuildConfiguration; 209 | buildSettings = { 210 | ALWAYS_SEARCH_USER_PATHS = NO; 211 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 212 | CLANG_CXX_LIBRARY = "libc++"; 213 | CLANG_ENABLE_OBJC_ARC = YES; 214 | CLANG_WARN_EMPTY_BODY = YES; 215 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 216 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 217 | COPY_PHASE_STRIP = YES; 218 | GCC_C_LANGUAGE_STANDARD = gnu99; 219 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 220 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 221 | GCC_WARN_UNUSED_VARIABLE = YES; 222 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 223 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 224 | SDKROOT = iphoneos; 225 | TARGETED_DEVICE_FAMILY = "1,2"; 226 | VALIDATE_PRODUCT = YES; 227 | }; 228 | name = Release; 229 | }; 230 | 73C8D4F9161F70CA007F378A /* Debug */ = { 231 | isa = XCBuildConfiguration; 232 | buildSettings = { 233 | INFOPLIST_FILE = "KGModalExample-Info.plist"; 234 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 235 | PRODUCT_NAME = KGModalExample; 236 | WRAPPER_EXTENSION = app; 237 | }; 238 | name = Debug; 239 | }; 240 | 73C8D4FA161F70CA007F378A /* Release */ = { 241 | isa = XCBuildConfiguration; 242 | buildSettings = { 243 | INFOPLIST_FILE = "KGModalExample-Info.plist"; 244 | IPHONEOS_DEPLOYMENT_TARGET = 5.0; 245 | PRODUCT_NAME = KGModalExample; 246 | WRAPPER_EXTENSION = app; 247 | }; 248 | name = Release; 249 | }; 250 | /* End XCBuildConfiguration section */ 251 | 252 | /* Begin XCConfigurationList section */ 253 | 73C8D4D4161F70CA007F378A /* Build configuration list for PBXProject "KGModalExample" */ = { 254 | isa = XCConfigurationList; 255 | buildConfigurations = ( 256 | 73C8D4F6161F70CA007F378A /* Debug */, 257 | 73C8D4F7161F70CA007F378A /* Release */, 258 | ); 259 | defaultConfigurationIsVisible = 0; 260 | defaultConfigurationName = Release; 261 | }; 262 | 73C8D4F8161F70CA007F378A /* Build configuration list for PBXNativeTarget "KGModalExample" */ = { 263 | isa = XCConfigurationList; 264 | buildConfigurations = ( 265 | 73C8D4F9161F70CA007F378A /* Debug */, 266 | 73C8D4FA161F70CA007F378A /* Release */, 267 | ); 268 | defaultConfigurationIsVisible = 0; 269 | defaultConfigurationName = Release; 270 | }; 271 | /* End XCConfigurationList section */ 272 | }; 273 | rootObject = 73C8D4D1161F70CA007F378A /* Project object */; 274 | } 275 | -------------------------------------------------------------------------------- /ExampleApp/KGModalExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ExampleApp/KGModalExample.xcodeproj/project.xcworkspace/xcshareddata/KGModalExample.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 5C978CE1-221A-4169-AF81-B64C6BBF112C 9 | IDESourceControlProjectName 10 | KGModalExample 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | FB6C026C-C1C4-455C-BA11-CFF8C0912A70 14 | https://github.com/kgn/KGModal.git 15 | 16 | IDESourceControlProjectPath 17 | ExampleApp/KGModalExample.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | FB6C026C-C1C4-455C-BA11-CFF8C0912A70 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/kgn/KGModal.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | FB6C026C-C1C4-455C-BA11-CFF8C0912A70 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | FB6C026C-C1C4-455C-BA11-CFF8C0912A70 36 | IDESourceControlWCCName 37 | KGModal 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ExampleApp/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // KGModal 4 | // 5 | // Created by David Keegan on 10/5/12. 6 | // Copyright (c) 2012 David Keegan. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "KGAppDelegate.h" 11 | 12 | int main(int argc, char *argv[]){ 13 | @autoreleasepool{ 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([KGAppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /KGModal.h: -------------------------------------------------------------------------------- 1 | // 2 | // KGModal.h 3 | // KGModal 4 | // 5 | // Created by David Keegan on 10/5/12. 6 | // Copyright (c) 2012 David Keegan. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | extern NSString *const KGModalWillShowNotification; 12 | extern NSString *const KGModalDidShowNotification; 13 | extern NSString *const KGModalWillHideNotification; 14 | extern NSString *const KGModalDidHideNotification; 15 | 16 | typedef NS_ENUM(NSUInteger, KGModalBackgroundDisplayStyle){ 17 | KGModalBackgroundDisplayStyleGradient, 18 | KGModalBackgroundDisplayStyleSolid 19 | }; 20 | 21 | typedef NS_ENUM(NSUInteger, KGModalCloseButtonType){ 22 | KGModalCloseButtonTypeNone, 23 | KGModalCloseButtonTypeLeft, 24 | KGModalCloseButtonTypeRight 25 | }; 26 | 27 | @interface KGModal : NSObject 28 | 29 | // Determines if the modal should dismiss if the user taps outside of the modal view 30 | // Defaults to YES 31 | @property (nonatomic) BOOL tapOutsideToDismiss; 32 | 33 | // Determines if the close button or tapping outside the modal should animate the dismissal 34 | // Defaults to YES 35 | @property (nonatomic) BOOL animateWhenDismissed; 36 | 37 | // Determins close button type (None/Left/Right) 38 | // Defaults to Left 39 | @property (nonatomic) KGModalCloseButtonType closeButtonType; 40 | 41 | // The background color of the modal window 42 | // Defaults black with 0.5 opacity 43 | @property (strong, nonatomic) UIColor *modalBackgroundColor; 44 | 45 | // The background display style, can be a transparent radial gradient or a transparent black 46 | // Defaults to gradient, this looks better but takes a bit more time to display on the retina iPad 47 | @property (nonatomic) KGModalBackgroundDisplayStyle backgroundDisplayStyle; 48 | 49 | // Determines if the modal should rotate when the device rotates 50 | // Defaults to YES, only applies to iOS5 51 | @property (nonatomic) BOOL shouldRotate; 52 | 53 | // The shared instance of the modal 54 | + (instancetype)sharedInstance; 55 | 56 | // Set the content view to display in the modal and display with animations 57 | - (void)showWithContentView:(UIView *)contentView; 58 | 59 | // Set the content view to display in the modal and whether the modal should animate in 60 | - (void)showWithContentView:(UIView *)contentView andAnimated:(BOOL)animated; 61 | 62 | // Set the content view controller to display in the modal and display with animations 63 | - (void)showWithContentViewController:(UIViewController *)contentViewController; 64 | 65 | // Set the content view controller to display in the modal and whether the modal should animate in 66 | - (void)showWithContentViewController:(UIViewController *)contentViewController andAnimated:(BOOL)animated; 67 | 68 | // Hide the modal with animations 69 | - (void)hide; 70 | 71 | // Hide the modal with animations, 72 | // run the completion after the modal is hidden 73 | - (void)hideWithCompletionBlock:(void(^)())completion; 74 | 75 | // Hide the modal and whether the modal should animate away 76 | - (void)hideAnimated:(BOOL)animated; 77 | 78 | // Hide the modal and whether the modal should animate away, 79 | // run the completion after the modal is hidden 80 | - (void)hideAnimated:(BOOL)animated withCompletionBlock:(void(^)())completion; 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /KGModal.m: -------------------------------------------------------------------------------- 1 | // 2 | // KGModal.m 3 | // KGModal 4 | // 5 | // Created by David Keegan on 10/5/12. 6 | // Copyright (c) 2012 David Keegan. All rights reserved. 7 | // 8 | 9 | #import "KGModal.h" 10 | #import 11 | 12 | CGFloat const kFadeInAnimationDuration = 0.3; 13 | CGFloat const kTransformPart1AnimationDuration = 0.2; 14 | CGFloat const kTransformPart2AnimationDuration = 0.1; 15 | CGFloat const kDefaultCloseButtonPadding = 17.0; 16 | 17 | NSString *const KGModalGradientViewTapped = @"KGModalGradientViewTapped"; 18 | 19 | NSString *const KGModalWillShowNotification = @"KGModalWillShowNotification"; 20 | NSString *const KGModalDidShowNotification = @"KGModalDidShowNotification"; 21 | NSString *const KGModalWillHideNotification = @"KGModalWillHideNotification"; 22 | NSString *const KGModalDidHideNotification = @"KGModalDidHideNotification"; 23 | 24 | @interface KGModalGradientView : UIView 25 | @end 26 | 27 | @interface KGModalContainerView : UIView 28 | @property (weak, nonatomic) CALayer *styleLayer; 29 | @property (strong, nonatomic) UIColor *modalBackgroundColor; 30 | @end 31 | 32 | @interface KGModalCloseButton : UIButton 33 | @end 34 | 35 | @interface KGModalViewController : UIViewController 36 | @property (weak, nonatomic) KGModalGradientView *styleView; 37 | @end 38 | 39 | @interface KGModal() 40 | @property (strong, nonatomic) UIWindow *window; 41 | @property (strong, nonatomic) UIViewController *contentViewController; 42 | @property (weak, nonatomic) KGModalViewController *viewController; 43 | @property (weak, nonatomic) KGModalContainerView *containerView; 44 | @property (weak, nonatomic) KGModalCloseButton *closeButton; 45 | @property (weak, nonatomic) UIView *contentView; 46 | 47 | @end 48 | 49 | @implementation KGModal 50 | 51 | + (instancetype)sharedInstance{ 52 | static id sharedInstance; 53 | static dispatch_once_t once; 54 | dispatch_once(&once, ^{ 55 | sharedInstance = [[[self class] alloc] init]; 56 | }); 57 | return sharedInstance; 58 | } 59 | 60 | - (instancetype)init{ 61 | if(!(self = [super init])){ 62 | return nil; 63 | } 64 | 65 | self.shouldRotate = YES; 66 | self.tapOutsideToDismiss = YES; 67 | self.animateWhenDismissed = YES; 68 | self.closeButtonType = KGModalCloseButtonTypeLeft; 69 | self.modalBackgroundColor = [UIColor colorWithWhite:0 alpha:0.5]; 70 | 71 | return self; 72 | } 73 | 74 | -(void)setCloseButtonType:(KGModalCloseButtonType)closeButtonType { 75 | _closeButtonType = closeButtonType; 76 | if(closeButtonType == KGModalCloseButtonTypeNone){ 77 | [self.closeButton setHidden:YES]; 78 | }else{ 79 | [self.closeButton setHidden:NO]; 80 | 81 | CGRect closeFrame = self.closeButton.frame; 82 | if(closeButtonType == KGModalCloseButtonTypeRight){ 83 | closeFrame.origin.x = round(CGRectGetWidth(self.containerView.frame)-kDefaultCloseButtonPadding-CGRectGetWidth(closeFrame)/2); 84 | }else{ 85 | closeFrame.origin.x = 0; 86 | } 87 | self.closeButton.frame = closeFrame; 88 | } 89 | } 90 | 91 | - (void)showWithContentView:(UIView *)contentView{ 92 | [self showWithContentView:contentView andAnimated:YES]; 93 | } 94 | 95 | - (void)showWithContentViewController:(UIViewController *)contentViewController{ 96 | [self showWithContentViewController:contentViewController andAnimated:YES]; 97 | } 98 | 99 | - (void)showWithContentViewController:(UIViewController *)contentViewController andAnimated:(BOOL)animated{ 100 | self.contentViewController = contentViewController; 101 | [self showWithContentView:contentViewController.view andAnimated:YES]; 102 | } 103 | 104 | - (void)showWithContentView:(UIView *)contentView andAnimated:(BOOL)animated { 105 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 106 | self.window.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; 107 | self.window.opaque = NO; 108 | 109 | KGModalViewController *viewController = [[KGModalViewController alloc] init]; 110 | self.window.rootViewController = viewController; 111 | self.viewController = viewController; 112 | 113 | CGFloat padding = 17; 114 | CGRect containerViewRect = CGRectInset(contentView.bounds, -padding, -padding); 115 | containerViewRect.origin.x = containerViewRect.origin.y = 0; 116 | containerViewRect.origin.x = round(CGRectGetMidX(self.window.bounds)-CGRectGetMidX(containerViewRect)); 117 | containerViewRect.origin.y = round(CGRectGetMidY(self.window.bounds)-CGRectGetMidY(containerViewRect)); 118 | KGModalContainerView *containerView = [[KGModalContainerView alloc] initWithFrame:containerViewRect]; 119 | containerView.modalBackgroundColor = self.modalBackgroundColor; 120 | containerView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin| 121 | UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin; 122 | containerView.layer.rasterizationScale = [[UIScreen mainScreen] scale]; 123 | contentView.frame = (CGRect){padding, padding, contentView.bounds.size}; 124 | [containerView addSubview:contentView]; 125 | [viewController.view addSubview:containerView]; 126 | self.containerView = containerView; 127 | 128 | KGModalCloseButton *closeButton = [[KGModalCloseButton alloc] init]; 129 | 130 | if(self.closeButtonType == KGModalCloseButtonTypeRight){ 131 | CGRect closeFrame = closeButton.frame; 132 | closeFrame.origin.x = CGRectGetWidth(containerView.bounds)-CGRectGetWidth(closeFrame); 133 | closeButton.frame = closeFrame; 134 | } 135 | 136 | [closeButton addTarget:self action:@selector(closeAction:) forControlEvents:UIControlEventTouchUpInside]; 137 | [containerView addSubview:closeButton]; 138 | self.closeButton = closeButton; 139 | 140 | // Force adjust visibility and placing 141 | [self setCloseButtonType:self.closeButtonType]; 142 | 143 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tapCloseAction:) 144 | name:KGModalGradientViewTapped object:nil]; 145 | 146 | // The window has to be un-hidden on the main thread 147 | // This will cause the window to display 148 | dispatch_async(dispatch_get_main_queue(), ^{ 149 | [[NSNotificationCenter defaultCenter] postNotificationName:KGModalWillShowNotification object:self]; 150 | [self.window makeKeyAndVisible]; 151 | 152 | if(animated){ 153 | viewController.styleView.alpha = 0; 154 | [UIView animateWithDuration:kFadeInAnimationDuration animations:^{ 155 | viewController.styleView.alpha = 1; 156 | }]; 157 | 158 | containerView.alpha = 0; 159 | containerView.layer.shouldRasterize = YES; 160 | containerView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.4, 0.4); 161 | [UIView animateWithDuration:kTransformPart1AnimationDuration animations:^{ 162 | containerView.alpha = 1; 163 | containerView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.1, 1.1); 164 | } completion:^(BOOL finished) { 165 | [UIView animateWithDuration:kTransformPart2AnimationDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ 166 | containerView.alpha = 1; 167 | containerView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1, 1); 168 | } completion:^(BOOL finished2) { 169 | containerView.layer.shouldRasterize = NO; 170 | [[NSNotificationCenter defaultCenter] postNotificationName:KGModalDidShowNotification object:self]; 171 | }]; 172 | }]; 173 | } 174 | }); 175 | } 176 | 177 | - (void)closeAction:(id)sender{ 178 | [self hideAnimated:self.animateWhenDismissed]; 179 | } 180 | 181 | - (void)tapCloseAction:(id)sender{ 182 | if(self.tapOutsideToDismiss){ 183 | [self hideAnimated:self.animateWhenDismissed]; 184 | } 185 | } 186 | 187 | - (void)hide{ 188 | [self hideAnimated:YES]; 189 | } 190 | 191 | - (void)hideWithCompletionBlock:(void(^)())completion{ 192 | [self hideAnimated:YES withCompletionBlock:completion]; 193 | } 194 | 195 | - (void)hideAnimated:(BOOL)animated{ 196 | [self hideAnimated:animated withCompletionBlock:nil]; 197 | } 198 | 199 | - (void)hideAnimated:(BOOL)animated withCompletionBlock:(void(^)())completion{ 200 | if(!animated){ 201 | [self cleanup]; 202 | return; 203 | } 204 | 205 | dispatch_async(dispatch_get_main_queue(), ^{ 206 | [[NSNotificationCenter defaultCenter] postNotificationName:KGModalWillHideNotification object:self]; 207 | 208 | [UIView animateWithDuration:kFadeInAnimationDuration animations:^{ 209 | self.viewController.styleView.alpha = 0; 210 | }]; 211 | 212 | self.containerView.layer.shouldRasterize = YES; 213 | [UIView animateWithDuration:kTransformPart2AnimationDuration animations:^{ 214 | self.containerView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.1, 1.1); 215 | } completion:^(BOOL finished){ 216 | [UIView animateWithDuration:kTransformPart1AnimationDuration delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ 217 | self.containerView.alpha = 0; 218 | self.containerView.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.4, 0.4); 219 | } completion:^(BOOL finished2){ 220 | [self cleanup]; 221 | if(completion){ 222 | completion(); 223 | } 224 | [[NSNotificationCenter defaultCenter] postNotificationName:KGModalDidHideNotification object:self]; 225 | }]; 226 | }]; 227 | }); 228 | } 229 | 230 | - (void)cleanup{ 231 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 232 | [self.containerView removeFromSuperview]; 233 | [[[[UIApplication sharedApplication] delegate] window] makeKeyWindow]; 234 | [self.window removeFromSuperview]; 235 | self.contentViewController = nil; 236 | self.window = nil; 237 | } 238 | 239 | - (void)setModalBackgroundColor:(UIColor *)modalBackgroundColor{ 240 | if(_modalBackgroundColor != modalBackgroundColor){ 241 | _modalBackgroundColor = modalBackgroundColor; 242 | self.containerView.modalBackgroundColor = modalBackgroundColor; 243 | } 244 | } 245 | 246 | - (void)dealloc{ 247 | [self cleanup]; 248 | } 249 | 250 | @end 251 | 252 | @implementation KGModalViewController 253 | 254 | - (void)loadView{ 255 | self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 256 | } 257 | 258 | - (void)viewDidLoad{ 259 | [super viewDidLoad]; 260 | 261 | self.view.backgroundColor = [UIColor clearColor]; 262 | self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; 263 | 264 | KGModalGradientView *styleView = [[KGModalGradientView alloc] initWithFrame:self.view.bounds]; 265 | styleView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; 266 | styleView.opaque = NO; 267 | [self.view addSubview:styleView]; 268 | self.styleView = styleView; 269 | } 270 | 271 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{ 272 | return [[KGModal sharedInstance] shouldRotate]; 273 | } 274 | 275 | - (BOOL)shouldAutorotate{ 276 | return [[KGModal sharedInstance] shouldRotate]; 277 | } 278 | 279 | @end 280 | 281 | @implementation KGModalContainerView 282 | 283 | - (instancetype)initWithFrame:(CGRect)frame{ 284 | if(!(self = [super initWithFrame:frame])){ 285 | return nil; 286 | } 287 | 288 | CALayer *styleLayer = [[CALayer alloc] init]; 289 | styleLayer.cornerRadius = 4; 290 | styleLayer.shadowColor= [[UIColor blackColor] CGColor]; 291 | styleLayer.shadowOffset = CGSizeMake(0, 0); 292 | styleLayer.shadowOpacity = 0.5; 293 | styleLayer.borderWidth = 1; 294 | styleLayer.borderColor = [[UIColor whiteColor] CGColor]; 295 | styleLayer.frame = CGRectInset(self.bounds, 12, 12); 296 | [self.layer addSublayer:styleLayer]; 297 | self.styleLayer = styleLayer; 298 | 299 | return self; 300 | } 301 | 302 | - (void)setModalBackgroundColor:(UIColor *)modalBackgroundColor{ 303 | if(_modalBackgroundColor != modalBackgroundColor){ 304 | _modalBackgroundColor = modalBackgroundColor; 305 | self.styleLayer.backgroundColor = [modalBackgroundColor CGColor]; 306 | } 307 | } 308 | 309 | @end 310 | 311 | @implementation KGModalGradientView 312 | 313 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ 314 | [[NSNotificationCenter defaultCenter] postNotificationName:KGModalGradientViewTapped object:nil]; 315 | } 316 | 317 | - (void)drawRect:(CGRect)rect{ 318 | CGContextRef context = UIGraphicsGetCurrentContext(); 319 | if([[KGModal sharedInstance] backgroundDisplayStyle] == KGModalBackgroundDisplayStyleSolid){ 320 | [[UIColor colorWithWhite:0 alpha:0.55] set]; 321 | CGContextFillRect(context, self.bounds); 322 | }else{ 323 | CGContextSaveGState(context); 324 | size_t gradLocationsNum = 2; 325 | CGFloat gradLocations[2] = {0.0f, 1.0f}; 326 | CGFloat gradColors[8] = {0, 0, 0, 0.3, 0, 0, 0, 0.8}; 327 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 328 | CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradColors, gradLocations, gradLocationsNum); 329 | CGColorSpaceRelease(colorSpace), colorSpace = NULL; 330 | CGPoint gradCenter= CGPointMake(round(CGRectGetMidX(self.bounds)), round(CGRectGetMidY(self.bounds))); 331 | CGFloat gradRadius = MAX(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds)); 332 | CGContextDrawRadialGradient(context, gradient, gradCenter, 0, gradCenter, gradRadius, kCGGradientDrawsAfterEndLocation); 333 | CGGradientRelease(gradient), gradient = NULL; 334 | CGContextRestoreGState(context); 335 | } 336 | } 337 | 338 | @end 339 | 340 | @implementation KGModalCloseButton 341 | 342 | - (instancetype)init{ 343 | if(!(self = [super initWithFrame:(CGRect){0, 0, 32, 32}])){ 344 | return nil; 345 | } 346 | static UIImage *closeButtonImage; 347 | static dispatch_once_t once; 348 | dispatch_once(&once, ^{ 349 | closeButtonImage = [self closeButtonImage]; 350 | }); 351 | [self setBackgroundImage:closeButtonImage forState:UIControlStateNormal]; 352 | return self; 353 | } 354 | 355 | - (UIImage *)closeButtonImage{ 356 | UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0); 357 | 358 | //// General Declarations 359 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 360 | CGContextRef context = UIGraphicsGetCurrentContext(); 361 | 362 | //// Color Declarations 363 | UIColor *topGradient = [UIColor colorWithRed:0.21 green:0.21 blue:0.21 alpha:0.9]; 364 | UIColor *bottomGradient = [UIColor colorWithRed:0.03 green:0.03 blue:0.03 alpha:0.9]; 365 | 366 | //// Gradient Declarations 367 | NSArray *gradientColors = @[(id)topGradient.CGColor, 368 | (id)bottomGradient.CGColor]; 369 | CGFloat gradientLocations[] = {0, 1}; 370 | CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)gradientColors, gradientLocations); 371 | 372 | //// Shadow Declarations 373 | CGColorRef shadow = [UIColor blackColor].CGColor; 374 | CGSize shadowOffset = CGSizeMake(0, 1); 375 | CGFloat shadowBlurRadius = 3; 376 | CGColorRef shadow2 = [UIColor blackColor].CGColor; 377 | CGSize shadow2Offset = CGSizeMake(0, 1); 378 | CGFloat shadow2BlurRadius = 0; 379 | 380 | 381 | //// Oval Drawing 382 | UIBezierPath *ovalPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(4, 3, 24, 24)]; 383 | CGContextSaveGState(context); 384 | [ovalPath addClip]; 385 | CGContextDrawLinearGradient(context, gradient, CGPointMake(16, 3), CGPointMake(16, 27), 0); 386 | CGContextRestoreGState(context); 387 | 388 | CGContextSaveGState(context); 389 | CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, shadow); 390 | [[UIColor whiteColor] setStroke]; 391 | ovalPath.lineWidth = 2; 392 | [ovalPath stroke]; 393 | CGContextRestoreGState(context); 394 | 395 | 396 | //// Bezier Drawing 397 | UIBezierPath *bezierPath = [UIBezierPath bezierPath]; 398 | [bezierPath moveToPoint:CGPointMake(22.36, 11.46)]; 399 | [bezierPath addLineToPoint:CGPointMake(18.83, 15)]; 400 | [bezierPath addLineToPoint:CGPointMake(22.36, 18.54)]; 401 | [bezierPath addLineToPoint:CGPointMake(19.54, 21.36)]; 402 | [bezierPath addLineToPoint:CGPointMake(16, 17.83)]; 403 | [bezierPath addLineToPoint:CGPointMake(12.46, 21.36)]; 404 | [bezierPath addLineToPoint:CGPointMake(9.64, 18.54)]; 405 | [bezierPath addLineToPoint:CGPointMake(13.17, 15)]; 406 | [bezierPath addLineToPoint:CGPointMake(9.64, 11.46)]; 407 | [bezierPath addLineToPoint:CGPointMake(12.46, 8.64)]; 408 | [bezierPath addLineToPoint:CGPointMake(16, 12.17)]; 409 | [bezierPath addLineToPoint:CGPointMake(19.54, 8.64)]; 410 | [bezierPath addLineToPoint:CGPointMake(22.36, 11.46)]; 411 | [bezierPath closePath]; 412 | CGContextSaveGState(context); 413 | CGContextSetShadowWithColor(context, shadow2Offset, shadow2BlurRadius, shadow2); 414 | [[UIColor whiteColor] setFill]; 415 | [bezierPath fill]; 416 | CGContextRestoreGState(context); 417 | 418 | 419 | //// Cleanup 420 | CGGradientRelease(gradient); 421 | CGColorSpaceRelease(colorSpace); 422 | 423 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 424 | UIGraphicsEndImageContext(); 425 | 426 | return image; 427 | } 428 | 429 | @end 430 | -------------------------------------------------------------------------------- /KGModal.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "KGModal" 3 | s.version = "1.2.0" 4 | s.summary = "KGModal is an easy drop in control that allows you to display any view in a modal popup." 5 | s.homepage = "https://github.com/kgn/KGModal" 6 | s.screenshots = "https://raw.github.com/kgn/KGModal/master/Screenshot.jpg" 7 | s.license = { :type => 'MIT', :file => 'license.txt' } 8 | s.author = { "David Keegan" => "git@davidkeegan.com" } 9 | s.source = { :git => "https://github.com/kgn/KGModal.git", :tag => "v#{s.version}" } 10 | s.platform = :ios, '5.0' 11 | s.source_files = 'KGModal.{h,m}' 12 | s.requires_arc = true 13 | end 14 | -------------------------------------------------------------------------------- /Screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kgn/KGModal/cf976893fc4581b4ac654a9a7010aab6f3544015/Screenshot.jpg -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 David Keegan (http://davidkeegan.com) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | KGModal is an easy drop in control that allows you to display any view in a modal popup. The modal will automatically scale to fit the content view and center it on screen with nice animations! 2 | 3 | ![](https://raw.github.com/kgn/KGModal/master/Screenshot.jpg) 4 | 5 | You supply your own content view and KGModal does the rest: 6 | 7 | ``` obj-c 8 | [[KGModal sharedInstance] showWithContentView:contentView andAnimated:YES]; 9 | ``` 10 | 11 | There are a couple other options but it's purposely designed to be simple and easy to use: 12 | 13 | ``` obj-c 14 | // Determines if the modal should dismiss if the user taps outside of the modal view 15 | // Defaults to YES 16 | @property (nonatomic) BOOL tapOutsideToDismiss; 17 | 18 | // Determines if the close button or tapping outside the modal should animate the dismissal 19 | // Defaults to YES 20 | @property (nonatomic) BOOL animateWhenDismissed; 21 | 22 | // Determins close button type (None/Left/Right) 23 | // Defaults to Left 24 | @property (nonatomic) KGModalCloseButtonType closeButtonType; 25 | 26 | // Determines whether close button will display on the left or right 27 | // Defaults to left 28 | @property (nonatomic) KGModalCloseButtonLocation closeButtonLocation; 29 | 30 | // The background color of the modal window 31 | // Defaults black with 0.5 opacity 32 | @property (strong, nonatomic) UIColor *modalBackgroundColor; 33 | 34 | // The background display style, can be a transparent radial gradient or a transparent black 35 | // Defaults to gradient, this looks better but takes a bit more time to display on the retina iPad 36 | @property (nonatomic) enum KGModalBackgroundDisplayStyle backgroundDisplayStyle; 37 | 38 | // The shared instance of the modal 39 | + (id)sharedInstance; 40 | 41 | // Set the content view to display in the modal and display with animations 42 | - (void)showWithContentView:(UIView *)contentView; 43 | 44 | // Set the content view to display in the modal and whether the modal should animate in 45 | - (void)showWithContentView:(UIView *)contentView andAnimated:(BOOL)animated; 46 | 47 | // Hide the modal with animations 48 | - (void)hide; 49 | 50 | // Hide the modal with animations, 51 | // run the completion after the modal is hidden 52 | - (void)hideWithCompletionBlock:(void(^)())completion; 53 | 54 | // Hide the modal and whether the modal should animate away 55 | - (void)hideAnimated:(BOOL)animated; 56 | 57 | // Hide the modal and whether the modal should animate away, 58 | // run the completion after the modal is hidden 59 | - (void)hideAnimated:(BOOL)animated withCompletionBlock:(void(^)())completion; 60 | ``` 61 | 62 | Check out the ExampleApp to see it in action! 63 | 64 | ###Installation via Cocoapods 65 | 66 | Add `pod 'KGModal', '~> 0.0.1'` to your `Podfile` and run `pod` to install. 67 | --------------------------------------------------------------------------------