├── .idea ├── .name ├── vcs.xml ├── modules.xml ├── JCAlert.iml ├── misc.xml └── workspace.xml ├── JCAlertController ├── Assets.xcassets │ ├── Contents.json │ ├── alert.imageset │ │ ├── alert@2x.png │ │ └── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── RootVC.h ├── ViewController.h ├── JCAlertController │ ├── ButtonItem │ │ ├── JCAlertButtonItem.m │ │ └── JCAlertButtonItem.h │ ├── Category │ │ ├── UIWindow+JCBlur.h │ │ ├── UIColor+JCHightlightedColor.h │ │ ├── UIImage+JCColor2Image.h │ │ ├── NSAttributedString+JCCalculateSize.h │ │ ├── UIImage+JCColor2Image.m │ │ ├── UIColor+JCHightlightedColor.m │ │ ├── NSAttributedString+JCCalculateSize.m │ │ └── UIWindow+JCBlur.m │ ├── AlertView │ │ ├── JCAlertView.h │ │ └── JCAlertView.m │ ├── JCPresentQueue │ │ ├── UIViewController+JCPresentQueue.h │ │ ├── JCPresentController.h │ │ ├── JCPresentController.m │ │ └── UIViewController+JCPresentQueue.m │ ├── JCAlertController.h │ ├── Style │ │ ├── JCAlertStyle.h │ │ └── JCAlertStyle.m │ └── JCAlertController.m ├── NormalVCForPresentation.h ├── AppDelegate.h ├── main.m ├── NSObject+BlockSEL.h ├── NormalVCForPresentation.m ├── NSObject+BlockSEL.m ├── Info.plist ├── Base.lproj │ └── LaunchScreen.storyboard ├── RootVC.m ├── AppDelegate.m └── ViewController.m ├── JCAlertController.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── project.pbxproj ├── JCAlertController.podspec ├── JCAlertControllerTests ├── Info.plist └── JCAlertControllerTests.m ├── JCAlertControllerUITests ├── Info.plist └── JCAlertControllerUITests.m ├── LICENSE ├── .gitignore ├── README_CN.md └── README.md /.idea/.name: -------------------------------------------------------------------------------- 1 | JCAlert -------------------------------------------------------------------------------- /JCAlertController/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /JCAlertController/Assets.xcassets/alert.imageset/alert@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RichDaddyCashMany/JCAlertController/HEAD/JCAlertController/Assets.xcassets/alert.imageset/alert@2x.png -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /JCAlertController.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /JCAlertController/RootVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // TestVC.h 3 | // JCAlertController 4 | // 5 | // Created by weiping.lii on 29/03/2018. 6 | // Copyright © 2018 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RootVC : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/JCAlert.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /JCAlertController/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/8. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UITableViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/ButtonItem/JCAlertButtonItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // JCAlertButtonItem.m 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/5. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import "JCAlertButtonItem.h" 10 | 11 | @implementation JCAlertButtonItem 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /JCAlertController/NormalVCForPresentation.h: -------------------------------------------------------------------------------- 1 | // 2 | // NormalVCForPresentation.h 3 | // JCAlertController 4 | // 5 | // Created by weiping.lii on 30/03/2018. 6 | // Copyright © 2018 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NormalVCForPresentation : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /JCAlertController.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/Category/UIWindow+JCBlur.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIWindow+blur.h 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/5. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIWindow (blur) 12 | 13 | - (UIImageView *)blurScreenshot; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /JCAlertController/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/8. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/Category/UIColor+JCHightlightedColor.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+JCHightlightedColor.h 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/6. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIColor (JCHightlightedColor) 12 | 13 | - (UIColor *)hightlightedColor; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/Category/UIImage+JCColor2Image.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+JCColor2Image.h 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/5. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIImage (JCColor2Image) 12 | 13 | +(UIImage *)createImageWithColor:(UIColor *)color; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /JCAlertController/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/8. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/Category/NSAttributedString+JCCalculateSize.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedString+JCCalculateSize.h 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/5. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSAttributedString (JCCalculateSize) 12 | 13 | - (CGSize)sizeWithMaxWidth:(CGFloat)maxWidth; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /JCAlertController/Assets.xcassets/alert.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "alert@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/ButtonItem/JCAlertButtonItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // JCAlertButtonItem.h 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/5. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "JCAlertStyle.h" 11 | 12 | @interface JCAlertButtonItem : NSObject 13 | 14 | @property (nonatomic, copy) NSString *title; 15 | @property (nonatomic, copy) void (^clicked)(void); 16 | @property (nonatomic) JCButtonType type; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /JCAlertController/NSObject+BlockSEL.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+BlockSEL.h 3 | // 4 | // 5 | // Created by HJaycee on 2017/4/28. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | @param weakSelf 方便使用,用来打破循环引用。使用时需要改成实际类型,否则没有代码提示. 13 | @param arg 事件默认传递的对象,比如`NSNotification`,`UIButton`。 14 | */ 15 | typedef void (^callback)(id weakSelf, id arg); 16 | 17 | @interface NSObject (BlockSEL) 18 | 19 | /** 20 | 用block来代替selector 21 | */ 22 | - (SEL)selectorBlock:(callback)block; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /JCAlertController.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "JCAlertController" 3 | s.version = "3.0.4" 4 | s.summary = "A replacement of UIAlertController" 5 | s.homepage = "https://github.com/HJaycee/JCAlertController" 6 | s.license = "MIT" 7 | s.author = { "HJaycee" => "huangxisu@gmail.com" } 8 | s.platform = :ios, "7.0" 9 | s.source = { :git => "https://github.com/HJaycee/JCAlertController.git", :tag => s.version } 10 | s.source_files = "JCAlertController/JCAlertController/**/*.{h,m}" 11 | s.frameworks = 'Accelerate' 12 | s.requires_arc = true 13 | end 14 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /JCAlertControllerTests/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 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /JCAlertControllerUITests/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 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/AlertView/JCAlertView.h: -------------------------------------------------------------------------------- 1 | // 2 | // JCAlertController.h 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/1. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "JCAlertStyle.h" 11 | 12 | @protocol JCAlertViewDelegate 13 | 14 | - (void)alertButtonClicked:(void(^)(void))clicked; 15 | 16 | @end 17 | 18 | @interface JCAlertView : UIView 19 | 20 | @property (nonatomic, copy) NSString *title; 21 | @property (nonatomic, copy) NSString *message; 22 | @property (nonatomic, strong) UIView *contentView; 23 | @property (nonatomic, strong) NSArray *buttonItems; 24 | @property (nonatomic, strong) JCAlertStyle *style; 25 | 26 | @property (nonatomic, weak) id delegate; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/Category/UIImage+JCColor2Image.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+JCColor2Image.m 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/5. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import "UIImage+JCColor2Image.h" 10 | 11 | @implementation UIImage (JCJCColor2Image) 12 | 13 | + (UIImage *)createImageWithColor:(UIColor *)color { 14 | CGRect rect=CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); 15 | UIGraphicsBeginImageContext(rect.size); 16 | CGContextRef context = UIGraphicsGetCurrentContext(); 17 | CGContextSetFillColorWithColor(context, [color CGColor]); 18 | CGContextFillRect(context, rect); 19 | UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext(); 20 | UIGraphicsEndImageContext(); 21 | return theImage; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /JCAlertController/NormalVCForPresentation.m: -------------------------------------------------------------------------------- 1 | // 2 | // NormalVCForPresentation.m 3 | // JCAlertController 4 | // 5 | // Created by weiping.lii on 30/03/2018. 6 | // Copyright © 2018 HJaycee. All rights reserved. 7 | // 8 | 9 | #import "NormalVCForPresentation.h" 10 | 11 | @interface NormalVCForPresentation () 12 | 13 | @end 14 | 15 | @implementation NormalVCForPresentation 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithTitle:@"Dismiss" style:UIBarButtonItemStyleDone target:self action:@selector(onDismiss)]; 21 | self.navigationItem.leftBarButtonItem = item; 22 | self.view.backgroundColor = [UIColor whiteColor]; 23 | } 24 | 25 | - (void)onDismiss { 26 | [self dismissViewControllerAnimated:YES completion:nil]; 27 | } 28 | 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/Category/UIColor+JCHightlightedColor.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+JCHightlightedColor.m 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/6. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import "UIColor+JCHightlightedColor.h" 10 | 11 | #define deepValue 10 12 | 13 | @implementation UIColor (JCHightlightedColor) 14 | 15 | - (UIColor *)hightlightedColor { 16 | const CGFloat *components = CGColorGetComponents(self.CGColor); 17 | 18 | CGFloat r = components[0]; 19 | CGFloat g = components[1]; 20 | CGFloat b = components[2]; 21 | 22 | r = r * 255 - deepValue >= 0 ? r * 255 - deepValue : 0; 23 | g = g * 255 - deepValue >= 0 ? g * 255 - deepValue : 0; 24 | b = b * 255 - deepValue >= 0 ? b * 255 - deepValue : 0; 25 | 26 | return [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:components[3]]; 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/Category/NSAttributedString+JCCalculateSize.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSAttributedString+JCCalculateSize.m 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/5. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import "NSAttributedString+JCCalculateSize.h" 10 | 11 | @implementation NSAttributedString (JCCalculateSize) 12 | 13 | - (CGSize)sizeWithMaxWidth:(CGFloat)maxWidth { 14 | if ([self length] > 0) { 15 | CGRect textRect = [self 16 | boundingRectWithSize:CGSizeMake(maxWidth, MAXFLOAT) 17 | options:(NSStringDrawingUsesLineFragmentOrigin | 18 | NSStringDrawingUsesFontLeading) 19 | context:nil]; 20 | return CGSizeMake(ceilf(textRect.size.width), ceilf(textRect.size.height)); 21 | } else { 22 | return CGSizeZero; 23 | }} 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /JCAlertController/NSObject+BlockSEL.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+BlockSEL.m 3 | // 4 | // 5 | // Created by HJaycee on 2017/4/28. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import "NSObject+BlockSEL.h" 10 | #import 11 | 12 | @implementation NSObject (BlockSEL) 13 | 14 | - (SEL)selectorBlock:(void (^)(id, id))block { 15 | if (!block) { 16 | [NSException raise:@"block can not be nil" format:@"%@ selectorBlock error", self]; 17 | } 18 | NSString *selName = [NSString stringWithFormat:@"selector_%p:", block]; 19 | SEL sel = NSSelectorFromString(selName); 20 | class_addMethod([self class], sel, (IMP)selectorImp, "v@:@"); 21 | objc_setAssociatedObject(self, sel, block, OBJC_ASSOCIATION_COPY_NONATOMIC); 22 | return sel; 23 | } 24 | 25 | static void selectorImp(id self, SEL _cmd, id arg) { 26 | callback block = objc_getAssociatedObject(self, _cmd); 27 | __weak typeof(self) weakSelf = self; 28 | if (block) { 29 | block(weakSelf, arg); 30 | } 31 | } 32 | 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /JCAlertController/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /JCAlertControllerTests/JCAlertControllerTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // JCAlertControllerTests.m 3 | // JCAlertControllerTests 4 | // 5 | // Created by HJaycee on 2017/4/8. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JCAlertControllerTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation JCAlertControllerTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2015 MJRefresh (https://github.com/HJaycee/JCAlertController) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/JCPresentQueue/UIViewController+JCPresentQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+JCPresentQueue.h 3 | // JCPresentController 4 | // 5 | // Created by HJaycee on 2017/4/4. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | extern NSString * const JCPresentControllersAllDismissedNotification; 12 | 13 | typedef NS_OPTIONS (NSUInteger, JCPresentType) { 14 | JCPresentTypeLIFO = 0, // last in, first out 15 | JCPresentTypeFIFO // first in, last out 16 | }; 17 | 18 | @interface UIViewController (JCPresentQueue) 19 | 20 | /** 21 | Present any controller with LIFO or FIFO. 22 | Choose one to use, dont't use LIFO and FIFO two together. 23 | 24 | @param controller any controller inherits in UIViewController 25 | @param presentType JCPresentTypeLIFO or JCPresentTypeFIFO 26 | @param presentCompletion callback if presented 27 | @param dismissCompletion callback if dismissed 28 | */ 29 | - (void)jc_presentViewController:(UIViewController *)controller presentType:(JCPresentType)presentType presentCompletion:(void (^)(void))presentCompletion dismissCompletion:(void (^)(void))dismissCompletion; 30 | 31 | @end 32 | 33 | -------------------------------------------------------------------------------- /JCAlertController/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 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIRequiredDeviceCapabilities 26 | 27 | armv7 28 | 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/JCPresentQueue/JCPresentController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JCPresentController.h 3 | // JCPresentController 4 | // 5 | // Created by HJaycee on 2018/5/3. 6 | // Copyright © 2018年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JCPresentController : NSObject 12 | 13 | /** 14 | overlayWindow's default windowLevel is UIWindowLevelNormal, you can modify it 15 | 16 | @param windowLevel windowLevel 17 | */ 18 | + (void)setOverlayWindowLevel:(UIWindowLevel)windowLevel; 19 | 20 | /** 21 | viewControllers will be presented like LIFO 22 | 23 | @param viewController viewControllerToPresent 24 | @param presentCompletion be performed after present 25 | @param dismissCompletion be performed after dismiss 26 | */ 27 | + (void)presentViewControllerLIFO:(UIViewController *)viewController presentCompletion:(void (^)(void))presentCompletion dismissCompletion:(void (^)(void))dismissCompletion; 28 | 29 | /** 30 | viewControllers will be presented like FIFO 31 | 32 | @param viewController viewControllerToPresent 33 | @param presentCompletion be performed after present 34 | @param dismissCompletion be performed after dismiss 35 | */ 36 | + (void)presentViewControllerFIFO:(UIViewController *)viewController presentCompletion:(void (^)(void))presentCompletion dismissCompletion:(void (^)(void))dismissCompletion; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /JCAlertControllerUITests/JCAlertControllerUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // JCAlertControllerUITests.m 3 | // JCAlertControllerUITests 4 | // 5 | // Created by HJaycee on 2017/4/8. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JCAlertControllerUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation JCAlertControllerUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /JCAlertController/Base.lproj/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 | -------------------------------------------------------------------------------- /JCAlertController/RootVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // TestVC.m 3 | // JCAlertController 4 | // 5 | // Created by weiping.lii on 29/03/2018. 6 | // Copyright © 2018 HJaycee. All rights reserved. 7 | // 8 | 9 | #import "RootVC.h" 10 | #import "ViewController.h" 11 | 12 | @interface RootVC () 13 | 14 | @property (strong, nonatomic) UIButton *pushButton; 15 | @property (strong, nonatomic) UIButton *presentButton; 16 | 17 | @end 18 | 19 | @implementation RootVC 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | self.view.backgroundColor = [UIColor whiteColor]; 24 | 25 | [self.view addSubview:self.pushButton]; 26 | [self.view addSubview:self.presentButton]; 27 | 28 | self.pushButton.frame = CGRectMake(50, 200, 100, 50); 29 | self.presentButton.frame = CGRectMake(50, 300, 100, 50); 30 | } 31 | 32 | - (void)onPushButtonClicked:(UIButton *)button { 33 | ViewController *vc = [ViewController new]; 34 | [self.navigationController pushViewController:vc animated:YES]; 35 | } 36 | 37 | - (void)onPresentButtonClicked:(UIButton *)button { 38 | ViewController *vc = [ViewController new]; 39 | [self presentViewController:vc animated:YES completion:nil]; 40 | } 41 | 42 | - (UIButton *)pushButton { 43 | if (!_pushButton) { 44 | _pushButton = [UIButton buttonWithType:UIButtonTypeCustom]; 45 | [_pushButton setTitle:@"Push" forState:UIControlStateNormal]; 46 | _pushButton.backgroundColor = [UIColor blackColor]; 47 | [_pushButton addTarget:self action:@selector(onPushButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; 48 | } 49 | return _pushButton; 50 | } 51 | 52 | - (UIButton *)presentButton { 53 | if (!_presentButton) { 54 | _presentButton = [UIButton buttonWithType:UIButtonTypeCustom]; 55 | [_presentButton setTitle:@"Present" forState:UIControlStateNormal]; 56 | _presentButton.backgroundColor = [UIColor blackColor]; 57 | [_presentButton addTarget:self action:@selector(onPresentButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; 58 | } 59 | return _presentButton; 60 | } 61 | 62 | 63 | @end 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /JCAlertController/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/6. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ViewController.h" 11 | #import "RootVC.h" 12 | #import "UIViewController+JCPresentQueue.h" 13 | 14 | @interface AppDelegate () 15 | 16 | @end 17 | 18 | @implementation AppDelegate 19 | 20 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 21 | // Override point for customization after application launch. 22 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 23 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[RootVC new]]; 24 | self.window.rootViewController = nav; 25 | [self.window makeKeyAndVisible]; 26 | return YES; 27 | } 28 | 29 | - (void)applicationWillResignActive:(UIApplication *)application { 30 | // 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. 31 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 32 | } 33 | 34 | 35 | - (void)applicationDidEnterBackground:(UIApplication *)application { 36 | // 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. 37 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 38 | } 39 | 40 | 41 | - (void)applicationWillEnterForeground:(UIApplication *)application { 42 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 43 | } 44 | 45 | 46 | - (void)applicationDidBecomeActive:(UIApplication *)application { 47 | // 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. 48 | } 49 | 50 | 51 | - (void)applicationWillTerminate:(UIApplication *)application { 52 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 53 | } 54 | 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/JCAlertController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JCAlertController.h 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/3/31. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "JCPresentController.h" 11 | #import "JCAlertStyle.h" 12 | 13 | /** 14 | Same level with UIAlertController. 15 | Use method 'jc_presentViewController...' in 'UIViewController+JCPresentQueue.h',It accouts with FIFO or LIFO. 16 | Use +[JCAlertStyle styleWithType:JCAlertType] to change the style of alertView. 17 | */ 18 | @interface JCAlertController : UIViewController 19 | 20 | /** 21 | Class method to create 'JCAlertController' instance 22 | The alertView is composed of title, message and buttons 23 | */ 24 | + (instancetype)alertWithTitle:(NSString *)title message:(NSString *)message; 25 | 26 | /** 27 | The alertView is composed of title, contentView and buttons 28 | */ 29 | + (instancetype)alertWithTitle:(NSString *)title contentView:(UIView *)contentView; 30 | 31 | /** 32 | Add a button on alertView with title and action 33 | */ 34 | - (void)addButtonWithTitle:(NSString *)title type:(JCButtonType)type clicked:(void (^)(void))clicked; 35 | 36 | @end 37 | 38 | @interface JCAlertController (keyboardHandle) 39 | 40 | /** 41 | Monitor keyboard showed state 42 | 43 | @param showed callback after keyboard showed 44 | */ 45 | - (void)monitorKeyboardShowed:(void(^)(CGFloat alertHeight, CGFloat keyboardHeight))showed; 46 | 47 | /** 48 | Monitor keyboard hided state 49 | 50 | @param hided callback after keyboard hided 51 | */ 52 | - (void)monitorKeyboardHided:(void(^)(void))hided; 53 | 54 | /** 55 | Move alertView to new centerY to avoid the keyboard 56 | 57 | @param centerY centerY 58 | @param animated is animated 59 | */ 60 | - (void)moveAlertViewToCenterY:(CGFloat)centerY animated:(BOOL)animated; 61 | 62 | /** 63 | Move alertView to center of screen 64 | 65 | @param animated is animated 66 | */ 67 | - (void)moveAlertViewToScreenCenterAnimated:(BOOL)animated; 68 | 69 | @end 70 | 71 | @interface JCAlertController (Deprecated) 72 | 73 | /** 74 | It's too waste time to pass parameter `type` each time. 75 | */ 76 | + (instancetype)alertWithTitle:(NSString *)title message:(NSString *)message type:(JCAlertType)type NS_DEPRECATED_IOS(2.0, 6.0, "Use + (instancetype)alertWithTitle:(NSString *)title message:(NSString *)message; please!"); 77 | + (instancetype)alertWithTitle:(NSString *)title contentView:(UIView *)contentView type:(JCAlertType)type NS_DEPRECATED_IOS(2.0, 6.0, "Use + (instancetype)alertWithTitle:(NSString *)title contentView:(UIView *)contentView; please!"); 78 | - (instancetype)initWithTitle:(NSString *)title message:(NSString *)message type:(JCAlertType)type NS_DEPRECATED_IOS(2.0, 6.0, "Use + (instancetype)alertWithTitle:(NSString *)title message:(NSString *)message; please!"); 79 | - (instancetype)initWithTitle:(NSString *)title contentView:(UIView *)contentView type:(JCAlertType)type NS_DEPRECATED_IOS(2.0, 6.0, "Use + (instancetype)alertWithTitle:(NSString *)title contentView:(UIView *)contentView; please!"); 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/JCPresentQueue/JCPresentController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JCPresentController.m 3 | // JCPresentController 4 | // 5 | // Created by HJaycee on 2018/5/3. 6 | // Copyright © 2018年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import "JCPresentController.h" 10 | #import "UIViewController+JCPresentQueue.h" 11 | 12 | @interface JCPresentWindow : UIWindow 13 | @end 14 | 15 | @implementation JCPresentWindow 16 | @end 17 | 18 | @interface JCPresentRootController : UIViewController 19 | @end 20 | 21 | @implementation JCPresentRootController 22 | @end 23 | 24 | @interface JCPresentQueueManager : NSObject 25 | 26 | @property (nonatomic) UIWindow *overlayWindow; 27 | @property (nonatomic) UIWindowLevel overLayWindowLevel; 28 | + (instancetype)shareManager; 29 | 30 | @end 31 | 32 | @implementation JCPresentQueueManager 33 | 34 | + (instancetype)shareManager { 35 | static JCPresentQueueManager *manager; 36 | static dispatch_once_t onceToken; 37 | dispatch_once(&onceToken, ^{ 38 | manager = [JCPresentQueueManager new]; 39 | }); 40 | return manager; 41 | } 42 | 43 | - (UIWindow *)overlayWindow { 44 | if (!_overlayWindow) { 45 | JCPresentRootController *rootViewController = [JCPresentRootController new]; 46 | rootViewController.view.backgroundColor = [UIColor clearColor]; 47 | _overlayWindow = [[JCPresentWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 48 | _overlayWindow.backgroundColor = [UIColor clearColor]; 49 | _overlayWindow.windowLevel = self.overLayWindowLevel; 50 | _overlayWindow.rootViewController = rootViewController; 51 | _overlayWindow.hidden = NO; 52 | [_overlayWindow makeKeyAndVisible]; 53 | } 54 | return _overlayWindow; 55 | } 56 | 57 | @end 58 | 59 | @implementation JCPresentController 60 | 61 | + (void)load { 62 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAllControllersDismissed) name:JCPresentControllersAllDismissedNotification object:nil]; 63 | } 64 | 65 | + (void)setOverlayWindowLevel:(UIWindowLevel)windowLevel { 66 | [JCPresentQueueManager shareManager].overLayWindowLevel = windowLevel; 67 | } 68 | 69 | + (void)presentViewControllerLIFO:(UIViewController *)viewController presentCompletion:(void (^)(void))presentCompletion dismissCompletion:(void (^)(void))dismissCompletion { 70 | [self presentViewController:viewController presentType:JCPresentTypeLIFO presentCompletion:presentCompletion dismissCompletion:dismissCompletion]; 71 | } 72 | 73 | + (void)presentViewControllerFIFO:(UIViewController *)viewController presentCompletion:(void (^)(void))presentCompletion dismissCompletion:(void (^)(void))dismissCompletion { 74 | [self presentViewController:viewController presentType:JCPresentTypeFIFO presentCompletion:presentCompletion dismissCompletion:dismissCompletion]; 75 | } 76 | 77 | + (void)presentViewController:(UIViewController *)viewController presentType:(JCPresentType)presentType presentCompletion:(void (^)(void))presentCompletion dismissCompletion:(void (^)(void))dismissCompletion { 78 | [[JCPresentQueueManager shareManager].overlayWindow.rootViewController jc_presentViewController:viewController presentType:presentType presentCompletion:^{ 79 | if (presentCompletion) { 80 | presentCompletion(); 81 | } 82 | } dismissCompletion:^{ 83 | if (dismissCompletion) { 84 | dismissCompletion(); 85 | } 86 | }]; 87 | } 88 | 89 | + (void)onAllControllersDismissed { 90 | [JCPresentQueueManager shareManager].overlayWindow.hidden = YES; 91 | [JCPresentQueueManager shareManager].overlayWindow = nil; 92 | } 93 | 94 | @end 95 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/Style/JCAlertStyle.h: -------------------------------------------------------------------------------- 1 | // 2 | // JCAlertStyle.h 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/5. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UIColor+JCHightlightedColor.h" 11 | 12 | typedef NS_OPTIONS (NSUInteger, JCButtonType){ 13 | JCButtonTypeNormal = 0, 14 | JCButtonTypeCancel, 15 | JCButtonTypeWarning 16 | }; 17 | 18 | @interface JCAlertStyleAlertView : NSObject 19 | @property (nonatomic) CGFloat width; 20 | @property (nonatomic) CGFloat maxHeight; 21 | @property (nonatomic, strong) UIColor *backgroundColor; 22 | @property (nonatomic) CGFloat cornerRadius; 23 | @end 24 | 25 | @interface JCAlertStyleBackground : NSObject 26 | @property (nonatomic) BOOL blur; 27 | @property (nonatomic) BOOL canDismiss; // dismissed with touched the bg 28 | @property (nonatomic) float alpha; 29 | @end 30 | 31 | @interface JCAlertStyleTitle : NSObject 32 | @property (nonatomic) UIEdgeInsets insets; 33 | @property (nonatomic) UIEdgeInsets onlyTitleInsets; 34 | @property (nonatomic) CGFloat minHeight; 35 | @property (nonatomic, strong) UIFont *font; 36 | @property (nonatomic, strong) UIColor *textColor; 37 | @property (nonatomic, strong) UIColor *backgroundColor; 38 | @property (assign, nonatomic) NSTextAlignment textAlignment; 39 | @end 40 | 41 | @interface JCAlertStyleButton : NSObject 42 | @property (nonatomic) CGFloat height; 43 | @property (nonatomic, strong) UIFont *font; 44 | @property (nonatomic, strong) UIColor *textColor; 45 | @property (nonatomic, strong) UIColor *backgroundColor; 46 | @property (nonatomic, strong) UIColor *highlightTextColor; 47 | @property (nonatomic, strong) UIColor *highlightBackgroundColor; 48 | @end 49 | 50 | @interface JCAlertStyleButtonNormal : JCAlertStyleButton 51 | @end 52 | 53 | @interface JCAlertStyleButtonCancel : JCAlertStyleButton 54 | @end 55 | 56 | @interface JCAlertStyleButtonWarning : JCAlertStyleButton 57 | @end 58 | 59 | @interface JCAlertStyleContent : NSObject 60 | @property (nonatomic) UIEdgeInsets insets; 61 | @property (nonatomic) UIEdgeInsets onlyMessageInsets; 62 | @property (nonatomic) CGFloat minHeight; 63 | @property (nonatomic, strong) UIFont *font; 64 | @property (nonatomic, strong) UIColor *textColor; 65 | @property (nonatomic, strong) UIColor *backgroundColor; 66 | @property (assign, nonatomic) NSTextAlignment textAlignment; 67 | @end 68 | 69 | @interface JCAlertStyleSeparator : NSObject 70 | @property (nonatomic) CGFloat width; 71 | @property (nonatomic, strong) UIColor *color; 72 | @end 73 | 74 | @interface JCAlertStyle : NSObject 75 | 76 | @property (nonatomic, strong) JCAlertStyleAlertView *alertView; 77 | @property (nonatomic, strong) JCAlertStyleBackground *background; 78 | @property (nonatomic, strong) JCAlertStyleTitle *title; 79 | @property (nonatomic, strong) JCAlertStyleContent *content; 80 | @property (nonatomic, strong) JCAlertStyleButtonNormal *buttonNormal; 81 | @property (nonatomic, strong) JCAlertStyleButtonCancel *buttonCancel; 82 | @property (nonatomic, strong) JCAlertStyleButtonWarning *buttonWarning; 83 | @property (nonatomic, strong) JCAlertStyleSeparator *separator; 84 | 85 | + (instancetype)shareStyle; 86 | 87 | @end 88 | 89 | @interface JCAlertStyle (Deprecated) 90 | 91 | typedef NS_OPTIONS (NSUInteger, JCAlertType){ 92 | JCAlertTypeNormal NS_ENUM_DEPRECATED_IOS(2.0, 6.0, "No longer support") = 0, 93 | JCAlertTypeTitleOnly NS_ENUM_DEPRECATED_IOS(2.0, 6.0, "No longer support"), 94 | JCAlertTypeContentOnly NS_ENUM_DEPRECATED_IOS(2.0, 6.0, "No longer support"), 95 | JCAlertTypeCustom NS_ENUM_DEPRECATED_IOS(2.0, 6.0, "No longer support") 96 | }; 97 | 98 | + (JCAlertStyle *)styleWithType:(JCAlertType)type NS_DEPRECATED_IOS(2.0, 6.0, "Use + (instancetype)alertWithTitle:(NSString *)title message:(NSString *)message; please!"); 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/Category/UIWindow+JCBlur.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIWindow+blur.m 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/5. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import "UIWindow+JCBlur.h" 10 | #import 11 | 12 | @implementation UIWindow (JCBlur) 13 | 14 | - (UIImageView *)blurScreenshot { 15 | UIGraphicsBeginImageContext(self.frame.size); 16 | [self.layer renderInContext:UIGraphicsGetCurrentContext()]; 17 | UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext(); 18 | UIGraphicsEndImageContext(); 19 | 20 | UIImage *originalImage = viewImage; 21 | 22 | CGFloat blurRadius = 4; 23 | UIColor *tintColor = [UIColor clearColor]; 24 | CGFloat saturationDeltaFactor = 1; 25 | UIImage *maskImage = nil; 26 | 27 | CGRect imageRect = { CGPointZero, originalImage.size }; 28 | UIImage *effectImage = originalImage; 29 | 30 | BOOL hasBlur = blurRadius > __FLT_EPSILON__; 31 | BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__; 32 | if (hasBlur || hasSaturationChange) { 33 | UIGraphicsBeginImageContextWithOptions(originalImage.size, NO, [[UIScreen mainScreen] scale]); 34 | CGContextRef effectInContext = UIGraphicsGetCurrentContext(); 35 | CGContextScaleCTM(effectInContext, 1.0, -1.0); 36 | CGContextTranslateCTM(effectInContext, 0, -originalImage.size.height); 37 | CGContextDrawImage(effectInContext, imageRect, originalImage.CGImage); 38 | 39 | vImage_Buffer effectInBuffer; 40 | effectInBuffer.data = CGBitmapContextGetData(effectInContext); 41 | effectInBuffer.width = CGBitmapContextGetWidth(effectInContext); 42 | effectInBuffer.height = CGBitmapContextGetHeight(effectInContext); 43 | effectInBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectInContext); 44 | 45 | UIGraphicsBeginImageContextWithOptions(originalImage.size, NO, [[UIScreen mainScreen] scale]); 46 | CGContextRef effectOutContext = UIGraphicsGetCurrentContext(); 47 | vImage_Buffer effectOutBuffer; 48 | effectOutBuffer.data = CGBitmapContextGetData(effectOutContext); 49 | effectOutBuffer.width = CGBitmapContextGetWidth(effectOutContext); 50 | effectOutBuffer.height = CGBitmapContextGetHeight(effectOutContext); 51 | effectOutBuffer.rowBytes = CGBitmapContextGetBytesPerRow(effectOutContext); 52 | 53 | if (hasBlur) { 54 | CGFloat inputRadius = blurRadius * [[UIScreen mainScreen] scale]; 55 | uint32_t radius = floor(inputRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5); 56 | if (radius % 2 != 1) { 57 | radius += 1; 58 | } 59 | vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); 60 | vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); 61 | vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, NULL, 0, 0, radius, radius, 0, kvImageEdgeExtend); 62 | } 63 | BOOL effectImageBuffersAreSwapped = NO; 64 | if (hasSaturationChange) { 65 | CGFloat s = saturationDeltaFactor; 66 | CGFloat floatingPointSaturationMatrix[] = { 67 | 0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0, 68 | 0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0, 69 | 0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0, 70 | 0, 0, 0, 1, 71 | }; 72 | const int32_t divisor = 256; 73 | NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]); 74 | int16_t saturationMatrix[matrixSize]; 75 | for (NSUInteger i = 0; i < matrixSize; ++i) { 76 | saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor); 77 | } 78 | if (hasBlur) { 79 | vImageMatrixMultiply_ARGB8888(&effectOutBuffer, &effectInBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); 80 | effectImageBuffersAreSwapped = YES; 81 | } 82 | else { 83 | vImageMatrixMultiply_ARGB8888(&effectInBuffer, &effectOutBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags); 84 | } 85 | } 86 | if (!effectImageBuffersAreSwapped) 87 | effectImage = UIGraphicsGetImageFromCurrentImageContext(); 88 | UIGraphicsEndImageContext(); 89 | 90 | if (effectImageBuffersAreSwapped) 91 | effectImage = UIGraphicsGetImageFromCurrentImageContext(); 92 | UIGraphicsEndImageContext(); 93 | } 94 | 95 | UIGraphicsBeginImageContextWithOptions(originalImage.size, NO, [[UIScreen mainScreen] scale]); 96 | CGContextRef outputContext = UIGraphicsGetCurrentContext(); 97 | CGContextScaleCTM(outputContext, 1.0, -1.0); 98 | CGContextTranslateCTM(outputContext, 0, -originalImage.size.height); 99 | 100 | CGContextDrawImage(outputContext, imageRect, originalImage.CGImage); 101 | 102 | if (hasBlur) { 103 | CGContextSaveGState(outputContext); 104 | if (maskImage) { 105 | CGContextClipToMask(outputContext, imageRect, maskImage.CGImage); 106 | } 107 | CGContextDrawImage(outputContext, imageRect, effectImage.CGImage); 108 | CGContextRestoreGState(outputContext); 109 | } 110 | 111 | if (tintColor) { 112 | CGContextSaveGState(outputContext); 113 | CGContextSetFillColorWithColor(outputContext, tintColor.CGColor); 114 | CGContextFillRect(outputContext, imageRect); 115 | CGContextRestoreGState(outputContext); 116 | } 117 | 118 | UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext(); 119 | UIGraphicsEndImageContext(); 120 | 121 | return [[UIImageView alloc] initWithImage:outputImage]; 122 | } 123 | 124 | @end 125 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/Style/JCAlertStyle.m: -------------------------------------------------------------------------------- 1 | // 2 | // JCAlertStyle.m 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/5. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import "JCAlertStyle.h" 10 | 11 | #define JCColor(r,g,b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1.0] 12 | #define JCDefaultTextColor JCColor(0,0,0) 13 | 14 | @interface JCAlertStyleCache : NSObject 15 | 16 | @property (nonatomic, strong) JCAlertStyle *styleNormal; 17 | @property (nonatomic, strong) JCAlertStyle *styleTitleOnly; 18 | @property (nonatomic, strong) JCAlertStyle *styleContentOnly; 19 | 20 | @end 21 | 22 | @implementation JCAlertStyleCache 23 | @end 24 | 25 | @implementation JCAlertStyleAlertView @end 26 | @implementation JCAlertStyleBackground @end 27 | @implementation JCAlertStyleTitle @end 28 | @implementation JCAlertStyleContent @end 29 | @implementation JCAlertStyleButton @end 30 | @implementation JCAlertStyleButtonNormal @end 31 | @implementation JCAlertStyleButtonCancel @end 32 | @implementation JCAlertStyleButtonWarning @end 33 | @implementation JCAlertStyleSeparator @end 34 | 35 | @implementation JCAlertStyle 36 | 37 | + (instancetype)shareStyle { 38 | static JCAlertStyle *style = nil; 39 | static dispatch_once_t onceToken; 40 | dispatch_once(&onceToken, ^{ 41 | style = [JCAlertStyle new]; 42 | // default 43 | [style useDefaultStyle]; 44 | }); 45 | return style; 46 | } 47 | 48 | + (JCAlertStyle *)styleWithType:(JCAlertType)type { 49 | static JCAlertStyleCache *cache = nil; 50 | static dispatch_once_t onceToken; 51 | dispatch_once(&onceToken, ^{ 52 | cache = [JCAlertStyleCache new]; 53 | cache.styleNormal = [[JCAlertStyle alloc] initWithType:JCAlertTypeNormal]; 54 | cache.styleTitleOnly = [[JCAlertStyle alloc] initWithType:JCAlertTypeTitleOnly]; 55 | cache.styleContentOnly = [[JCAlertStyle alloc] initWithType:JCAlertTypeContentOnly]; 56 | }); 57 | 58 | if (type == JCAlertTypeNormal) { 59 | return cache.styleNormal; 60 | } else if (type == JCAlertTypeTitleOnly) { 61 | return cache.styleTitleOnly; 62 | } else { 63 | return cache.styleContentOnly; 64 | } 65 | } 66 | 67 | #pragma clang diagnostic push 68 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 69 | 70 | - (instancetype)initWithType:(JCAlertType)type { 71 | if (self = [super init]) { 72 | [self useDefaultStyle]; 73 | 74 | if (type == JCAlertTypeTitleOnly) { 75 | [self useTitleOnlyStyle]; 76 | } else if (type == JCAlertTypeContentOnly) { 77 | [self useContentOnlyStyle]; 78 | } 79 | } 80 | return self; 81 | } 82 | 83 | #pragma clang diagnostic pop 84 | 85 | - (void)useDefaultStyle { 86 | JCAlertStyleBackground *background = [JCAlertStyleBackground new]; 87 | background.blur = NO; 88 | background.canDismiss = NO; 89 | background.alpha = 0.3; 90 | 91 | JCAlertStyleAlertView *alertView = [JCAlertStyleAlertView new]; 92 | alertView.width = [UIScreen mainScreen].bounds.size.width == 320 ? 260 : 280; 93 | alertView.maxHeight = [UIScreen mainScreen].bounds.size.height - 120; 94 | alertView.backgroundColor = [UIColor whiteColor]; 95 | alertView.cornerRadius = 8; 96 | 97 | JCAlertStyleTitle *title = [JCAlertStyleTitle new]; 98 | title.insets = UIEdgeInsetsMake(10, 10, 10, 10); 99 | title.onlyTitleInsets = UIEdgeInsetsMake(28, 20, 28, 20); 100 | title.font = [UIFont boldSystemFontOfSize:17]; 101 | title.textColor = JCDefaultTextColor; 102 | title.backgroundColor = [UIColor whiteColor]; 103 | title.textAlignment = NSTextAlignmentCenter; 104 | 105 | JCAlertStyleContent *content = [JCAlertStyleContent new]; 106 | content.insets = UIEdgeInsetsMake(5, 10, 15, 10); 107 | content.onlyMessageInsets = UIEdgeInsetsMake(28, 20, 28, 20); 108 | content.font = [UIFont systemFontOfSize:15]; 109 | content.textColor = JCDefaultTextColor; 110 | content.backgroundColor = [UIColor whiteColor]; 111 | content.textAlignment = NSTextAlignmentCenter; 112 | 113 | JCAlertStyleButtonNormal *buttonNormal = [JCAlertStyleButtonNormal new]; 114 | buttonNormal.height = 44; 115 | buttonNormal.font = [UIFont systemFontOfSize:17]; 116 | buttonNormal.textColor = JCDefaultTextColor; 117 | buttonNormal.backgroundColor = [UIColor whiteColor]; 118 | buttonNormal.highlightTextColor = JCDefaultTextColor; 119 | buttonNormal.highlightBackgroundColor = JCColor(224, 224, 224); 120 | 121 | JCAlertStyleButtonCancel *buttonCancel = [JCAlertStyleButtonCancel new]; 122 | buttonCancel.height = 44; 123 | buttonCancel.font = [UIFont systemFontOfSize:17]; 124 | buttonCancel.textColor = JCDefaultTextColor; 125 | buttonCancel.backgroundColor = [UIColor whiteColor]; 126 | buttonCancel.highlightTextColor = JCDefaultTextColor; 127 | buttonCancel.highlightBackgroundColor = JCColor(224, 224, 224); 128 | 129 | JCAlertStyleButtonWarning *buttonWarning = [JCAlertStyleButtonWarning new]; 130 | buttonWarning.height = 44; 131 | buttonWarning.font = [UIFont systemFontOfSize:17]; 132 | buttonWarning.textColor = JCColor(248, 59, 50); 133 | buttonWarning.backgroundColor = [UIColor whiteColor]; 134 | buttonWarning.highlightTextColor = JCColor(248, 59, 50); 135 | buttonWarning.highlightBackgroundColor = JCColor(224, 224, 224); 136 | 137 | JCAlertStyleSeparator *separator = [JCAlertStyleSeparator new]; 138 | separator.width = 0.5; 139 | separator.color = JCColor(200, 200, 205); 140 | 141 | self.background = background; 142 | self.alertView = alertView; 143 | self.title = title; 144 | self.content = content; 145 | self.buttonNormal = buttonNormal; 146 | self.buttonCancel = buttonCancel; 147 | self.buttonWarning = buttonWarning; 148 | self.separator = separator; 149 | } 150 | 151 | - (void)useTitleOnlyStyle { 152 | self.title.insets = UIEdgeInsetsMake(28, 20, 28, 20); 153 | } 154 | 155 | - (void)useContentOnlyStyle { 156 | self.content.insets = UIEdgeInsetsMake(28, 20, 28, 20); 157 | } 158 | 159 | @end 160 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 31 | 36 | 37 | 38 | 39 | true 40 | 41 | 42 | 43 | 44 | 45 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 81 | 82 | 83 | 84 | 87 | 88 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 1446598579909 110 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 142 | 145 | 146 | 147 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### [English](https://github.com/HJaycee/JCAlertController) | [中文](https://github.com/HJaycee/JCAlertController/blob/master/README_CN.md) 4 | 5 | JCAlertController继承于UIViewController,可以作为替代UIAlertController的弹窗库,使用简单,可自定义程度高。 6 | 7 | 8 | | 比较 |队列管理 | 自定义样式 | 自定义view | 最低支持系统 | 9 | | :----: | :----: | :----: | :----: | :----: | 10 | | JCAlertController | 支持 | 简单 | 简单 | iOS 7| 11 | | UIAlertController | 不支持 | 复杂 | 复杂 | iOS 8| 12 | 13 | 14 | * 支持队列管理 15 | * 支持自定义样式 16 | * 支持自定义contentView 17 | 18 | ## 什么是队列管理 ? 19 | 请看下面的伪代码: 20 | 21 | ```objc 22 | [self presentWithFIFO:alert1]; 23 | [self presentWithFIFO:alert2]; 24 | [self presentWithFIFO:alert3]; 25 | ``` 26 | 结果:
27 | alert1`第一个`显示, 被用户关闭后, alert2`第二个`显示, 被用户关闭后, alert3`第三个`显示
28 | 就像这样: `alert1` >> `alert2` >> `alert3` 29 | 30 | ```objc 31 | [self presentWithLIFO:alert1]; 32 | [self presentWithLIFO:alert2]; 33 | [self presentWithLIFO:alert3]; 34 | ``` 35 | 结果:
36 | alert3`第一个`显示, 被用户关闭后, alert2`第二个`显示, 被用户关闭后, alert1`第三个`显示
37 | 就像这样 `alert3` >> `alert2` >> `alert1` 38 | 39 | >Present顺序由 [JCPresentQueue](https://github.com/HJaycee/JCPresentQueue)管理,支持cocoapods导入。你可以用它来自动管理任何`UIAlertController`库的弹出顺序。 40 | >如果你已经导入了[JCAlertController](https://github.com/HJaycee/JCAlertController)就不用再导入[JCPresentQueue](https://github.com/HJaycee/JCPresentQueue)了。 41 | 42 | ## 预览 43 | 44 | #### 默认样式(标题和内容都有) 45 | 46 | 47 | #### 默认样式(只有标题) 48 | 49 | 50 | #### 默认样式(只有内容) 51 | 52 | 53 | 54 | #### 默认样式 (超长文字) 55 | 56 | 57 | #### 自定义样式 58 | 59 | 60 | #### 自定义View 61 | 62 | 63 | #### 自定义View+键盘处理 64 | 65 | 66 | #### 自定义View+富文本 67 | 68 | 69 | 70 | ## 文件结构 71 | 72 | ```objc 73 | . 74 | |____.DS_Store 75 | |____AlertView 76 | | |____JCAlertView.h 77 | | |____JCAlertView.m 78 | |____ButtonItem 79 | | |____JCAlertButtonItem.h 80 | | |____JCAlertButtonItem.m 81 | |____Category 82 | | |____NSAttributedString+JCCalculateSize.h 83 | | |____NSAttributedString+JCCalculateSize.m 84 | | |____UIColor+JCHightlightedColor.h 85 | | |____UIColor+JCHightlightedColor.m 86 | | |____UIImage+JCColor2Image.h 87 | | |____UIImage+JCColor2Image.m 88 | | |____UIViewController+JCPresentQueue.h // present category 89 | | |____UIViewController+JCPresentQueue.m 90 | | |____UIWindow+JCBlur.h 91 | | |____UIWindow+JCBlur.m 92 | |____JCAlertController.h // import this 93 | |____JCAlertController.m 94 | |____Style 95 | | |____JCAlertStyle.h 96 | | |____JCAlertStyle.m 97 | | |____JCAlertStyleAlertView.h 98 | | |____JCAlertStyleAlertView.m 99 | | |____JCAlertStyleBackground.h 100 | | |____JCAlertStyleBackground.m 101 | | |____JCAlertStyleButton.h 102 | | |____JCAlertStyleButton.m 103 | | |____JCAlertStyleButtonCancel.h 104 | | |____JCAlertStyleButtonCancel.m 105 | | |____JCAlertStyleButtonNormal.h 106 | | |____JCAlertStyleButtonNormal.m 107 | | |____JCAlertStyleButtonWarning.h 108 | | |____JCAlertStyleButtonWarning.m 109 | | |____JCAlertStyleContent.h 110 | | |____JCAlertStyleContent.m 111 | | |____JCAlertStyleSeparator.h 112 | | |____JCAlertStyleSeparator.m 113 | | |____JCAlertStyleTitle.h 114 | | |____JCAlertStyleTitle.m 115 | ``` 116 | 117 | ## 使用CocoaPods集成 118 | 119 | step 1 120 | ```objc 121 | platform :ios, '7.0' 122 | target 'your target' do 123 | pod 'JCAlertController' 124 | end 125 | ``` 126 | 127 | step 2 128 | ```objc 129 | #import "JCAlertController.h" 130 | ``` 131 | 132 | ## 如何使用 133 | 134 | ```objc 135 | // LIFO: alert3 >> alert2 >> alert1 136 | for (int i = 1; i<4; i++) { 137 | JCAlertController *alert = [JCAlertController alertWithTitle:[NSString stringWithFormat:@"alert%zi", i] message:nil]; 138 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 139 | [self jc_presentViewController:alert presentCompletion:nil dismissCompletion:nil]; 140 | } 141 | ``` 142 | 143 | 144 | ## Contact me 145 | 146 | E-mail: hjaycee@163.com
147 | Blog: http://www.jianshu.com/u/8bde69945e50 148 | 149 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### [English](https://github.com/HJaycee/JCAlertController) | [中文](https://github.com/HJaycee/JCAlertController/blob/master/README_CN.md) 4 | 5 | `JCAlertController` is `same level` with `UIAlertController`.
6 | It is `inherited` from `UIViewController` too.
7 | It supports managing presented controllers with `FIFO` or `LIFO`. 8 | 9 | 10 | | Compare | Present Queue | Custom Style | Custom View | Minimum iOS Target | 11 | | :----: | :----: | :----: | :----: | :----: | 12 | | JCAlertController | support | simple | simple | iOS 7| 13 | | UIAlertController | not support| difficult | difficult | iOS 8| 14 | 15 | 16 | * support present queue 17 | * support custom style 18 | * support custom contentView 19 | 20 | ## What is present queue ? 21 | Look at the flowing code: 22 | 23 | ```objc 24 | [self presentWithFIFO:alert1]; 25 | [self presentWithFIFO:alert2]; 26 | [self presentWithFIFO:alert3]; 27 | ``` 28 | Result:
29 | alert1 shows `first`, after dismissed by user, alert2 shows `second`, after dismissed by user, alert3 shows `third`.
30 | like this: `alert1` >> `alert2` >> `alert3` 31 | 32 | ```objc 33 | [self presentWithLIFO:alert1]; 34 | [self presentWithLIFO:alert2]; 35 | [self presentWithLIFO:alert3]; 36 | ``` 37 | Result:
38 | alert3 shows `first`, after dismissed by user, alert2 shows `second`, after dismissed by user, alert1 shows `third`.
39 | like this `alert3` >> `alert2` >> `alert1` 40 | 41 | Present queue is powered by [JCPresentQueue](https://github.com/HJaycee/JCPresentQueue). It supports cocoapods too. 42 | 43 | ## Preview 44 | 45 | #### normal style 46 | 47 | 48 | #### normal style(title only) 49 | 50 | 51 | #### normal style(content only) 52 | 53 | 54 | 55 | #### normal style (words oveflow) 56 | 57 | 58 | #### custom style 59 | 60 | 61 | #### custom contentView 62 | 63 | 64 | #### custom contentView and keyboard handle 65 | 66 | 67 | #### custom contentView and attributedstring 68 | 69 | 70 | 71 | ## Struct 72 | 73 | ```objc 74 | . 75 | |____.DS_Store 76 | |____AlertView 77 | | |____JCAlertView.h 78 | | |____JCAlertView.m 79 | |____ButtonItem 80 | | |____JCAlertButtonItem.h 81 | | |____JCAlertButtonItem.m 82 | |____Category 83 | | |____NSAttributedString+JCCalculateSize.h 84 | | |____NSAttributedString+JCCalculateSize.m 85 | | |____UIColor+JCHightlightedColor.h 86 | | |____UIColor+JCHightlightedColor.m 87 | | |____UIImage+JCColor2Image.h 88 | | |____UIImage+JCColor2Image.m 89 | | |____UIViewController+JCPresentQueue.h // present category 90 | | |____UIViewController+JCPresentQueue.m 91 | | |____UIWindow+JCBlur.h 92 | | |____UIWindow+JCBlur.m 93 | |____JCAlertController.h // import this 94 | |____JCAlertController.m 95 | |____Style 96 | | |____JCAlertStyle.h 97 | | |____JCAlertStyle.m 98 | | |____JCAlertStyleAlertView.h 99 | | |____JCAlertStyleAlertView.m 100 | | |____JCAlertStyleBackground.h 101 | | |____JCAlertStyleBackground.m 102 | | |____JCAlertStyleButton.h 103 | | |____JCAlertStyleButton.m 104 | | |____JCAlertStyleButtonCancel.h 105 | | |____JCAlertStyleButtonCancel.m 106 | | |____JCAlertStyleButtonNormal.h 107 | | |____JCAlertStyleButtonNormal.m 108 | | |____JCAlertStyleButtonWarning.h 109 | | |____JCAlertStyleButtonWarning.m 110 | | |____JCAlertStyleContent.h 111 | | |____JCAlertStyleContent.m 112 | | |____JCAlertStyleSeparator.h 113 | | |____JCAlertStyleSeparator.m 114 | | |____JCAlertStyleTitle.h 115 | | |____JCAlertStyleTitle.m 116 | ``` 117 | 118 | ## Installation with CocoaPods 119 | 120 | step 1 121 | ```objc 122 | platform :ios, '7.0' 123 | target 'your target' do 124 | pod 'JCAlertController' 125 | end 126 | ``` 127 | 128 | step 2 129 | ```objc 130 | #import "JCAlertController.h" 131 | ``` 132 | 133 | ## Usage 134 | 135 | ```objc 136 | // LIFO: alert3 >> alert2 >> alert1 137 | for (int i = 1; i<4; i++) { 138 | JCAlertController *alert = [JCAlertController alertWithTitle:[NSString stringWithFormat:@"alert%zi", i] message:nil]; 139 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 140 | [self jc_presentViewController:alert presentCompletion:nil dismissCompletion:nil]; 141 | } 142 | ``` 143 | 144 | ## Contact me 145 | 146 | E-mail: hjaycee@163.com
147 | Blog: http://www.jianshu.com/u/8bde69945e50 148 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/JCPresentQueue/UIViewController+JCPresentQueue.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+JCPresentQueue.m 3 | // JCPresentController 4 | // 5 | // Created by HJaycee on 2017/4/4. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import "UIViewController+JCPresentQueue.h" 10 | #import 11 | 12 | NSString * const JCPresentControllersAllDismissedNotification = @"JCPresentControllersAllDismissedNotification"; 13 | 14 | static NSMutableArray *_stackControllers; 15 | static NSOperationQueue *_operationQueue; 16 | static dispatch_queue_t _jc_present_queue; 17 | 18 | @implementation UIViewController (JCPresentQueue) 19 | 20 | + (void)load { 21 | SEL oldSel = @selector(viewDidDisappear:); 22 | SEL newSel = @selector(jc_viewDidDisappear:); 23 | Method oldMethod = class_getInstanceMethod([self class], oldSel); 24 | Method newMethod = class_getInstanceMethod([self class], newSel); 25 | 26 | BOOL didAddMethod = class_addMethod(self, oldSel, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)); 27 | if (didAddMethod) { 28 | class_replaceMethod(self, newSel, method_getImplementation(oldMethod), method_getTypeEncoding(oldMethod)); 29 | } else { 30 | method_exchangeImplementations(oldMethod, newMethod); 31 | } 32 | 33 | _stackControllers = ({ 34 | static NSMutableArray *stackControllers = nil; 35 | static dispatch_once_t onceToken; 36 | dispatch_once(&onceToken, ^{ 37 | stackControllers = [NSMutableArray array]; 38 | }); 39 | stackControllers; 40 | }); 41 | 42 | _operationQueue = ({ 43 | static NSOperationQueue *operationQueue = nil; 44 | static dispatch_once_t onceToken; 45 | dispatch_once(&onceToken, ^{ 46 | _jc_present_queue = dispatch_queue_create("jc_present_queue", DISPATCH_QUEUE_SERIAL); 47 | operationQueue = [NSOperationQueue new]; 48 | operationQueue.underlyingQueue = _jc_present_queue; 49 | }); 50 | operationQueue; 51 | }); 52 | } 53 | 54 | - (void)jc_viewDidDisappear:(BOOL)animated { 55 | [self jc_viewDidDisappear:animated]; 56 | 57 | if ([self getDeallocCompletion] && ![self isTemporarilyDismissed]) { 58 | [self getDeallocCompletion](); 59 | } 60 | } 61 | 62 | - (void)setDeallocCompletion:(void (^)(void))completion { 63 | objc_setAssociatedObject(self, @selector(getDeallocCompletion), completion, OBJC_ASSOCIATION_COPY_NONATOMIC); 64 | } 65 | 66 | - (void (^)(void))getDeallocCompletion { 67 | return objc_getAssociatedObject(self, _cmd); 68 | } 69 | 70 | - (void)setDismissCompletion:(void (^)(void))completion { 71 | objc_setAssociatedObject(self, @selector(getDismissCompletion), completion, OBJC_ASSOCIATION_COPY_NONATOMIC); 72 | } 73 | 74 | - (void (^)(void))getDismissCompletion { 75 | return objc_getAssociatedObject(self, _cmd); 76 | } 77 | 78 | - (void)setPresentCompletion:(void (^)(void))completion { 79 | objc_setAssociatedObject(self, @selector(getPresentCompletion), completion, OBJC_ASSOCIATION_COPY_NONATOMIC); 80 | } 81 | 82 | - (void (^)(void))getPresentCompletion { 83 | return objc_getAssociatedObject(self, _cmd); 84 | } 85 | 86 | - (void)setCurrentPresentType:(JCPresentType)presentType { 87 | objc_setAssociatedObject(self, @selector(getCurrentPresentType), @(presentType), OBJC_ASSOCIATION_COPY_NONATOMIC); 88 | } 89 | 90 | - (JCPresentType)getCurrentPresentType { 91 | NSNumber *type = objc_getAssociatedObject(self, _cmd); 92 | return [type integerValue]; 93 | } 94 | 95 | - (void)setTemporarilyDismissed:(BOOL)temporarilyDismissed { 96 | objc_setAssociatedObject(self, @selector(isTemporarilyDismissed), @(temporarilyDismissed), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 97 | } 98 | 99 | - (BOOL)isTemporarilyDismissed { 100 | NSNumber *num = objc_getAssociatedObject(self, _cmd); 101 | return [num boolValue]; 102 | } 103 | 104 | - (void)setDismissing:(BOOL)dismissing { 105 | objc_setAssociatedObject(self, @selector(isDismissing), @(dismissing), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 106 | } 107 | 108 | - (BOOL)isDismissing { 109 | NSNumber *num = objc_getAssociatedObject(self, _cmd); 110 | return [num boolValue]; 111 | } 112 | 113 | - (void)jc_presentViewController:(UIViewController *)controller presentType:(JCPresentType)presentType presentCompletion:(void (^)(void))presentCompletion dismissCompletion:(void (^)(void))dismissCompletion { 114 | if ([_operationQueue operations].count > 0 && presentType != [self getCurrentPresentType]) { 115 | [NSException raise:@"This is dangerous." format:@"%@'s present queue is confused. Dont't use LIFO and FIFO two together.", self]; 116 | } 117 | [self setCurrentPresentType:presentType]; 118 | 119 | if (presentType == JCPresentTypeLIFO) { 120 | [self lifoPresentViewController:controller presentCompletion:presentCompletion dismissCompletion:dismissCompletion]; 121 | } else { 122 | [self fifoPresentViewController:controller presentCompletion:presentCompletion dismissCompletion:dismissCompletion]; 123 | } 124 | } 125 | 126 | #pragma mark - present controller with LIFO 127 | - (void)lifoPresentViewController:(UIViewController *)controller presentCompletion:(void (^)(void))presentCompletion dismissCompletion:(void (^)(void))dismissCompletion { 128 | 129 | dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 130 | 131 | // put in stack 132 | NSMutableArray *stackControllers = _stackControllers; 133 | if (![stackControllers containsObject:controller]) { 134 | [stackControllers addObject:controller]; 135 | } 136 | 137 | NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ 138 | __weak typeof(controller) weakController = controller; 139 | [controller setPresentCompletion:presentCompletion]; 140 | [controller setDismissCompletion:dismissCompletion]; 141 | [controller setDeallocCompletion:^{ 142 | if (dismissCompletion) { 143 | dismissCompletion(); 144 | } 145 | 146 | // fetch new next controller if exists, because button action after dismiss completion 147 | [weakController setDismissing:YES]; 148 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 149 | [weakController setDismissing:NO]; 150 | // if the dismiss controller is the last one 151 | if (stackControllers.lastObject == weakController) { 152 | [stackControllers removeObject:weakController]; 153 | 154 | // is there any previous controllers 155 | if (stackControllers.count > 0) { 156 | UIViewController *preController = [stackControllers lastObject]; 157 | [self lifoPresentViewController:preController presentCompletion:[preController getPresentCompletion] dismissCompletion:[preController getDismissCompletion]]; 158 | } else { 159 | [[NSNotificationCenter defaultCenter] postNotificationName:JCPresentControllersAllDismissedNotification object:nil]; 160 | } 161 | } else { 162 | NSUInteger index = [stackControllers indexOfObject:weakController]; 163 | [stackControllers removeObject:weakController]; 164 | 165 | // is there any next controllers 166 | NSArray *nextControllers = [stackControllers objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, stackControllers.count - index)]]; 167 | for (UIViewController *nextController in nextControllers) { 168 | [self lifoPresentViewController:nextController presentCompletion:[nextController getPresentCompletion] dismissCompletion:[nextController getDismissCompletion]]; 169 | } 170 | } 171 | }); 172 | }]; 173 | 174 | // if the previous controller is dismissing, wait it's completion 175 | if (stackControllers.count > 1) { 176 | for (UIViewController *preController in stackControllers) { 177 | if ([preController isDismissing]) { 178 | return ; 179 | } 180 | } 181 | } 182 | 183 | // present a new controller before dismissing the presented controller if exists 184 | dispatch_async(dispatch_get_main_queue(), ^{ 185 | if (self.presentedViewController) { 186 | [self.presentedViewController temporarilyDismissViewControllerAnimated:YES completion:^{ 187 | [self presentViewController:controller animated:YES completion:^{ 188 | dispatch_semaphore_signal(semaphore); 189 | }]; 190 | }]; 191 | } else { 192 | [self presentViewController:controller animated:YES completion:^{ 193 | dispatch_semaphore_signal(semaphore); 194 | if (presentCompletion) { 195 | presentCompletion(); 196 | } 197 | }]; 198 | } 199 | }); 200 | 201 | dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 202 | }]; 203 | 204 | // put in queue 205 | if (_operationQueue.operations.lastObject) { 206 | [operation addDependency:_operationQueue.operations.lastObject]; 207 | } 208 | [_operationQueue addOperation:operation]; 209 | } 210 | 211 | // dismiss controller temporarily 212 | - (void)temporarilyDismissViewControllerAnimated: (BOOL)flag completion: (void (^ __nullable)(void))completion { 213 | [self setTemporarilyDismissed:YES]; 214 | [self dismissViewControllerAnimated:flag completion:^{ 215 | [self setTemporarilyDismissed:NO]; 216 | if (completion) { 217 | completion(); 218 | } 219 | }]; 220 | } 221 | 222 | #pragma mark - present controller with FIFO 223 | - (void)fifoPresentViewController:(UIViewController *)controller presentCompletion:(void (^)(void))presentCompletion dismissCompletion:(void (^)(void))dismissCompletion { 224 | dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 225 | NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ 226 | [controller setDeallocCompletion:^{ 227 | if (dismissCompletion) { 228 | dismissCompletion(); 229 | } 230 | 231 | if (_operationQueue.operations.count <= 1) { 232 | [[NSNotificationCenter defaultCenter] postNotificationName:JCPresentControllersAllDismissedNotification object:nil]; 233 | } 234 | 235 | // got to next operation 236 | dispatch_semaphore_signal(semaphore); 237 | }]; 238 | dispatch_async(dispatch_get_main_queue(), ^{ 239 | [self presentViewController:controller animated:YES completion:presentCompletion]; 240 | }); 241 | dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 242 | }]; 243 | 244 | // put in queue 245 | if (_operationQueue.operations.lastObject) { 246 | [operation addDependency:_operationQueue.operations.lastObject]; 247 | } 248 | [_operationQueue addOperation:operation]; 249 | } 250 | 251 | @end 252 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/JCAlertController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JCAlertController.m 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/3/31. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import "JCAlertController.h" 10 | #import "JCAlertView.h" 11 | #import "UIWindow+JCBlur.h" 12 | #import "JCAlertStyle.h" 13 | #import "NSAttributedString+JCCalculateSize.h" 14 | #import "JCAlertButtonItem.h" 15 | 16 | @interface JCAlertController () 17 | 18 | @property (nonatomic, strong) UIImageView *blurView; 19 | @property (nonatomic, strong) UIButton *coverView; 20 | @property (nonatomic, strong) JCAlertView *alertView; 21 | 22 | @end 23 | 24 | #pragma mark - transitionAnimation 25 | 26 | @interface JCDimissAnimation : NSObject 27 | @end 28 | 29 | @implementation JCDimissAnimation 30 | 31 | - (NSTimeInterval)transitionDuration:(id)transitionContext { 32 | return 0.2; 33 | } 34 | 35 | - (void)animateTransition:(id)transitionContext { 36 | JCAlertController *alertController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; 37 | 38 | NSTimeInterval duration = [self transitionDuration:transitionContext]; 39 | 40 | [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{ 41 | alertController.coverView.alpha = 0; 42 | alertController.blurView.alpha = 0; 43 | alertController.alertView.alpha = 0; 44 | } completion:^(BOOL finished) { 45 | [alertController.view removeFromSuperview]; 46 | [transitionContext completeTransition:YES]; 47 | }]; 48 | 49 | [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ 50 | alertController.alertView.transform = CGAffineTransformMakeScale(0.7, 0.7); 51 | } completion:^(BOOL finished) { 52 | alertController.alertView.transform = CGAffineTransformIdentity; 53 | }]; 54 | } 55 | 56 | @end 57 | 58 | @interface JCPresentAnimation : NSObject 59 | @end 60 | 61 | @implementation JCPresentAnimation 62 | 63 | - (NSTimeInterval)transitionDuration:(id)transitionContext { 64 | return 0.4; 65 | } 66 | 67 | - (void)animateTransition:(id)transitionContext { 68 | JCAlertController *alertController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; 69 | 70 | [[transitionContext containerView] addSubview:alertController.view]; 71 | 72 | NSTimeInterval duration = [self transitionDuration:transitionContext]; 73 | 74 | alertController.blurView.alpha = 0; 75 | alertController.coverView.alpha = 0; 76 | alertController.alertView.alpha = 1; 77 | alertController.alertView.transform = CGAffineTransformMakeScale(0.4, 0.4); 78 | 79 | [UIView animateWithDuration:duration / 2 animations:^{ 80 | alertController.coverView.alpha = alertController.alertView.style.background.alpha; 81 | }]; 82 | 83 | [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{ 84 | alertController.blurView.alpha = 1; 85 | } completion:nil]; 86 | 87 | [UIView animateWithDuration:duration delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:20 options:UIViewAnimationOptionAllowUserInteraction animations:^{ 88 | alertController.alertView.transform = CGAffineTransformIdentity; 89 | } completion:^(BOOL finished) { 90 | [transitionContext completeTransition:YES]; 91 | }]; 92 | } 93 | 94 | @end 95 | 96 | @interface JCAlertController () 97 | 98 | @property (nonatomic, copy) NSString *alertTitle; 99 | @property (nonatomic, copy) NSString *alertMessage; 100 | @property (nonatomic, strong) UIView *contentView; 101 | @property (nonatomic, strong) NSMutableArray *buttonItems; 102 | @property (nonatomic, strong) JCAlertStyle *style; 103 | @property (nonatomic, copy) void(^keyboardShowed)(CGFloat alertHeight, CGFloat keyboardHeight); 104 | @property (nonatomic, copy) void(^keyboardHided)(void); 105 | 106 | @end 107 | 108 | @implementation JCAlertController 109 | 110 | #pragma clang diagnostic push 111 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 112 | 113 | + (instancetype)alertWithTitle:(NSString *)title message:(NSString *)message { 114 | return [self alertWithTitle:title message:message type:0]; 115 | } 116 | 117 | + (instancetype)alertWithTitle:(NSString *)title contentView:(UIView *)contentView { 118 | return [self alertWithTitle:title contentView:contentView type:0]; 119 | } 120 | 121 | #pragma clang diagnostic pop 122 | 123 | + (instancetype)alertWithTitle:(NSString *)title message:(NSString *)message type:(JCAlertType)type { 124 | return [[self alloc] initWithTitle:title message:message type:type]; 125 | } 126 | 127 | + (instancetype)alertWithTitle:(NSString *)title contentView:(UIView *)contentView type:(JCAlertType)type { 128 | return [[self alloc] initWithTitle:title contentView:contentView type:type]; 129 | } 130 | 131 | - (instancetype)initWithTitle:(NSString *)title message:(NSString *)message type:(JCAlertType)type{ 132 | if (self = [super init]) { 133 | self.modalPresentationStyle = UIModalPresentationCustom; 134 | self.transitioningDelegate = self; 135 | self.alertTitle = title; 136 | self.alertMessage = message; 137 | self.style = [JCAlertStyle shareStyle]; 138 | 139 | if (self.alertTitle.length == 0 && self.alertMessage.length == 0) { 140 | [NSException raise:@"can not show" format:@"%@: need title or message at least one", self]; 141 | } 142 | } 143 | return self; 144 | } 145 | 146 | - (instancetype)initWithTitle:(NSString *)title contentView:(UIView *)contentView type:(JCAlertType)type { 147 | if (self = [super init]) { 148 | self.modalPresentationStyle = UIModalPresentationCustom; 149 | self.transitioningDelegate = self; 150 | self.alertTitle = title; 151 | self.contentView = contentView; 152 | self.style = [JCAlertStyle shareStyle]; 153 | 154 | if (self.alertTitle.length == 0 && contentView.frame.size.width != self.style.alertView.width) { 155 | [NSException raise:@"can not show" format:@"%@: title is empty or contentView's width is not equal to alertView's width", self]; 156 | } 157 | } 158 | return self; 159 | } 160 | 161 | - (void)monitorKeyboardShowed:(void(^)(CGFloat alertHeight, CGFloat keyboardHeight))showed { 162 | self.keyboardShowed = showed; 163 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardShow:) name:UIKeyboardWillShowNotification object:nil]; 164 | } 165 | 166 | - (void)monitorKeyboardHided:(void(^)(void))hided { 167 | self.keyboardHided = hided; 168 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardHide) name:UIKeyboardWillHideNotification object:nil]; 169 | } 170 | 171 | - (void)keyboardShow:(NSNotification *)notification { 172 | CGRect keyBoardRect = [[[notification userInfo]objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue]; 173 | 174 | if (self.keyboardShowed) { 175 | self.keyboardShowed(self.alertView.frame.size.height, keyBoardRect.size.height); 176 | } 177 | } 178 | 179 | - (void)keyboardHide { 180 | if (self.keyboardHided) { 181 | self.keyboardHided(); 182 | } 183 | } 184 | 185 | - (void)dealloc { 186 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 187 | } 188 | 189 | - (void)moveAlertViewToCenterY:(CGFloat)centerY animated:(BOOL)animated { 190 | [UIView animateWithDuration:animated ? 0.25 : 0 animations:^{ 191 | self.alertView.center = CGPointMake(self.alertView.center.x, centerY); 192 | }]; 193 | } 194 | 195 | - (void)moveAlertViewToScreenCenterAnimated:(BOOL)animated { 196 | [self moveAlertViewToCenterY:[UIScreen mainScreen].bounds.size.height / 2 animated:animated]; 197 | } 198 | 199 | - (NSMutableArray *)buttonItems { 200 | if (!_buttonItems) { 201 | _buttonItems = [NSMutableArray arrayWithCapacity:2]; 202 | } 203 | return _buttonItems; 204 | } 205 | 206 | - (void)addButtonWithTitle:(NSString *)title type:(JCButtonType)type clicked:(void (^)(void))clicked { 207 | if (self.buttonItems.count >= 2) { 208 | [NSException raise:@"You can add 2 buttons at most" format:@"%@: already has %zi buttons", self, self.buttonItems.count]; 209 | } 210 | 211 | JCAlertButtonItem *item = [JCAlertButtonItem new]; 212 | item.title = title; 213 | item.type = type; 214 | item.clicked = clicked; 215 | [self.buttonItems addObject:item]; 216 | } 217 | 218 | - (void)viewDidLoad { 219 | [super viewDidLoad]; 220 | 221 | [self setupBlurView]; 222 | [self setupAlphaCoverView]; 223 | [self setupAlertView]; 224 | } 225 | 226 | - (void)setupBlurView { 227 | if (self.style.background.blur) { 228 | // check the window 229 | NSArray* reversedWindows = [[[UIApplication sharedApplication].windows reverseObjectEnumerator] allObjects]; 230 | for (UIWindow *window in reversedWindows) { 231 | if ([NSStringFromClass([window class]) isEqualToString:@"UIWindow"] && CGRectEqualToRect(window.frame, [UIScreen mainScreen].bounds)) { 232 | self.blurView = [window blurScreenshot]; 233 | [self.view addSubview:self.blurView]; 234 | break; 235 | } 236 | } 237 | } 238 | } 239 | 240 | - (void)setupAlphaCoverView { 241 | self.coverView = [[UIButton alloc] initWithFrame:[UIScreen mainScreen].bounds]; 242 | self.coverView.backgroundColor = [UIColor colorWithRed:5/255.0 green:0 blue:10/255.0 alpha:1.0]; 243 | [self.view addSubview:self.coverView]; 244 | if (self.style.background.canDismiss) { 245 | [self.coverView addTarget:self action:@selector(dismissViewController) forControlEvents:UIControlEventTouchUpInside]; 246 | } 247 | } 248 | 249 | - (void)setupAlertView { 250 | self.alertView = [JCAlertView new]; 251 | self.alertView.title = self.alertTitle; 252 | self.alertView.message = self.alertMessage; 253 | self.alertView.contentView = self.contentView; 254 | self.alertView.buttonItems = self.buttonItems; 255 | self.alertView.style = self.style; 256 | self.alertView.backgroundColor = self.style.alertView.backgroundColor; 257 | self.alertView.delegate = self; 258 | [self.view addSubview:self.alertView]; 259 | } 260 | 261 | - (void)dismissViewController { 262 | [self dismissViewControllerAnimated:YES completion:nil]; 263 | } 264 | 265 | #pragma mark - transtionAnimation 266 | - (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { 267 | return [JCPresentAnimation new]; 268 | } 269 | 270 | - (id)animationControllerForDismissedController:(UIViewController *)dismissed { 271 | return [JCDimissAnimation new]; 272 | } 273 | 274 | #pragma mark - JCAlertViewDelegate 275 | - (void)alertButtonClicked:(void (^)(void))clicked { 276 | [self dismissViewControllerAnimated:YES completion:^{ 277 | if (clicked) { 278 | clicked(); 279 | } 280 | }]; 281 | } 282 | 283 | @end 284 | -------------------------------------------------------------------------------- /JCAlertController/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/6. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "JCAlertController.h" 11 | #import "NSObject+BlockSEL.h" // just used in demo 12 | #import "UIViewController+JCPresentQueue.h" 13 | #import "NormalVCForPresentation.h" 14 | 15 | #define identifier @"identifier" 16 | #define longTitle @"I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title I am title " 17 | #define longMessage @"I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content I am content " 18 | 19 | @interface ViewController () 20 | 21 | @property (nonatomic, strong) NSArray *dataSource; 22 | 23 | @end 24 | 25 | @implementation ViewController 26 | 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | // Do any additional setup after loading the view, typically from a nib. 30 | 31 | self.title = @"JCAlertController"; 32 | 33 | self.dataSource = @[ 34 | @{@"Normal Style":@[@"only title",@"only content",@"title and content both",@"title words overflow",@"content words overflow"]}, 35 | @{@"Custom Style":@[@"change JCAlertTypeCustom"]}, 36 | @{@"Present Queue":@[@"JCAlertController LIFO", 37 | @"JCAlertController FIFO", 38 | @"UIAlertController LIFO", 39 | @"UIAlertController FIFO", 40 | @"UIAlertController default"]}, 41 | @{@"Custom ContentView":@[@"contentView",@"contentView and keyboard handle",@"contentView and attributed string"]}, 42 | @{@"FIFO View Hierarchy test":@[@"pop/dismiss self when alert dismissed"]}, 43 | @{@"LIFO View Hierarchy test":@[@"pop/dismiss self when alert dismissed", @"present another controller when first alert dismissed"]}]; 44 | 45 | [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:identifier]; 46 | [self.tableView reloadData]; 47 | 48 | // default is UIWindowLevelNormal 49 | [JCPresentController setOverlayWindowLevel:UIWindowLevelAlert + 1]; 50 | } 51 | 52 | #pragma mark - TableView delegate/datasource 53 | 54 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 55 | return self.dataSource.count; 56 | } 57 | 58 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 59 | NSDictionary *dict = self.dataSource[section]; 60 | NSArray *array = [dict.allValues firstObject]; 61 | return array.count; 62 | } 63 | 64 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 65 | NSDictionary *dict = self.dataSource[section]; 66 | return dict.allKeys.firstObject; 67 | } 68 | 69 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 70 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 71 | NSDictionary *dict = self.dataSource[indexPath.section]; 72 | NSArray *array = [dict.allValues firstObject]; 73 | cell.textLabel.text = array[indexPath.row]; 74 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 75 | return cell; 76 | } 77 | 78 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 79 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 80 | 81 | if (indexPath.section == 0) { 82 | if (indexPath.row == 0) { 83 | [self onlyTitle]; 84 | } else if (indexPath.row == 1) { 85 | [self onlyContent]; 86 | } else if (indexPath.row == 2) { 87 | [self titleAndContentBoth]; 88 | } else if (indexPath.row == 3) { 89 | [self titleWordsOverflow]; 90 | } else if (indexPath.row == 4) { 91 | [self contentWordsOverflow]; 92 | } 93 | } 94 | 95 | if (indexPath.section == 1) { 96 | [self customStyle]; 97 | } 98 | 99 | if (indexPath.section == 2) { 100 | if (indexPath.row == 0) { 101 | [self JCAlertControllerLIFO]; 102 | } else if (indexPath.row == 1) { 103 | [self JCAlertControllerFIFO]; 104 | } else if (indexPath.row == 2){ 105 | [self UIAlertControllerLIFO]; 106 | } else if (indexPath.row == 3) { 107 | [self UIAlertControllerFIFO]; 108 | } else { 109 | [self UIAlertControllerDefault]; 110 | } 111 | } 112 | 113 | if (indexPath.section == 3) { 114 | if (indexPath.row == 0) { 115 | [self customView]; 116 | } else if (indexPath.row == 1) { 117 | [self customViewAndHandleKeyboard]; 118 | } else { 119 | [self customViewAndAttributedString]; 120 | } 121 | } 122 | 123 | if (indexPath.section == 4) { 124 | if (indexPath.row == 0) { 125 | [self popOrDismissSelfWhenAlertDismissedFIFO]; 126 | } 127 | } 128 | 129 | if (indexPath.section == 5) { 130 | if (indexPath.row == 0) { 131 | [self popOrDismissSelfWhenAlertDismissedLIFO]; 132 | } else if (indexPath.row == 1) { 133 | [self presentOtherVCWhenLastAlertDismissed]; 134 | } 135 | } 136 | } 137 | 138 | 139 | #pragma mark - Methods 140 | 141 | - (void)onlyTitle { 142 | JCAlertController *alert = [JCAlertController alertWithTitle:@"I am title" message:nil]; 143 | [alert addButtonWithTitle:@"Cancel" type:JCButtonTypeCancel clicked:^{ 144 | NSLog(@"Cancel button clicked"); 145 | }]; 146 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:^{ 147 | NSLog(@"OK button clicked"); 148 | }]; 149 | [JCPresentController presentViewControllerLIFO:alert presentCompletion:^{ 150 | NSLog(@"present completion"); 151 | } dismissCompletion:^{ 152 | NSLog(@"dismiss completion"); 153 | }]; 154 | } 155 | 156 | - (void)onlyContent { 157 | JCAlertController *alert = [JCAlertController alertWithTitle:nil message:@"I am content"]; 158 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 159 | [JCPresentController presentViewControllerLIFO:alert presentCompletion:nil dismissCompletion:nil]; 160 | } 161 | 162 | - (void)titleAndContentBoth { 163 | JCAlertController *alert = [JCAlertController alertWithTitle:@"JCAlertController" message:@"Support custom Style.\nSupport custom View.\nSupport presented with LIFO."]; 164 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 165 | [JCPresentController presentViewControllerLIFO:alert presentCompletion:nil dismissCompletion:nil]; 166 | } 167 | 168 | - (void)titleWordsOverflow { 169 | JCAlertController *alert = [JCAlertController alertWithTitle:longTitle message:nil]; 170 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 171 | [JCPresentController presentViewControllerLIFO:alert presentCompletion:nil dismissCompletion:nil]; 172 | } 173 | 174 | - (void)contentWordsOverflow { 175 | JCAlertController *alert = [JCAlertController alertWithTitle:@"I am title" message:longMessage]; 176 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 177 | [JCPresentController presentViewControllerLIFO:alert presentCompletion:nil dismissCompletion:nil]; 178 | } 179 | 180 | - (void)customStyle { 181 | // See all properties in JCAlertStyle 182 | JCAlertStyle *style = [JCAlertStyle shareStyle]; 183 | 184 | style.background.blur = YES; 185 | style.background.alpha = 0.65; 186 | style.background.canDismiss = YES; 187 | 188 | style.alertView.cornerRadius = 4; 189 | 190 | style.title.backgroundColor = [UIColor colorWithRed:251/255.0 green:2/255.0 blue:19/255.0 alpha:1.0]; 191 | style.title.textColor = [UIColor whiteColor]; 192 | 193 | style.content.backgroundColor = [UIColor colorWithRed:251/255.0 green:2/255.0 blue:19/255.0 alpha:1.0]; 194 | style.content.textColor = [UIColor whiteColor]; 195 | style.content.insets = UIEdgeInsetsMake(20, 20, 40, 20); 196 | 197 | style.buttonNormal.textColor = [UIColor colorWithRed:248/255.0 green:59/255.0 blue:50/255.0 alpha:1.0]; 198 | style.buttonNormal.highlightTextColor = [style.buttonNormal.textColor hightlightedColor]; 199 | style.buttonNormal.backgroundColor = [UIColor whiteColor]; 200 | style.buttonNormal.highlightBackgroundColor = [UIColor whiteColor]; 201 | 202 | JCAlertController *alert = [JCAlertController alertWithTitle:@"I am title" message:@"I am content"]; 203 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 204 | [JCPresentController presentViewControllerLIFO:alert presentCompletion:nil dismissCompletion:nil]; 205 | } 206 | 207 | - (void)JCAlertControllerLIFO { 208 | // LIFO: alert3 >> alert2 >> alert1 209 | for (int i = 1; i<4; i++) { 210 | JCAlertController *alert = [JCAlertController alertWithTitle:[NSString stringWithFormat:@"alert%i", i] message:nil]; 211 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 212 | [JCPresentController presentViewControllerLIFO:alert presentCompletion:nil dismissCompletion:nil]; 213 | } 214 | } 215 | 216 | - (void)JCAlertControllerFIFO { 217 | // FIFO alert1 >> alert2 >> alert3 218 | for (int i = 1; i<4; i++) { 219 | JCAlertController *alert = [JCAlertController alertWithTitle:[NSString stringWithFormat:@"alert%i", i] message:nil]; 220 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 221 | [JCPresentController presentViewControllerFIFO:alert presentCompletion:nil dismissCompletion:nil]; 222 | } 223 | } 224 | 225 | - (void)UIAlertControllerLIFO { 226 | // LIFO: alert3 >> alert2 >> alert1 227 | for (int i = 1; i<4; i++) { 228 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"alert%i", i] message:nil preferredStyle:UIAlertControllerStyleAlert]; 229 | UIAlertAction *alertAction = [UIAlertAction actionWithTitle:@"ok" style:UIAlertActionStyleDefault handler:nil]; 230 | [alert addAction:alertAction]; 231 | [JCPresentController presentViewControllerLIFO:alert presentCompletion:nil dismissCompletion:nil]; 232 | } 233 | } 234 | 235 | - (void)UIAlertControllerFIFO { 236 | // FIFO: alert1 >> alert2 >> alert3 237 | for (int i = 1; i<4; i++) { 238 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"alert%i", i] message:nil preferredStyle:UIAlertControllerStyleAlert]; 239 | UIAlertAction *alertAction = [UIAlertAction actionWithTitle:@"ok" style:UIAlertActionStyleDefault handler:nil]; 240 | [alert addAction:alertAction]; 241 | [JCPresentController presentViewControllerFIFO:alert presentCompletion:nil dismissCompletion:nil]; 242 | } 243 | } 244 | 245 | - (void)UIAlertControllerDefault { 246 | // Only show one alert and log error msg. 247 | for (int i = 1; i<4; i++) { 248 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"alert%i", i] message:nil preferredStyle:UIAlertControllerStyleAlert]; 249 | UIAlertAction *alertAction = [UIAlertAction actionWithTitle:@"ok" style:UIAlertActionStyleDefault handler:nil]; 250 | [alert addAction:alertAction]; 251 | [self presentViewController:alert animated:YES completion:nil]; 252 | } 253 | } 254 | 255 | 256 | - (void)popOrDismissSelfWhenAlertDismissedFIFO { 257 | JCAlertController *alert = [JCAlertController alertWithTitle:@"pop/dismiss self in completion" message:nil]; 258 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 259 | __weak typeof(self) weakSelf = self; 260 | [JCPresentController presentViewControllerFIFO:alert presentCompletion:nil dismissCompletion:^(void){ 261 | if (weakSelf.navigationController) { 262 | [weakSelf.navigationController popViewControllerAnimated:YES]; 263 | } else { 264 | [weakSelf dismissViewControllerAnimated:YES completion:nil]; 265 | } 266 | }]; 267 | for (int i = 1; i<4; i++) { 268 | JCAlertController *alert = [JCAlertController alertWithTitle:[NSString stringWithFormat:@"alert%i", i] message:nil]; 269 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 270 | [JCPresentController presentViewControllerFIFO:alert presentCompletion:nil dismissCompletion:nil]; 271 | } 272 | } 273 | 274 | - (void)popOrDismissSelfWhenAlertDismissedLIFO { 275 | for (int i = 1; i<4; i++) { 276 | JCAlertController *alert = [JCAlertController alertWithTitle:[NSString stringWithFormat:@"alert%i", i] message:nil]; 277 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 278 | [JCPresentController presentViewControllerLIFO:alert presentCompletion:nil dismissCompletion:nil]; 279 | } 280 | JCAlertController *alert = [JCAlertController alertWithTitle:@"pop/dismiss self in completion" message:nil]; 281 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 282 | __weak typeof(self) weakSelf = self; 283 | [JCPresentController presentViewControllerLIFO:alert presentCompletion:nil dismissCompletion:^(void){ 284 | if (weakSelf.presentingViewController) { 285 | [weakSelf dismissViewControllerAnimated:YES completion:nil]; 286 | } else { 287 | [weakSelf.navigationController popViewControllerAnimated:YES]; 288 | } 289 | }]; 290 | } 291 | 292 | - (void)presentOtherVCWhenLastAlertDismissed { 293 | for (int i = 1; i<4; i++) { 294 | JCAlertController *alert = [JCAlertController alertWithTitle:[NSString stringWithFormat:@"alert%i", i] message:nil]; 295 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 296 | [JCPresentController presentViewControllerLIFO:alert presentCompletion:nil dismissCompletion:nil]; 297 | } 298 | JCAlertController *alert = [JCAlertController alertWithTitle:@"present a nav in completion" message:nil]; 299 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 300 | __weak typeof(self) weakSelf = self; 301 | [JCPresentController presentViewControllerLIFO:alert presentCompletion:nil dismissCompletion:^(void){ 302 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[NormalVCForPresentation new]]; 303 | [weakSelf presentViewController:nav animated:YES completion:nil]; 304 | }]; 305 | } 306 | 307 | #pragma mark - 308 | 309 | - (void)customView { 310 | // without title and button 311 | 312 | // setup a contentView 313 | CGFloat width = [JCAlertStyle shareStyle].alertView.width; 314 | UIImageView *contentView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, width, width * 0.623)]; 315 | contentView.image = [UIImage imageNamed:@"alert"]; 316 | contentView.userInteractionEnabled = YES; 317 | 318 | // pass the contentView 319 | JCAlertController *alert = [JCAlertController alertWithTitle:nil contentView:contentView]; 320 | [JCPresentController presentViewControllerLIFO:alert presentCompletion:nil dismissCompletion:nil]; 321 | 322 | // avoid retain circle 323 | __weak JCAlertController *weakAlert = alert; 324 | 325 | // add gesture to dismiss alert 326 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:[self selectorBlock:^(id weakSelf, id arg) { 327 | [weakAlert dismissViewControllerAnimated:YES completion:nil]; 328 | }]]; 329 | [contentView addGestureRecognizer:tap]; 330 | } 331 | 332 | - (void)customViewAndHandleKeyboard { 333 | // without title 334 | 335 | CGFloat width = [JCAlertStyle shareStyle].alertView.width; 336 | 337 | // setup contentView with a textField inside 338 | UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, width - 20, 26)]; 339 | textField.backgroundColor = [UIColor colorWithRed:241/255.0 green:241/255.0 blue:241/255.0 alpha:1.0]; 340 | textField.layer.cornerRadius = 2; 341 | textField.clipsToBounds = YES; 342 | textField.center = CGPointMake(width / 2, 30); 343 | textField.secureTextEntry = YES; 344 | textField.textAlignment = NSTextAlignmentCenter; 345 | [textField becomeFirstResponder]; 346 | 347 | UIView *contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, 60)]; 348 | contentView.backgroundColor = [UIColor whiteColor]; 349 | [contentView addSubview:textField]; 350 | 351 | // pass the contentView 352 | JCAlertController *alert = [JCAlertController alertWithTitle:@"Enter password please" contentView:contentView]; 353 | [alert addButtonWithTitle:@"Confirm" type:JCButtonTypeNormal clicked:^{ 354 | NSLog(@"You inputed:%@", textField.text); 355 | [textField resignFirstResponder]; 356 | }]; 357 | [JCPresentController presentViewControllerLIFO:alert presentCompletion:^{ 358 | [textField becomeFirstResponder]; 359 | } dismissCompletion:nil]; 360 | 361 | // avoid retain circle 362 | __weak typeof(JCAlertController *) weakalert = alert; 363 | 364 | // callback after keyboard shows 365 | [alert monitorKeyboardShowed:^(CGFloat alertHeight, CGFloat keyboardHeight) { 366 | [weakalert moveAlertViewToCenterY:alertHeight / 2 + 120 animated:YES]; 367 | }]; 368 | // callback after keyboard hides 369 | [alert monitorKeyboardHided:^{ 370 | [weakalert moveAlertViewToScreenCenterAnimated:YES]; 371 | }]; 372 | } 373 | 374 | - (void)customViewAndAttributedString { 375 | // without title 376 | CGFloat width = [JCAlertStyle shareStyle].alertView.width; 377 | UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, width, 100)]; 378 | label.backgroundColor = [UIColor whiteColor]; 379 | label.textAlignment = NSTextAlignmentCenter; 380 | NSMutableAttributedString *AttributedStr = [[NSMutableAttributedString alloc]initWithString:@"Hello"]; 381 | [AttributedStr addAttribute:NSForegroundColorAttributeName value:[UIColor orangeColor] range:NSMakeRange(0, 2)]; 382 | [AttributedStr addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(2, 3)]; 383 | label.attributedText = AttributedStr; 384 | 385 | JCAlertController *alert = [JCAlertController alertWithTitle:nil contentView:label]; 386 | [alert addButtonWithTitle:@"OK" type:JCButtonTypeNormal clicked:nil]; 387 | [JCPresentController presentViewControllerLIFO:alert presentCompletion:nil dismissCompletion:nil]; 388 | } 389 | 390 | @end 391 | -------------------------------------------------------------------------------- /JCAlertController/JCAlertController/AlertView/JCAlertView.m: -------------------------------------------------------------------------------- 1 | // 2 | // JCAlertController.m 3 | // JCAlertController 4 | // 5 | // Created by HJaycee on 2017/4/1. 6 | // Copyright © 2017年 HJaycee. All rights reserved. 7 | // 8 | 9 | #import "JCAlertView.h" 10 | #import "NSAttributedString+JCCalculateSize.h" 11 | #import "JCAlertButtonItem.h" 12 | #import "UIImage+JCColor2Image.h" 13 | 14 | @interface JCAlertView () 15 | 16 | @property (nonatomic) CGFloat buttonHeight; 17 | @property (nonatomic, weak) UIButton *leftBtn; 18 | @property (nonatomic, weak) UIButton *rightBtn; 19 | 20 | @end 21 | 22 | @implementation JCAlertView 23 | 24 | - (void)willMoveToSuperview:(UIView *)newSuperview { 25 | [super willMoveToSuperview:newSuperview]; 26 | 27 | self.backgroundColor = [UIColor clearColor]; 28 | 29 | JCAlertStyle *style = self.style; 30 | 31 | UIEdgeInsets titleInsets = style.title.insets; 32 | if (self.title && self.title.length > 0 && (!self.message || self.message.length == 0) && !self.contentView) { 33 | titleInsets = style.title.onlyTitleInsets; 34 | } 35 | 36 | UIEdgeInsets messageInsets = style.content.insets; 37 | if (self.message && self.message.length > 0 && (!self.title || self.title.length == 0)) { 38 | messageInsets = style.content.onlyMessageInsets; 39 | } 40 | 41 | // button height 42 | self.buttonHeight = self.buttonItems.count > 0 ? style.buttonNormal.height : 0; 43 | 44 | // cal title height 45 | CGFloat titleHeight = 0; 46 | CGSize titleSize = CGSizeZero; 47 | if (self.title.length > 0) { 48 | NSAttributedString *titleStr = [[NSAttributedString alloc] initWithString:self.title attributes:@{NSFontAttributeName:style.title.font}]; 49 | titleSize = [titleStr sizeWithMaxWidth:style.alertView.width - titleInsets.left - titleInsets.right]; 50 | titleHeight = titleSize.height + titleInsets.top + titleInsets.bottom; 51 | } 52 | 53 | // title one line height 54 | NSAttributedString *titleChar = [[NSAttributedString alloc] initWithString:@" " attributes:@{NSFontAttributeName:style.title.font}]; 55 | CGFloat titleCharHeight = [titleChar sizeWithMaxWidth:self.frame.size.width].height; 56 | 57 | // if has contentView 58 | if (self.contentView) { 59 | CGFloat totalHeight = titleHeight + self.contentView.frame.size.height + self.buttonHeight; 60 | CGFloat alertHeight = totalHeight > self.style.alertView.maxHeight ? self.style.alertView.maxHeight : totalHeight; 61 | self.frame = CGRectMake(0, 0, style.alertView.width, alertHeight); 62 | 63 | if (titleHeight > 0) { 64 | if (titleSize.height <= titleCharHeight) { // show in center 65 | UILabel *titleView = [[UILabel alloc] initWithFrame:CGRectIntegral(CGRectMake(titleInsets.left, titleInsets.top, style.alertView.width - titleInsets.left - titleInsets.right, titleCharHeight))]; 66 | titleView.text = self.title; 67 | titleView.font = style.title.font; 68 | titleView.textColor = style.title.textColor; 69 | titleView.backgroundColor = [UIColor clearColor]; 70 | titleView.textAlignment = style.title.textAlignment; 71 | 72 | UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, style.alertView.width, titleHeight)]; 73 | bgView.backgroundColor = style.title.backgroundColor; 74 | [bgView addSubview:titleView]; 75 | 76 | [self addSubview:bgView]; 77 | } else { // break line use textview 78 | UITextView *titleView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, style.alertView.width, titleHeight)]; 79 | titleView.textContainerInset = titleInsets; 80 | titleView.text = self.title; 81 | titleView.font = style.title.font; 82 | titleView.textColor = style.title.textColor; 83 | titleView.backgroundColor = style.title.backgroundColor; 84 | titleView.editable = NO; 85 | titleView.selectable = NO; 86 | titleView.scrollEnabled = YES; 87 | titleView.textAlignment = style.title.textAlignment; 88 | // because contentsize.height < frame.size.height 89 | if (titleView.frame.size.height < titleView.contentSize.height) { 90 | CGRect newF = titleView.frame; 91 | newF.size.height = titleView.contentSize.height; 92 | titleView.frame = newF; 93 | } 94 | titleView.scrollEnabled = NO; 95 | [self addSubview:titleView]; 96 | } 97 | } 98 | 99 | CGRect contentFrame = self.contentView.frame; 100 | contentFrame.origin.y = titleHeight; 101 | 102 | CGFloat maxContentHeight = self.style.alertView.maxHeight - titleHeight - self.buttonHeight; 103 | if (CGRectGetHeight(contentFrame) > maxContentHeight) { 104 | CGRect scrollFrame = contentFrame; 105 | scrollFrame.size.height = maxContentHeight; 106 | UIScrollView *contentScrollView = [[UIScrollView alloc] initWithFrame:scrollFrame]; 107 | contentScrollView.contentSize = contentFrame.size; 108 | contentScrollView.backgroundColor = self.style.alertView.backgroundColor; 109 | [contentScrollView addSubview:self.contentView]; 110 | [self addSubview:contentScrollView]; 111 | } else { 112 | self.contentView.frame = contentFrame; 113 | [self addSubview:self.contentView]; 114 | } 115 | 116 | [self setupButton]; 117 | 118 | if (titleHeight + self.buttonHeight > 0) { 119 | self.layer.cornerRadius = style.alertView.cornerRadius; 120 | if (self.layer.cornerRadius > 0) { 121 | self.clipsToBounds = YES; 122 | } 123 | } 124 | 125 | self.center = newSuperview.center; 126 | return; 127 | } 128 | 129 | // title height than max 130 | CGFloat maxUnstretchTitleHeight = style.alertView.maxHeight - self.buttonHeight; 131 | 132 | // cal content height 133 | CGFloat contentHeight = 0; 134 | CGSize contentSize = CGSizeZero; 135 | if (self.message.length > 0) { 136 | NSAttributedString *contentStr = [[NSAttributedString alloc] initWithString:self.message attributes:@{NSFontAttributeName:style.content.font}]; 137 | contentSize = [contentStr sizeWithMaxWidth:style.alertView.width - messageInsets.left - messageInsets.right]; 138 | contentHeight = contentSize.height + messageInsets.top + messageInsets.bottom; 139 | } 140 | 141 | // content one line height 142 | NSAttributedString *contentChar = [[NSAttributedString alloc] initWithString:@" " attributes:@{NSFontAttributeName:style.content.font}]; 143 | CGFloat contentCharHeight = [contentChar sizeWithMaxWidth:self.frame.size.width].height; 144 | 145 | // give alert frame 146 | if (titleHeight + contentHeight + self.buttonHeight > style.alertView.maxHeight) { 147 | self.frame = CGRectMake(0, 0, style.alertView.width, style.alertView.maxHeight); 148 | } else { 149 | self.frame = CGRectMake(0, 0, style.alertView.width, titleHeight + contentHeight + self.buttonHeight); 150 | } 151 | 152 | // layout 153 | if (titleHeight + contentHeight + self.buttonHeight < style.alertView.maxHeight) { // in max height 154 | if (titleHeight > 0) { 155 | if (titleSize.height <= titleCharHeight) { // show in center 156 | UILabel *titleView = [[UILabel alloc] initWithFrame:CGRectIntegral(CGRectMake(titleInsets.left, titleInsets.top, style.alertView.width - titleInsets.left - titleInsets.right, titleCharHeight))]; 157 | titleView.text = self.title; 158 | titleView.font = style.title.font; 159 | titleView.textColor = style.title.textColor; 160 | titleView.backgroundColor = [UIColor clearColor]; 161 | titleView.textAlignment = style.title.textAlignment; 162 | 163 | UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, style.alertView.width, titleHeight)]; 164 | bgView.backgroundColor = style.title.backgroundColor; 165 | [bgView addSubview:titleView]; 166 | 167 | [self addSubview:bgView]; 168 | } else { 169 | UITextView *titleView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, style.alertView.width, titleHeight)]; 170 | titleView.text = self.title; 171 | titleView.font = style.title.font; 172 | titleView.textContainerInset = titleInsets; 173 | titleView.textColor = style.title.textColor; 174 | titleView.backgroundColor = style.title.backgroundColor; 175 | titleView.editable = NO; 176 | titleView.selectable = NO; 177 | titleView.scrollEnabled = YES; 178 | titleView.textAlignment = style.title.textAlignment; 179 | // because contentsize.height < frame.size.height 180 | if (titleView.frame.size.height < titleView.contentSize.height) { 181 | CGRect newF = titleView.frame; 182 | newF.size.height = titleView.contentSize.height; 183 | titleView.frame = newF; 184 | } 185 | titleView.scrollEnabled = NO; 186 | [self addSubview:titleView]; 187 | } 188 | } 189 | 190 | if (contentHeight > 0) { 191 | if (contentSize.height <= contentCharHeight) { 192 | UILabel *contentView = [[UILabel alloc] initWithFrame:CGRectMake(messageInsets.left, messageInsets.top, style.alertView.width - messageInsets.left - messageInsets.right, contentCharHeight)]; 193 | contentView.text = self.message; 194 | contentView.font = style.content.font; 195 | contentView.textColor = style.content.textColor; 196 | contentView.backgroundColor = [UIColor clearColor]; 197 | contentView.textAlignment = style.content.textAlignment; 198 | 199 | UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(0, titleHeight, style.alertView.width, contentHeight)]; 200 | bgView.backgroundColor = style.content.backgroundColor; 201 | [bgView addSubview:contentView]; 202 | 203 | [self addSubview:bgView]; 204 | } else { 205 | UITextView *contentView = [[UITextView alloc] initWithFrame:CGRectMake(0, titleHeight, style.alertView.width, contentHeight)]; 206 | contentView.textContainerInset = messageInsets; 207 | contentView.text = self.message; 208 | contentView.font = style.content.font; 209 | contentView.textColor = style.content.textColor; 210 | contentView.backgroundColor = style.content.backgroundColor; 211 | contentView.editable = NO; 212 | contentView.selectable = NO; 213 | contentView.scrollEnabled = YES; 214 | contentView.textAlignment = style.content.textAlignment; 215 | // because contentsize.height < frame.size.height 216 | if (contentView.frame.size.height < contentView.contentSize.height) { 217 | CGRect newF = contentView.frame; 218 | newF.size.height = contentView.contentSize.height; 219 | contentView.frame = newF; 220 | } 221 | contentView.scrollEnabled = NO; 222 | [self addSubview:contentView]; 223 | } 224 | } 225 | 226 | [self setupButton]; 227 | } else { 228 | if (titleHeight > maxUnstretchTitleHeight) { // title scrollable 229 | UITextView *titleView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, style.alertView.width, maxUnstretchTitleHeight)]; 230 | titleView.textContainerInset = titleInsets; 231 | titleView.text = self.title; 232 | titleView.font = style.title.font; 233 | titleView.textColor = style.title.textColor; 234 | titleView.backgroundColor = style.title.backgroundColor; 235 | titleView.editable = NO; 236 | titleView.selectable = NO; 237 | titleView.textAlignment = style.title.textAlignment; 238 | [self addSubview:titleView]; 239 | 240 | [self setupButton]; 241 | } else { // content scrollable 242 | if (titleHeight > 0) { 243 | if (titleSize.height <= titleCharHeight) { // show in center 244 | UILabel *titleView = [[UILabel alloc] initWithFrame:CGRectIntegral(CGRectMake(titleInsets.left, titleInsets.top, style.alertView.width - titleInsets.left - titleInsets.right, titleCharHeight))]; 245 | titleView.text = self.title; 246 | titleView.font = style.title.font; 247 | titleView.textColor = style.title.textColor; 248 | titleView.backgroundColor = [UIColor clearColor]; 249 | titleView.textAlignment = style.title.textAlignment; 250 | 251 | UIView *bgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, style.alertView.width, titleHeight)]; 252 | bgView.backgroundColor = style.title.backgroundColor; 253 | [bgView addSubview:titleView]; 254 | 255 | [self addSubview:bgView]; 256 | } else { 257 | UITextView *titleView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, style.alertView.width, titleHeight)]; 258 | titleView.textContainerInset = titleInsets; 259 | titleView.text = self.title; 260 | titleView.font = style.title.font; 261 | titleView.textColor = style.title.textColor; 262 | titleView.backgroundColor = style.title.backgroundColor; 263 | titleView.editable = NO; 264 | titleView.selectable = NO; 265 | titleView.scrollEnabled = YES; 266 | titleView.textAlignment = style.title.textAlignment; 267 | // because contentsize.height < frame.size.height 268 | if (titleView.frame.size.height < titleView.contentSize.height) { 269 | CGRect newF = titleView.frame; 270 | newF.size.height = titleView.contentSize.height; 271 | titleView.frame = newF; 272 | } 273 | titleView.scrollEnabled = NO; 274 | [self addSubview:titleView]; 275 | } 276 | } 277 | 278 | UITextView *contentView = [[UITextView alloc] initWithFrame:CGRectMake(0, titleHeight, style.alertView.width, maxUnstretchTitleHeight - titleHeight)]; 279 | contentView.textContainerInset = messageInsets; 280 | contentView.text = self.message; 281 | contentView.font = style.content.font; 282 | contentView.textColor = style.content.textColor; 283 | contentView.backgroundColor = style.content.backgroundColor; 284 | contentView.editable = NO; 285 | contentView.selectable = NO; 286 | contentView.scrollEnabled = YES; 287 | contentView.textAlignment = style.content.textAlignment; 288 | [self addSubview:contentView]; 289 | 290 | [self setupButton]; 291 | } 292 | } 293 | 294 | self.layer.cornerRadius = style.alertView.cornerRadius; 295 | if (self.layer.cornerRadius > 0) { 296 | self.clipsToBounds = YES; 297 | } 298 | 299 | self.center = newSuperview.center; 300 | } 301 | 302 | - (void)setupButton { 303 | if (self.buttonHeight > 0) { 304 | JCAlertStyle *style = self.style;; 305 | if (self.buttonItems.count > 1) { 306 | JCAlertButtonItem *leftItem = self.buttonItems[0]; 307 | JCAlertStyleButton *styleButton = style.buttonNormal; 308 | if (leftItem.type == JCButtonTypeCancel) { 309 | styleButton = style.buttonCancel; 310 | } else if (leftItem.type == JCButtonTypeWarning) { 311 | styleButton = style.buttonWarning; 312 | } 313 | CGFloat alertHeight = (self.frame.size.height > self.style.alertView.maxHeight) ? self.style.alertView.maxHeight : self.frame.size.height; 314 | UIButton *leftBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, alertHeight - self.buttonHeight, style.alertView.width / 2, self.buttonHeight)]; 315 | leftBtn.userInteractionEnabled = NO; 316 | [leftBtn setTitle:leftItem.title forState:UIControlStateNormal]; 317 | [leftBtn setTitleColor:styleButton.textColor forState:UIControlStateNormal]; 318 | [leftBtn setTitleColor:styleButton.highlightTextColor forState:UIControlStateHighlighted]; 319 | [leftBtn setBackgroundImage:[UIImage createImageWithColor:styleButton.backgroundColor] forState:UIControlStateNormal]; 320 | [leftBtn setBackgroundImage:[UIImage createImageWithColor:styleButton.highlightBackgroundColor] forState:UIControlStateHighlighted]; 321 | leftBtn.titleLabel.font = styleButton.font; 322 | [self addSubview:leftBtn]; 323 | self.leftBtn = leftBtn; 324 | 325 | JCAlertButtonItem *rightItem = self.buttonItems[1]; 326 | styleButton = style.buttonNormal; 327 | if (rightItem.type == JCButtonTypeCancel) { 328 | styleButton = style.buttonCancel; 329 | } else if (rightItem.type == JCButtonTypeWarning) { 330 | styleButton = style.buttonWarning; 331 | } 332 | UIButton *rightBtn = [[UIButton alloc] initWithFrame:CGRectMake(style.alertView.width / 2, alertHeight - self.buttonHeight, style.alertView.width / 2, self.buttonHeight)]; 333 | rightBtn.userInteractionEnabled = NO; 334 | [rightBtn setTitle:rightItem.title forState:UIControlStateNormal]; 335 | [rightBtn setTitleColor:styleButton.textColor forState:UIControlStateNormal]; 336 | [rightBtn setTitleColor:styleButton.highlightTextColor forState:UIControlStateHighlighted]; 337 | [rightBtn setBackgroundImage:[UIImage createImageWithColor:styleButton.backgroundColor] forState:UIControlStateNormal]; 338 | [rightBtn setBackgroundImage:[UIImage createImageWithColor:styleButton.highlightBackgroundColor] forState:UIControlStateHighlighted]; 339 | rightBtn.titleLabel.font = styleButton.font; 340 | [self addSubview:rightBtn]; 341 | self.rightBtn = rightBtn; 342 | 343 | UIView *separator = [[UIView alloc] initWithFrame:CGRectMake(0, self.frame.size.height - self.buttonHeight, style.alertView.width, style.separator.width)]; 344 | separator.backgroundColor = style.separator.color; 345 | [self addSubview:separator]; 346 | 347 | UIView *separator1 = [[UIView alloc] initWithFrame:CGRectMake(style.alertView.width / 2, self.frame.size.height - self.buttonHeight, style.separator.width, styleButton.height)]; 348 | separator1.backgroundColor = style.separator.color; 349 | [self addSubview:separator1]; 350 | } else { 351 | JCAlertButtonItem *item = self.buttonItems[0]; 352 | JCAlertStyleButton *styleButton = style.buttonNormal; 353 | if (item.type == JCButtonTypeCancel) { 354 | styleButton = style.buttonCancel; 355 | } else if (item.type == JCButtonTypeWarning) { 356 | styleButton = style.buttonWarning; 357 | } 358 | CGFloat alertHeight = (self.frame.size.height > self.style.alertView.maxHeight) ? self.style.alertView.maxHeight : self.frame.size.height; 359 | UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, alertHeight - self.buttonHeight, style.alertView.width, self.buttonHeight)]; 360 | btn.userInteractionEnabled = NO; 361 | [btn setTitle:item.title forState:UIControlStateNormal]; 362 | [btn setTitleColor:styleButton.textColor forState:UIControlStateNormal]; 363 | [btn setTitleColor:styleButton.highlightTextColor forState:UIControlStateHighlighted]; 364 | [btn setBackgroundImage:[UIImage createImageWithColor:styleButton.backgroundColor] forState:UIControlStateNormal]; 365 | [btn setBackgroundImage:[UIImage createImageWithColor:styleButton.highlightBackgroundColor] forState:UIControlStateHighlighted]; 366 | btn.titleLabel.font = styleButton.font; 367 | [self addSubview:btn]; 368 | self.leftBtn = btn; 369 | 370 | UIView *separator = [[UIView alloc] initWithFrame:CGRectMake(0, self.frame.size.height - self.buttonHeight, style.alertView.width, style.separator.width)]; 371 | separator.backgroundColor = style.separator.color; 372 | [self addSubview:separator]; 373 | } 374 | } 375 | } 376 | 377 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 378 | UITouch *touch = [[touches allObjects] lastObject]; 379 | CGPoint originPoint = [touch locationInView:self]; 380 | 381 | [self handleTouch:originPoint insideLeft:^{ 382 | self.leftBtn.highlighted = YES; 383 | self.rightBtn.highlighted = NO; 384 | } insideRight:^{ 385 | self.rightBtn.highlighted = YES; 386 | self.leftBtn.highlighted = NO; 387 | } neither:^{ 388 | self.rightBtn.highlighted = NO; 389 | self.leftBtn.highlighted = NO; 390 | }]; 391 | } 392 | 393 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 394 | UITouch *touch = [[touches allObjects] lastObject]; 395 | CGPoint originPoint = [touch locationInView:self]; 396 | 397 | [self handleTouch:originPoint insideLeft:^{ 398 | [self leftBtnClick]; 399 | } insideRight:^{ 400 | [self rightBtnClick]; 401 | } neither:nil]; 402 | } 403 | 404 | - (void)handleTouch:(CGPoint)originPoint insideLeft:(void(^)(void))insideLeft insideRight:(void(^)(void))insideRight neither:(void(^)(void))neither { 405 | CGPoint point = [self convertPoint:originPoint toView:self.leftBtn]; 406 | if (point.x > 0 && point.y > 0 && point.x <= self.leftBtn.frame.size.width && point.y <= self.leftBtn.frame.size.height) { 407 | insideLeft(); 408 | } else { 409 | point = [self convertPoint:originPoint toView:self.rightBtn]; 410 | if (point.x > 0 && point.y > 0 && point.x <= self.rightBtn.frame.size.width && point.y <= self.rightBtn.frame.size.height) { 411 | insideRight(); 412 | } else { 413 | if (neither) { 414 | neither(); 415 | } 416 | } 417 | } 418 | } 419 | 420 | - (void)leftBtnClick { 421 | JCAlertButtonItem *item = self.buttonItems[0]; 422 | [self notifyDelegateWithClicked:item.clicked]; 423 | } 424 | 425 | - (void)rightBtnClick { 426 | JCAlertButtonItem *item = self.buttonItems[1]; 427 | [self notifyDelegateWithClicked:item.clicked]; 428 | } 429 | 430 | - (void)notifyDelegateWithClicked:(void(^)(void))clicked { 431 | if ([self.delegate respondsToSelector:@selector(alertButtonClicked:)]) { 432 | [self.delegate alertButtonClicked:clicked]; 433 | } 434 | } 435 | 436 | @end 437 | -------------------------------------------------------------------------------- /JCAlertController.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0306AD681ECC6032008705B4 /* NSObject+BlockSEL.m in Sources */ = {isa = PBXBuildFile; fileRef = 0306AD671ECC6032008705B4 /* NSObject+BlockSEL.m */; }; 11 | 030C7A971E9CF3C200B822C1 /* JCAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = 030C7A711E9CF3C200B822C1 /* JCAlertView.m */; }; 12 | 030C7A981E9CF3C200B822C1 /* JCAlertButtonItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 030C7A741E9CF3C200B822C1 /* JCAlertButtonItem.m */; }; 13 | 030C7A991E9CF3C200B822C1 /* NSAttributedString+JCCalculateSize.m in Sources */ = {isa = PBXBuildFile; fileRef = 030C7A771E9CF3C200B822C1 /* NSAttributedString+JCCalculateSize.m */; }; 14 | 030C7A9A1E9CF3C200B822C1 /* UIColor+JCHightlightedColor.m in Sources */ = {isa = PBXBuildFile; fileRef = 030C7A791E9CF3C200B822C1 /* UIColor+JCHightlightedColor.m */; }; 15 | 030C7A9B1E9CF3C200B822C1 /* UIImage+JCColor2Image.m in Sources */ = {isa = PBXBuildFile; fileRef = 030C7A7B1E9CF3C200B822C1 /* UIImage+JCColor2Image.m */; }; 16 | 030C7A9D1E9CF3C200B822C1 /* UIWindow+JCBlur.m in Sources */ = {isa = PBXBuildFile; fileRef = 030C7A7F1E9CF3C200B822C1 /* UIWindow+JCBlur.m */; }; 17 | 030C7A9E1E9CF3C200B822C1 /* JCAlertController.m in Sources */ = {isa = PBXBuildFile; fileRef = 030C7A811E9CF3C200B822C1 /* JCAlertController.m */; }; 18 | 030C7A9F1E9CF3C200B822C1 /* JCAlertStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 030C7A841E9CF3C200B822C1 /* JCAlertStyle.m */; }; 19 | 034A70C520A4195F007A61D6 /* JCPresentController.m in Sources */ = {isa = PBXBuildFile; fileRef = 034A70C220A4195F007A61D6 /* JCPresentController.m */; }; 20 | 034A70C620A4195F007A61D6 /* UIViewController+JCPresentQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 034A70C320A4195F007A61D6 /* UIViewController+JCPresentQueue.m */; }; 21 | 03A99E141E98066B009BC03D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 03A99E131E98066B009BC03D /* main.m */; }; 22 | 03A99E171E98066B009BC03D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 03A99E161E98066B009BC03D /* AppDelegate.m */; }; 23 | 03A99E1A1E98066B009BC03D /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03A99E191E98066B009BC03D /* ViewController.m */; }; 24 | 03A99E1F1E98066B009BC03D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 03A99E1E1E98066B009BC03D /* Assets.xcassets */; }; 25 | 03A99E221E98066B009BC03D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 03A99E201E98066B009BC03D /* LaunchScreen.storyboard */; }; 26 | 03A99E2D1E98066B009BC03D /* JCAlertControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 03A99E2C1E98066B009BC03D /* JCAlertControllerTests.m */; }; 27 | 03A99E381E98066B009BC03D /* JCAlertControllerUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 03A99E371E98066B009BC03D /* JCAlertControllerUITests.m */; }; 28 | F872B58C206CCFAF003456A2 /* RootVC.m in Sources */ = {isa = PBXBuildFile; fileRef = F872B58B206CCFAF003456A2 /* RootVC.m */; }; 29 | F872B595206E3F92003456A2 /* NormalVCForPresentation.m in Sources */ = {isa = PBXBuildFile; fileRef = F872B594206E3F92003456A2 /* NormalVCForPresentation.m */; }; 30 | /* End PBXBuildFile section */ 31 | 32 | /* Begin PBXContainerItemProxy section */ 33 | 03A99E291E98066B009BC03D /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = 03A99E071E98066B009BC03D /* Project object */; 36 | proxyType = 1; 37 | remoteGlobalIDString = 03A99E0E1E98066B009BC03D; 38 | remoteInfo = JCAlertController; 39 | }; 40 | 03A99E341E98066B009BC03D /* PBXContainerItemProxy */ = { 41 | isa = PBXContainerItemProxy; 42 | containerPortal = 03A99E071E98066B009BC03D /* Project object */; 43 | proxyType = 1; 44 | remoteGlobalIDString = 03A99E0E1E98066B009BC03D; 45 | remoteInfo = JCAlertController; 46 | }; 47 | /* End PBXContainerItemProxy section */ 48 | 49 | /* Begin PBXFileReference section */ 50 | 0306AD661ECC6032008705B4 /* NSObject+BlockSEL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+BlockSEL.h"; sourceTree = ""; }; 51 | 0306AD671ECC6032008705B4 /* NSObject+BlockSEL.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+BlockSEL.m"; sourceTree = ""; }; 52 | 030C7A701E9CF3C200B822C1 /* JCAlertView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCAlertView.h; sourceTree = ""; }; 53 | 030C7A711E9CF3C200B822C1 /* JCAlertView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCAlertView.m; sourceTree = ""; }; 54 | 030C7A731E9CF3C200B822C1 /* JCAlertButtonItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCAlertButtonItem.h; sourceTree = ""; }; 55 | 030C7A741E9CF3C200B822C1 /* JCAlertButtonItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCAlertButtonItem.m; sourceTree = ""; }; 56 | 030C7A761E9CF3C200B822C1 /* NSAttributedString+JCCalculateSize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSAttributedString+JCCalculateSize.h"; sourceTree = ""; }; 57 | 030C7A771E9CF3C200B822C1 /* NSAttributedString+JCCalculateSize.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSAttributedString+JCCalculateSize.m"; sourceTree = ""; }; 58 | 030C7A781E9CF3C200B822C1 /* UIColor+JCHightlightedColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIColor+JCHightlightedColor.h"; sourceTree = ""; }; 59 | 030C7A791E9CF3C200B822C1 /* UIColor+JCHightlightedColor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIColor+JCHightlightedColor.m"; sourceTree = ""; }; 60 | 030C7A7A1E9CF3C200B822C1 /* UIImage+JCColor2Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+JCColor2Image.h"; sourceTree = ""; }; 61 | 030C7A7B1E9CF3C200B822C1 /* UIImage+JCColor2Image.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+JCColor2Image.m"; sourceTree = ""; }; 62 | 030C7A7E1E9CF3C200B822C1 /* UIWindow+JCBlur.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIWindow+JCBlur.h"; sourceTree = ""; }; 63 | 030C7A7F1E9CF3C200B822C1 /* UIWindow+JCBlur.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIWindow+JCBlur.m"; sourceTree = ""; }; 64 | 030C7A801E9CF3C200B822C1 /* JCAlertController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCAlertController.h; sourceTree = ""; }; 65 | 030C7A811E9CF3C200B822C1 /* JCAlertController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCAlertController.m; sourceTree = ""; }; 66 | 030C7A831E9CF3C200B822C1 /* JCAlertStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCAlertStyle.h; sourceTree = ""; }; 67 | 030C7A841E9CF3C200B822C1 /* JCAlertStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCAlertStyle.m; sourceTree = ""; }; 68 | 034A70C120A4195F007A61D6 /* UIViewController+JCPresentQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+JCPresentQueue.h"; sourceTree = ""; }; 69 | 034A70C220A4195F007A61D6 /* JCPresentController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JCPresentController.m; sourceTree = ""; }; 70 | 034A70C320A4195F007A61D6 /* UIViewController+JCPresentQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+JCPresentQueue.m"; sourceTree = ""; }; 71 | 034A70C420A4195F007A61D6 /* JCPresentController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JCPresentController.h; sourceTree = ""; }; 72 | 03A99E0F1E98066B009BC03D /* JCAlertController.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JCAlertController.app; sourceTree = BUILT_PRODUCTS_DIR; }; 73 | 03A99E131E98066B009BC03D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 74 | 03A99E151E98066B009BC03D /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 75 | 03A99E161E98066B009BC03D /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 76 | 03A99E181E98066B009BC03D /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 77 | 03A99E191E98066B009BC03D /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 78 | 03A99E1E1E98066B009BC03D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 79 | 03A99E211E98066B009BC03D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 80 | 03A99E231E98066B009BC03D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 81 | 03A99E281E98066B009BC03D /* JCAlertControllerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JCAlertControllerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 82 | 03A99E2C1E98066B009BC03D /* JCAlertControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JCAlertControllerTests.m; sourceTree = ""; }; 83 | 03A99E2E1E98066B009BC03D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 84 | 03A99E331E98066B009BC03D /* JCAlertControllerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JCAlertControllerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 85 | 03A99E371E98066B009BC03D /* JCAlertControllerUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JCAlertControllerUITests.m; sourceTree = ""; }; 86 | 03A99E391E98066B009BC03D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 87 | F872B58A206CCFAF003456A2 /* RootVC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RootVC.h; sourceTree = ""; }; 88 | F872B58B206CCFAF003456A2 /* RootVC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RootVC.m; sourceTree = ""; }; 89 | F872B593206E3F92003456A2 /* NormalVCForPresentation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NormalVCForPresentation.h; sourceTree = ""; }; 90 | F872B594206E3F92003456A2 /* NormalVCForPresentation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NormalVCForPresentation.m; sourceTree = ""; }; 91 | /* End PBXFileReference section */ 92 | 93 | /* Begin PBXFrameworksBuildPhase section */ 94 | 03A99E0C1E98066B009BC03D /* Frameworks */ = { 95 | isa = PBXFrameworksBuildPhase; 96 | buildActionMask = 2147483647; 97 | files = ( 98 | ); 99 | runOnlyForDeploymentPostprocessing = 0; 100 | }; 101 | 03A99E251E98066B009BC03D /* Frameworks */ = { 102 | isa = PBXFrameworksBuildPhase; 103 | buildActionMask = 2147483647; 104 | files = ( 105 | ); 106 | runOnlyForDeploymentPostprocessing = 0; 107 | }; 108 | 03A99E301E98066B009BC03D /* Frameworks */ = { 109 | isa = PBXFrameworksBuildPhase; 110 | buildActionMask = 2147483647; 111 | files = ( 112 | ); 113 | runOnlyForDeploymentPostprocessing = 0; 114 | }; 115 | /* End PBXFrameworksBuildPhase section */ 116 | 117 | /* Begin PBXGroup section */ 118 | 030C7A6E1E9CF3C200B822C1 /* JCAlertController */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 030C7A801E9CF3C200B822C1 /* JCAlertController.h */, 122 | 030C7A811E9CF3C200B822C1 /* JCAlertController.m */, 123 | 034A70C020A4195F007A61D6 /* JCPresentQueue */, 124 | 030C7A6F1E9CF3C200B822C1 /* AlertView */, 125 | 030C7A721E9CF3C200B822C1 /* ButtonItem */, 126 | 030C7A751E9CF3C200B822C1 /* Category */, 127 | 030C7A821E9CF3C200B822C1 /* Style */, 128 | ); 129 | path = JCAlertController; 130 | sourceTree = ""; 131 | }; 132 | 030C7A6F1E9CF3C200B822C1 /* AlertView */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 030C7A701E9CF3C200B822C1 /* JCAlertView.h */, 136 | 030C7A711E9CF3C200B822C1 /* JCAlertView.m */, 137 | ); 138 | path = AlertView; 139 | sourceTree = ""; 140 | }; 141 | 030C7A721E9CF3C200B822C1 /* ButtonItem */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 030C7A731E9CF3C200B822C1 /* JCAlertButtonItem.h */, 145 | 030C7A741E9CF3C200B822C1 /* JCAlertButtonItem.m */, 146 | ); 147 | path = ButtonItem; 148 | sourceTree = ""; 149 | }; 150 | 030C7A751E9CF3C200B822C1 /* Category */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 030C7A761E9CF3C200B822C1 /* NSAttributedString+JCCalculateSize.h */, 154 | 030C7A771E9CF3C200B822C1 /* NSAttributedString+JCCalculateSize.m */, 155 | 030C7A781E9CF3C200B822C1 /* UIColor+JCHightlightedColor.h */, 156 | 030C7A791E9CF3C200B822C1 /* UIColor+JCHightlightedColor.m */, 157 | 030C7A7A1E9CF3C200B822C1 /* UIImage+JCColor2Image.h */, 158 | 030C7A7B1E9CF3C200B822C1 /* UIImage+JCColor2Image.m */, 159 | 030C7A7E1E9CF3C200B822C1 /* UIWindow+JCBlur.h */, 160 | 030C7A7F1E9CF3C200B822C1 /* UIWindow+JCBlur.m */, 161 | ); 162 | path = Category; 163 | sourceTree = ""; 164 | }; 165 | 030C7A821E9CF3C200B822C1 /* Style */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | 030C7A831E9CF3C200B822C1 /* JCAlertStyle.h */, 169 | 030C7A841E9CF3C200B822C1 /* JCAlertStyle.m */, 170 | ); 171 | path = Style; 172 | sourceTree = ""; 173 | }; 174 | 034A70C020A4195F007A61D6 /* JCPresentQueue */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | 034A70C420A4195F007A61D6 /* JCPresentController.h */, 178 | 034A70C220A4195F007A61D6 /* JCPresentController.m */, 179 | 034A70C120A4195F007A61D6 /* UIViewController+JCPresentQueue.h */, 180 | 034A70C320A4195F007A61D6 /* UIViewController+JCPresentQueue.m */, 181 | ); 182 | path = JCPresentQueue; 183 | sourceTree = ""; 184 | }; 185 | 03A99E061E98066B009BC03D = { 186 | isa = PBXGroup; 187 | children = ( 188 | 03A99E111E98066B009BC03D /* JCAlertController */, 189 | 03A99E2B1E98066B009BC03D /* JCAlertControllerTests */, 190 | 03A99E361E98066B009BC03D /* JCAlertControllerUITests */, 191 | 03A99E101E98066B009BC03D /* Products */, 192 | ); 193 | sourceTree = ""; 194 | }; 195 | 03A99E101E98066B009BC03D /* Products */ = { 196 | isa = PBXGroup; 197 | children = ( 198 | 03A99E0F1E98066B009BC03D /* JCAlertController.app */, 199 | 03A99E281E98066B009BC03D /* JCAlertControllerTests.xctest */, 200 | 03A99E331E98066B009BC03D /* JCAlertControllerUITests.xctest */, 201 | ); 202 | name = Products; 203 | sourceTree = ""; 204 | }; 205 | 03A99E111E98066B009BC03D /* JCAlertController */ = { 206 | isa = PBXGroup; 207 | children = ( 208 | 030C7A6E1E9CF3C200B822C1 /* JCAlertController */, 209 | 03A99E151E98066B009BC03D /* AppDelegate.h */, 210 | 03A99E161E98066B009BC03D /* AppDelegate.m */, 211 | 0306AD661ECC6032008705B4 /* NSObject+BlockSEL.h */, 212 | 0306AD671ECC6032008705B4 /* NSObject+BlockSEL.m */, 213 | F872B58A206CCFAF003456A2 /* RootVC.h */, 214 | F872B58B206CCFAF003456A2 /* RootVC.m */, 215 | 03A99E181E98066B009BC03D /* ViewController.h */, 216 | 03A99E191E98066B009BC03D /* ViewController.m */, 217 | F872B593206E3F92003456A2 /* NormalVCForPresentation.h */, 218 | F872B594206E3F92003456A2 /* NormalVCForPresentation.m */, 219 | 03A99E1E1E98066B009BC03D /* Assets.xcassets */, 220 | 03A99E201E98066B009BC03D /* LaunchScreen.storyboard */, 221 | 03A99E231E98066B009BC03D /* Info.plist */, 222 | 03A99E121E98066B009BC03D /* Supporting Files */, 223 | ); 224 | path = JCAlertController; 225 | sourceTree = ""; 226 | }; 227 | 03A99E121E98066B009BC03D /* Supporting Files */ = { 228 | isa = PBXGroup; 229 | children = ( 230 | 03A99E131E98066B009BC03D /* main.m */, 231 | ); 232 | name = "Supporting Files"; 233 | sourceTree = ""; 234 | }; 235 | 03A99E2B1E98066B009BC03D /* JCAlertControllerTests */ = { 236 | isa = PBXGroup; 237 | children = ( 238 | 03A99E2C1E98066B009BC03D /* JCAlertControllerTests.m */, 239 | 03A99E2E1E98066B009BC03D /* Info.plist */, 240 | ); 241 | path = JCAlertControllerTests; 242 | sourceTree = ""; 243 | }; 244 | 03A99E361E98066B009BC03D /* JCAlertControllerUITests */ = { 245 | isa = PBXGroup; 246 | children = ( 247 | 03A99E371E98066B009BC03D /* JCAlertControllerUITests.m */, 248 | 03A99E391E98066B009BC03D /* Info.plist */, 249 | ); 250 | path = JCAlertControllerUITests; 251 | sourceTree = ""; 252 | }; 253 | /* End PBXGroup section */ 254 | 255 | /* Begin PBXNativeTarget section */ 256 | 03A99E0E1E98066B009BC03D /* JCAlertController */ = { 257 | isa = PBXNativeTarget; 258 | buildConfigurationList = 03A99E3C1E98066B009BC03D /* Build configuration list for PBXNativeTarget "JCAlertController" */; 259 | buildPhases = ( 260 | 03A99E0B1E98066B009BC03D /* Sources */, 261 | 03A99E0C1E98066B009BC03D /* Frameworks */, 262 | 03A99E0D1E98066B009BC03D /* Resources */, 263 | ); 264 | buildRules = ( 265 | ); 266 | dependencies = ( 267 | ); 268 | name = JCAlertController; 269 | productName = JCAlertController; 270 | productReference = 03A99E0F1E98066B009BC03D /* JCAlertController.app */; 271 | productType = "com.apple.product-type.application"; 272 | }; 273 | 03A99E271E98066B009BC03D /* JCAlertControllerTests */ = { 274 | isa = PBXNativeTarget; 275 | buildConfigurationList = 03A99E3F1E98066B009BC03D /* Build configuration list for PBXNativeTarget "JCAlertControllerTests" */; 276 | buildPhases = ( 277 | 03A99E241E98066B009BC03D /* Sources */, 278 | 03A99E251E98066B009BC03D /* Frameworks */, 279 | 03A99E261E98066B009BC03D /* Resources */, 280 | ); 281 | buildRules = ( 282 | ); 283 | dependencies = ( 284 | 03A99E2A1E98066B009BC03D /* PBXTargetDependency */, 285 | ); 286 | name = JCAlertControllerTests; 287 | productName = JCAlertControllerTests; 288 | productReference = 03A99E281E98066B009BC03D /* JCAlertControllerTests.xctest */; 289 | productType = "com.apple.product-type.bundle.unit-test"; 290 | }; 291 | 03A99E321E98066B009BC03D /* JCAlertControllerUITests */ = { 292 | isa = PBXNativeTarget; 293 | buildConfigurationList = 03A99E421E98066B009BC03D /* Build configuration list for PBXNativeTarget "JCAlertControllerUITests" */; 294 | buildPhases = ( 295 | 03A99E2F1E98066B009BC03D /* Sources */, 296 | 03A99E301E98066B009BC03D /* Frameworks */, 297 | 03A99E311E98066B009BC03D /* Resources */, 298 | ); 299 | buildRules = ( 300 | ); 301 | dependencies = ( 302 | 03A99E351E98066B009BC03D /* PBXTargetDependency */, 303 | ); 304 | name = JCAlertControllerUITests; 305 | productName = JCAlertControllerUITests; 306 | productReference = 03A99E331E98066B009BC03D /* JCAlertControllerUITests.xctest */; 307 | productType = "com.apple.product-type.bundle.ui-testing"; 308 | }; 309 | /* End PBXNativeTarget section */ 310 | 311 | /* Begin PBXProject section */ 312 | 03A99E071E98066B009BC03D /* Project object */ = { 313 | isa = PBXProject; 314 | attributes = { 315 | LastUpgradeCheck = 0820; 316 | ORGANIZATIONNAME = HJaycee; 317 | TargetAttributes = { 318 | 03A99E0E1E98066B009BC03D = { 319 | CreatedOnToolsVersion = 8.2.1; 320 | DevelopmentTeam = 7L64JRM966; 321 | ProvisioningStyle = Automatic; 322 | }; 323 | 03A99E271E98066B009BC03D = { 324 | CreatedOnToolsVersion = 8.2.1; 325 | ProvisioningStyle = Automatic; 326 | TestTargetID = 03A99E0E1E98066B009BC03D; 327 | }; 328 | 03A99E321E98066B009BC03D = { 329 | CreatedOnToolsVersion = 8.2.1; 330 | ProvisioningStyle = Automatic; 331 | TestTargetID = 03A99E0E1E98066B009BC03D; 332 | }; 333 | }; 334 | }; 335 | buildConfigurationList = 03A99E0A1E98066B009BC03D /* Build configuration list for PBXProject "JCAlertController" */; 336 | compatibilityVersion = "Xcode 3.2"; 337 | developmentRegion = English; 338 | hasScannedForEncodings = 0; 339 | knownRegions = ( 340 | en, 341 | Base, 342 | ); 343 | mainGroup = 03A99E061E98066B009BC03D; 344 | productRefGroup = 03A99E101E98066B009BC03D /* Products */; 345 | projectDirPath = ""; 346 | projectRoot = ""; 347 | targets = ( 348 | 03A99E0E1E98066B009BC03D /* JCAlertController */, 349 | 03A99E271E98066B009BC03D /* JCAlertControllerTests */, 350 | 03A99E321E98066B009BC03D /* JCAlertControllerUITests */, 351 | ); 352 | }; 353 | /* End PBXProject section */ 354 | 355 | /* Begin PBXResourcesBuildPhase section */ 356 | 03A99E0D1E98066B009BC03D /* Resources */ = { 357 | isa = PBXResourcesBuildPhase; 358 | buildActionMask = 2147483647; 359 | files = ( 360 | 03A99E221E98066B009BC03D /* LaunchScreen.storyboard in Resources */, 361 | 03A99E1F1E98066B009BC03D /* Assets.xcassets in Resources */, 362 | ); 363 | runOnlyForDeploymentPostprocessing = 0; 364 | }; 365 | 03A99E261E98066B009BC03D /* Resources */ = { 366 | isa = PBXResourcesBuildPhase; 367 | buildActionMask = 2147483647; 368 | files = ( 369 | ); 370 | runOnlyForDeploymentPostprocessing = 0; 371 | }; 372 | 03A99E311E98066B009BC03D /* Resources */ = { 373 | isa = PBXResourcesBuildPhase; 374 | buildActionMask = 2147483647; 375 | files = ( 376 | ); 377 | runOnlyForDeploymentPostprocessing = 0; 378 | }; 379 | /* End PBXResourcesBuildPhase section */ 380 | 381 | /* Begin PBXSourcesBuildPhase section */ 382 | 03A99E0B1E98066B009BC03D /* Sources */ = { 383 | isa = PBXSourcesBuildPhase; 384 | buildActionMask = 2147483647; 385 | files = ( 386 | 030C7A971E9CF3C200B822C1 /* JCAlertView.m in Sources */, 387 | 030C7A9E1E9CF3C200B822C1 /* JCAlertController.m in Sources */, 388 | 03A99E1A1E98066B009BC03D /* ViewController.m in Sources */, 389 | 0306AD681ECC6032008705B4 /* NSObject+BlockSEL.m in Sources */, 390 | 030C7A9F1E9CF3C200B822C1 /* JCAlertStyle.m in Sources */, 391 | 034A70C620A4195F007A61D6 /* UIViewController+JCPresentQueue.m in Sources */, 392 | 030C7A991E9CF3C200B822C1 /* NSAttributedString+JCCalculateSize.m in Sources */, 393 | 030C7A981E9CF3C200B822C1 /* JCAlertButtonItem.m in Sources */, 394 | 03A99E171E98066B009BC03D /* AppDelegate.m in Sources */, 395 | 03A99E141E98066B009BC03D /* main.m in Sources */, 396 | F872B58C206CCFAF003456A2 /* RootVC.m in Sources */, 397 | 030C7A9A1E9CF3C200B822C1 /* UIColor+JCHightlightedColor.m in Sources */, 398 | 030C7A9B1E9CF3C200B822C1 /* UIImage+JCColor2Image.m in Sources */, 399 | 034A70C520A4195F007A61D6 /* JCPresentController.m in Sources */, 400 | F872B595206E3F92003456A2 /* NormalVCForPresentation.m in Sources */, 401 | 030C7A9D1E9CF3C200B822C1 /* UIWindow+JCBlur.m in Sources */, 402 | ); 403 | runOnlyForDeploymentPostprocessing = 0; 404 | }; 405 | 03A99E241E98066B009BC03D /* Sources */ = { 406 | isa = PBXSourcesBuildPhase; 407 | buildActionMask = 2147483647; 408 | files = ( 409 | 03A99E2D1E98066B009BC03D /* JCAlertControllerTests.m in Sources */, 410 | ); 411 | runOnlyForDeploymentPostprocessing = 0; 412 | }; 413 | 03A99E2F1E98066B009BC03D /* Sources */ = { 414 | isa = PBXSourcesBuildPhase; 415 | buildActionMask = 2147483647; 416 | files = ( 417 | 03A99E381E98066B009BC03D /* JCAlertControllerUITests.m in Sources */, 418 | ); 419 | runOnlyForDeploymentPostprocessing = 0; 420 | }; 421 | /* End PBXSourcesBuildPhase section */ 422 | 423 | /* Begin PBXTargetDependency section */ 424 | 03A99E2A1E98066B009BC03D /* PBXTargetDependency */ = { 425 | isa = PBXTargetDependency; 426 | target = 03A99E0E1E98066B009BC03D /* JCAlertController */; 427 | targetProxy = 03A99E291E98066B009BC03D /* PBXContainerItemProxy */; 428 | }; 429 | 03A99E351E98066B009BC03D /* PBXTargetDependency */ = { 430 | isa = PBXTargetDependency; 431 | target = 03A99E0E1E98066B009BC03D /* JCAlertController */; 432 | targetProxy = 03A99E341E98066B009BC03D /* PBXContainerItemProxy */; 433 | }; 434 | /* End PBXTargetDependency section */ 435 | 436 | /* Begin PBXVariantGroup section */ 437 | 03A99E201E98066B009BC03D /* LaunchScreen.storyboard */ = { 438 | isa = PBXVariantGroup; 439 | children = ( 440 | 03A99E211E98066B009BC03D /* Base */, 441 | ); 442 | name = LaunchScreen.storyboard; 443 | sourceTree = ""; 444 | }; 445 | /* End PBXVariantGroup section */ 446 | 447 | /* Begin XCBuildConfiguration section */ 448 | 03A99E3A1E98066B009BC03D /* Debug */ = { 449 | isa = XCBuildConfiguration; 450 | buildSettings = { 451 | ALWAYS_SEARCH_USER_PATHS = NO; 452 | CLANG_ANALYZER_NONNULL = YES; 453 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 454 | CLANG_CXX_LIBRARY = "libc++"; 455 | CLANG_ENABLE_MODULES = YES; 456 | CLANG_ENABLE_OBJC_ARC = YES; 457 | CLANG_WARN_BOOL_CONVERSION = YES; 458 | CLANG_WARN_CONSTANT_CONVERSION = YES; 459 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 460 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 461 | CLANG_WARN_EMPTY_BODY = YES; 462 | CLANG_WARN_ENUM_CONVERSION = YES; 463 | CLANG_WARN_INFINITE_RECURSION = YES; 464 | CLANG_WARN_INT_CONVERSION = YES; 465 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 466 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 467 | CLANG_WARN_UNREACHABLE_CODE = YES; 468 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 469 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 470 | COPY_PHASE_STRIP = NO; 471 | DEBUG_INFORMATION_FORMAT = dwarf; 472 | ENABLE_STRICT_OBJC_MSGSEND = YES; 473 | ENABLE_TESTABILITY = YES; 474 | GCC_C_LANGUAGE_STANDARD = gnu99; 475 | GCC_DYNAMIC_NO_PIC = NO; 476 | GCC_NO_COMMON_BLOCKS = YES; 477 | GCC_OPTIMIZATION_LEVEL = 0; 478 | GCC_PREPROCESSOR_DEFINITIONS = ( 479 | "DEBUG=1", 480 | "$(inherited)", 481 | ); 482 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 483 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 484 | GCC_WARN_UNDECLARED_SELECTOR = YES; 485 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 486 | GCC_WARN_UNUSED_FUNCTION = YES; 487 | GCC_WARN_UNUSED_VARIABLE = YES; 488 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 489 | MTL_ENABLE_DEBUG_INFO = YES; 490 | ONLY_ACTIVE_ARCH = YES; 491 | SDKROOT = iphoneos; 492 | }; 493 | name = Debug; 494 | }; 495 | 03A99E3B1E98066B009BC03D /* Release */ = { 496 | isa = XCBuildConfiguration; 497 | buildSettings = { 498 | ALWAYS_SEARCH_USER_PATHS = NO; 499 | CLANG_ANALYZER_NONNULL = YES; 500 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 501 | CLANG_CXX_LIBRARY = "libc++"; 502 | CLANG_ENABLE_MODULES = YES; 503 | CLANG_ENABLE_OBJC_ARC = YES; 504 | CLANG_WARN_BOOL_CONVERSION = YES; 505 | CLANG_WARN_CONSTANT_CONVERSION = YES; 506 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 507 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 508 | CLANG_WARN_EMPTY_BODY = YES; 509 | CLANG_WARN_ENUM_CONVERSION = YES; 510 | CLANG_WARN_INFINITE_RECURSION = YES; 511 | CLANG_WARN_INT_CONVERSION = YES; 512 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 513 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 514 | CLANG_WARN_UNREACHABLE_CODE = YES; 515 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 516 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 517 | COPY_PHASE_STRIP = NO; 518 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 519 | ENABLE_NS_ASSERTIONS = NO; 520 | ENABLE_STRICT_OBJC_MSGSEND = YES; 521 | GCC_C_LANGUAGE_STANDARD = gnu99; 522 | GCC_NO_COMMON_BLOCKS = YES; 523 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 524 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 525 | GCC_WARN_UNDECLARED_SELECTOR = YES; 526 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 527 | GCC_WARN_UNUSED_FUNCTION = YES; 528 | GCC_WARN_UNUSED_VARIABLE = YES; 529 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 530 | MTL_ENABLE_DEBUG_INFO = NO; 531 | SDKROOT = iphoneos; 532 | VALIDATE_PRODUCT = YES; 533 | }; 534 | name = Release; 535 | }; 536 | 03A99E3D1E98066B009BC03D /* Debug */ = { 537 | isa = XCBuildConfiguration; 538 | buildSettings = { 539 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 540 | DEVELOPMENT_TEAM = 7L64JRM966; 541 | INFOPLIST_FILE = JCAlertController/Info.plist; 542 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 543 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 544 | PRODUCT_BUNDLE_IDENTIFIER = com.HJaycee.JCAlertController; 545 | PRODUCT_NAME = "$(TARGET_NAME)"; 546 | }; 547 | name = Debug; 548 | }; 549 | 03A99E3E1E98066B009BC03D /* Release */ = { 550 | isa = XCBuildConfiguration; 551 | buildSettings = { 552 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 553 | DEVELOPMENT_TEAM = 7L64JRM966; 554 | INFOPLIST_FILE = JCAlertController/Info.plist; 555 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 556 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 557 | PRODUCT_BUNDLE_IDENTIFIER = com.HJaycee.JCAlertController; 558 | PRODUCT_NAME = "$(TARGET_NAME)"; 559 | }; 560 | name = Release; 561 | }; 562 | 03A99E401E98066B009BC03D /* Debug */ = { 563 | isa = XCBuildConfiguration; 564 | buildSettings = { 565 | BUNDLE_LOADER = "$(TEST_HOST)"; 566 | INFOPLIST_FILE = JCAlertControllerTests/Info.plist; 567 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 568 | PRODUCT_BUNDLE_IDENTIFIER = com.HJaycee.JCAlertControllerTests; 569 | PRODUCT_NAME = "$(TARGET_NAME)"; 570 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JCAlertController.app/JCAlertController"; 571 | }; 572 | name = Debug; 573 | }; 574 | 03A99E411E98066B009BC03D /* Release */ = { 575 | isa = XCBuildConfiguration; 576 | buildSettings = { 577 | BUNDLE_LOADER = "$(TEST_HOST)"; 578 | INFOPLIST_FILE = JCAlertControllerTests/Info.plist; 579 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 580 | PRODUCT_BUNDLE_IDENTIFIER = com.HJaycee.JCAlertControllerTests; 581 | PRODUCT_NAME = "$(TARGET_NAME)"; 582 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JCAlertController.app/JCAlertController"; 583 | }; 584 | name = Release; 585 | }; 586 | 03A99E431E98066B009BC03D /* Debug */ = { 587 | isa = XCBuildConfiguration; 588 | buildSettings = { 589 | INFOPLIST_FILE = JCAlertControllerUITests/Info.plist; 590 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 591 | PRODUCT_BUNDLE_IDENTIFIER = com.HJaycee.JCAlertControllerUITests; 592 | PRODUCT_NAME = "$(TARGET_NAME)"; 593 | TEST_TARGET_NAME = JCAlertController; 594 | }; 595 | name = Debug; 596 | }; 597 | 03A99E441E98066B009BC03D /* Release */ = { 598 | isa = XCBuildConfiguration; 599 | buildSettings = { 600 | INFOPLIST_FILE = JCAlertControllerUITests/Info.plist; 601 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 602 | PRODUCT_BUNDLE_IDENTIFIER = com.HJaycee.JCAlertControllerUITests; 603 | PRODUCT_NAME = "$(TARGET_NAME)"; 604 | TEST_TARGET_NAME = JCAlertController; 605 | }; 606 | name = Release; 607 | }; 608 | /* End XCBuildConfiguration section */ 609 | 610 | /* Begin XCConfigurationList section */ 611 | 03A99E0A1E98066B009BC03D /* Build configuration list for PBXProject "JCAlertController" */ = { 612 | isa = XCConfigurationList; 613 | buildConfigurations = ( 614 | 03A99E3A1E98066B009BC03D /* Debug */, 615 | 03A99E3B1E98066B009BC03D /* Release */, 616 | ); 617 | defaultConfigurationIsVisible = 0; 618 | defaultConfigurationName = Release; 619 | }; 620 | 03A99E3C1E98066B009BC03D /* Build configuration list for PBXNativeTarget "JCAlertController" */ = { 621 | isa = XCConfigurationList; 622 | buildConfigurations = ( 623 | 03A99E3D1E98066B009BC03D /* Debug */, 624 | 03A99E3E1E98066B009BC03D /* Release */, 625 | ); 626 | defaultConfigurationIsVisible = 0; 627 | defaultConfigurationName = Release; 628 | }; 629 | 03A99E3F1E98066B009BC03D /* Build configuration list for PBXNativeTarget "JCAlertControllerTests" */ = { 630 | isa = XCConfigurationList; 631 | buildConfigurations = ( 632 | 03A99E401E98066B009BC03D /* Debug */, 633 | 03A99E411E98066B009BC03D /* Release */, 634 | ); 635 | defaultConfigurationIsVisible = 0; 636 | defaultConfigurationName = Release; 637 | }; 638 | 03A99E421E98066B009BC03D /* Build configuration list for PBXNativeTarget "JCAlertControllerUITests" */ = { 639 | isa = XCConfigurationList; 640 | buildConfigurations = ( 641 | 03A99E431E98066B009BC03D /* Debug */, 642 | 03A99E441E98066B009BC03D /* Release */, 643 | ); 644 | defaultConfigurationIsVisible = 0; 645 | defaultConfigurationName = Release; 646 | }; 647 | /* End XCConfigurationList section */ 648 | }; 649 | rootObject = 03A99E071E98066B009BC03D /* Project object */; 650 | } 651 | --------------------------------------------------------------------------------