STAlertView.m 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. //
  2. // STAlertView.m
  3. // STModalDemo
  4. //
  5. // Created by zhenlintie on 15/6/5.
  6. // Copyright (c) 2015年 sTeven. All rights reserved.
  7. //
  8. #import "STAlertView.h"
  9. #import "STModal.h"
  10. #import "STModalUtil.h"
  11. #define kSTAlertWidth 300
  12. #define kSTAlertPaddingV 11
  13. #define kSTAlertPaddingH 18
  14. #define kSTAlertRadius 13
  15. #define kSTAlertButtonHeight 40
  16. @interface STAlertView ()
  17. @property (strong, nonatomic) UIView *backgroundView;
  18. @property (strong, nonatomic) UIView *containerView;
  19. @property (strong, nonatomic) UIScrollView *scrollView;
  20. @property (strong, nonatomic) UILabel *titleLabel;
  21. @property (strong, nonatomic) UIImageView *imageView;
  22. @property (strong, nonatomic) UILabel *messageLabel;
  23. @property (strong, nonatomic) NSMutableArray *buttons;
  24. @property (strong, nonatomic) NSMutableArray *lines;
  25. @end
  26. @implementation STAlertView{
  27. STModal *_modal;
  28. BOOL _didLayouted;
  29. CGFloat _scrollBottom;
  30. CGFloat _buttonsHeight;
  31. CGFloat _maxContentWidth;
  32. CGFloat _maxAlertViewHeight;
  33. }
  34. - (instancetype)initWithTitle:(NSString *)title image:(UIImage *)image message:(NSString *)message buttonTitles:(NSArray *)buttonTitles{
  35. if (self = [self initWithFrame:CGRectZero]){
  36. _title = [title copy];
  37. _image = image;
  38. _message = [message copy];
  39. _buttonTitles = [NSArray arrayWithArray:buttonTitles];
  40. }
  41. return self;
  42. }
  43. - (instancetype)initWithFrame:(CGRect)frame{
  44. if (self = [super initWithFrame:CGRectMake(0, 0, kSTAlertWidth, 0)]){
  45. [self loadData];
  46. [self loadUI];
  47. }
  48. return self;
  49. }
  50. - (void)loadData{
  51. _didLayouted = NO;
  52. _hideWhenTapOutside = NO;
  53. _buttons = [NSMutableArray new];
  54. _lines = [NSMutableArray new];
  55. _modal = [STModal modalWithContentView:self];
  56. _modal.hideWhenTouchOutside = NO;
  57. _modal.dimBackgroundWhenShow = NO;
  58. _modal.showAnimation = [self showAnimation];
  59. _modal.hideAnimation = [self hideAnimation];
  60. }
  61. - (void)loadUI{
  62. _backgroundView = [UIView new];
  63. _backgroundView.backgroundColor = STModalRGBA(255, 255, 255, 1);
  64. _backgroundView.layer.cornerRadius = kSTAlertRadius;
  65. _backgroundView.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.5].CGColor;
  66. _backgroundView.layer.shadowOffset = CGSizeZero;
  67. _backgroundView.layer.shadowOpacity = 1;
  68. _backgroundView.layer.shadowRadius = kSTAlertRadius;
  69. // _backgroundView.layer.borderWidth = 0.5;
  70. // _backgroundView.layer.borderColor = STModalRGBA(110, 115, 120, 1).CGColor;
  71. _containerView = [UIView new];
  72. _containerView.layer.cornerRadius = kSTAlertRadius;
  73. _containerView.layer.masksToBounds = YES;
  74. _scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];
  75. [_containerView addSubview:_scrollView];
  76. [self addSubview:_backgroundView];
  77. [self addSubview:_containerView];
  78. }
  79. - (st_modal_animation)showAnimation{
  80. return ^CGFloat(){
  81. self.alpha = 0;
  82. CGFloat d1 = 0.2, d2 = 0.15;
  83. self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.4, 0.4);
  84. [UIView animateWithDuration:d1 animations:^{
  85. self.alpha = 1;
  86. self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.1, 1.1);
  87. } completion:^(BOOL finished) {
  88. [UIView animateWithDuration:d2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
  89. self.alpha = 1;
  90. self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1, 1);
  91. } completion:^(BOOL finished2) {
  92. }];
  93. }];
  94. return (d1+d2);
  95. };
  96. }
  97. - (st_modal_animation)hideAnimation{
  98. return ^CGFloat(){
  99. CGFloat d1 = 0.2, d2 = 0.1;
  100. [UIView animateWithDuration:d2 animations:^{
  101. self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.1, 1.1);
  102. } completion:^(BOOL finished){
  103. [UIView animateWithDuration:d1 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
  104. self.alpha = 0;
  105. self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.4, 0.4);
  106. } completion:^(BOOL finished2){
  107. }];
  108. }];
  109. return (d1+d2);
  110. };
  111. }
  112. #pragma mark - prepare for show
  113. - (void)prepareForShow{
  114. if (_didLayouted){
  115. return;
  116. }
  117. [self resetViews];
  118. _scrollBottom = 0;
  119. CGFloat insetY = kSTAlertPaddingV;
  120. _maxContentWidth = kSTAlertWidth-2*kSTAlertPaddingH;
  121. _maxAlertViewHeight = [UIScreen mainScreen].bounds.size.height-50;
  122. [self loadTitle];
  123. [self loadImage];
  124. [self loadMessage];
  125. _buttonsHeight = kSTAlertButtonHeight*((_buttonTitles.count>2||_buttonTitles.count==0)?_buttonTitles.count:1);
  126. self.frame = CGRectMake(0, 0, kSTAlertWidth, MIN(MAX(_scrollBottom+2*insetY+_buttonsHeight, 2*kSTAlertRadius+kSTAlertPaddingV), _maxAlertViewHeight));
  127. _backgroundView.frame = self.bounds;
  128. _backgroundView.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.bounds].CGPath;
  129. _containerView.frame = self.bounds;
  130. _scrollView.frame = CGRectMake(0, insetY, CGRectGetWidth(_containerView.frame),MIN(_scrollBottom, CGRectGetHeight(_containerView.frame)-2*insetY-_buttonsHeight));
  131. _scrollView.contentSize = CGSizeMake(_maxContentWidth, _scrollBottom);
  132. _didLayouted = YES;
  133. [self loadButtons];
  134. }
  135. - (void)resetViews{
  136. if (_titleLabel){
  137. [_titleLabel removeFromSuperview];
  138. _titleLabel.text = @"";
  139. }
  140. if (_imageView){
  141. [_imageView removeFromSuperview];
  142. _imageView.image = nil;
  143. }
  144. if (_messageLabel){
  145. [_messageLabel removeFromSuperview];
  146. _messageLabel.text = @"";
  147. }
  148. if (_buttons.count > 0){
  149. [_buttons makeObjectsPerformSelector:@selector(removeFromSuperview)];
  150. [_buttons removeAllObjects];
  151. }
  152. if (_lines.count > 0){
  153. [_lines makeObjectsPerformSelector:@selector(removeFromSuperview)];
  154. [_lines removeAllObjects];
  155. }
  156. }
  157. - (void)addLabel:(UILabel *)label maxHeight:(CGFloat)maxHeight{
  158. CGSize size = [label sizeThatFits:CGSizeMake(_maxContentWidth, maxHeight)];
  159. label.frame = CGRectMake(kSTAlertPaddingH, _scrollBottom, _maxContentWidth, size.height);
  160. [_scrollView addSubview:label];
  161. _scrollBottom = CGRectGetMaxY(label.frame)+kSTAlertPaddingV;
  162. }
  163. - (void)addLine:(CGRect)frame toView:(UIView *)view{
  164. UIView *line = [[UIView alloc] initWithFrame:frame];
  165. line.backgroundColor = STModalRGBA(160, 170, 160, 0.5);
  166. [view addSubview:line];
  167. [_lines addObject:line];
  168. }
  169. - (void)loadTitle{
  170. if (!_title){
  171. return;
  172. }
  173. if (!_titleLabel){
  174. _titleLabel = [UILabel new];
  175. _titleLabel.textColor = [UIColor blackColor];
  176. _titleLabel.font = [UIFont boldSystemFontOfSize:17];
  177. _titleLabel.textAlignment = NSTextAlignmentCenter;
  178. _titleLabel.numberOfLines = 0;
  179. }
  180. _titleLabel.text = _title;
  181. [self addLabel:_titleLabel maxHeight:100];
  182. [self addLine:CGRectMake(kSTAlertPaddingH, _scrollBottom, _maxContentWidth, 0.5) toView:_scrollView];
  183. _scrollBottom += kSTAlertPaddingV;
  184. }
  185. - (void)loadImage{
  186. if (!_image){
  187. return;
  188. }
  189. if (!_imageView){
  190. _imageView = [UIImageView new];
  191. }
  192. _imageView.image = _image;
  193. CGSize size = _image.size;
  194. if (size.width > _maxContentWidth){
  195. size = CGSizeMake(_maxContentWidth, size.height/size.width*_maxContentWidth);
  196. }
  197. _imageView.frame = CGRectMake(kSTAlertPaddingH+_maxContentWidth/2-size.width/2, _scrollBottom, size.width, size.height);
  198. [_scrollView addSubview:_imageView];
  199. _scrollBottom = CGRectGetMaxY(_imageView.frame)+kSTAlertPaddingV;
  200. }
  201. - (void)loadMessage{
  202. if (!_message){
  203. return;
  204. }
  205. if (!_messageLabel){
  206. _messageLabel = [UILabel new];
  207. _messageLabel.textColor = [UIColor grayColor];
  208. _messageLabel.font = [UIFont systemFontOfSize:15];
  209. _messageLabel.textAlignment = NSTextAlignmentCenter;
  210. _messageLabel.numberOfLines = 0;
  211. }
  212. _messageLabel.text = _message;
  213. [self addLabel:_messageLabel maxHeight:100000];
  214. }
  215. - (void)loadButtons{
  216. if (!_buttonTitles || _buttonTitles.count==0){
  217. return;
  218. }
  219. CGFloat buttonHeight = kSTAlertButtonHeight;
  220. CGFloat buttonWidth = kSTAlertWidth;
  221. CGFloat top = CGRectGetHeight(_containerView.frame)-_buttonsHeight;
  222. [self addLine:CGRectMake(0, top-0.5, buttonWidth, 0.5) toView:_containerView];
  223. if (1 == _buttonTitles.count){
  224. [self addButton:CGRectMake(0, top, buttonWidth, buttonHeight) title:[_buttonTitles firstObject] tag:0];
  225. }
  226. else if (2 == _buttonTitles.count){
  227. [self addButton:CGRectMake(0, top, buttonWidth/2, buttonHeight) title:[_buttonTitles firstObject] tag:0];
  228. [self addButton:CGRectMake(0+buttonWidth/2, top, buttonWidth/2, buttonHeight) title:[_buttonTitles lastObject] tag:1];
  229. [self addLine:CGRectMake(0+buttonWidth/2-.5, top, 0.5, buttonHeight) toView:_containerView];
  230. }
  231. else{
  232. for (NSInteger i=0; i<_buttonTitles.count; i++){
  233. [self addButton:CGRectMake(0, top, buttonWidth, buttonHeight) title:_buttonTitles[i] tag:i];
  234. top += buttonHeight;
  235. if (_buttonTitles.count-1!=i){
  236. [self addLine:CGRectMake(0, top, buttonWidth, 0.5) toView:_containerView];
  237. }
  238. }
  239. [_lines enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  240. [_containerView bringSubviewToFront:obj];
  241. }];
  242. }
  243. }
  244. - (UIButton *)addButton:(CGRect)frame title:(NSString *)title tag:(NSInteger)tag{
  245. UIButton *button = [[UIButton alloc] initWithFrame:frame];
  246. [button setTitle:title forState:UIControlStateNormal];
  247. button.titleLabel.font = [UIFont boldSystemFontOfSize:17];
  248. button.tag = tag;
  249. [button setTitleColor:STModalRGBA(255, 255, 255, 1) forState:UIControlStateNormal];
  250. [button setBackgroundImage:st_imageWithColor(THEMECOLOR) forState:UIControlStateNormal];
  251. [button setBackgroundImage:st_imageWithColor(STModalRGBA(255, 0, 0, 0.45)) forState:UIControlStateHighlighted];
  252. [button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
  253. [_containerView addSubview:button];
  254. [_buttons addObject:button];
  255. return button;
  256. }
  257. - (void)buttonClicked:(UIButton *)button{
  258. [self hide:YES];
  259. if (self.actionHandler){
  260. self.actionHandler(button.tag);
  261. }
  262. }
  263. #pragma mark - show / hide
  264. - (void)show:(BOOL)animated{
  265. [self prepareForShow];
  266. _modal.hideWhenTouchOutside = self.hideWhenTapOutside;
  267. _modal.didShowHandler = self.didShowHandler;
  268. _modal.didHideHandler = self.didHideHandler;
  269. [_modal show:animated];
  270. }
  271. - (void)hide:(BOOL)animated{
  272. [_modal hide:animated];
  273. }
  274. - (BOOL)onShow{
  275. return _modal.onShow;
  276. }
  277. @end
  278. @implementation STAlertView (Show)
  279. + (instancetype)showTitle:(NSString *)title
  280. image:(UIImage *)image
  281. message:(NSString *)message
  282. buttonTitles:(NSArray *)buttonTitles
  283. handler:(void (^)(NSInteger))handler{
  284. STAlertView *alert = [[STAlertView alloc] initWithTitle:title
  285. image:image
  286. message:message
  287. buttonTitles:buttonTitles];
  288. [alert setActionHandler:handler];
  289. [alert show:YES];
  290. return alert;
  291. }
  292. + (instancetype)showTitle:(NSString *)title
  293. message:(NSString *)message{
  294. STAlertView *alert = [[STAlertView alloc] initWithTitle:title
  295. image:nil
  296. message:message
  297. buttonTitles:nil];
  298. alert.hideWhenTapOutside = YES;
  299. [alert show:YES];
  300. return alert;
  301. }
  302. + (instancetype)showTitle:(NSString *)title
  303. message:(NSString *)message
  304. hideDelay:(CGFloat)delay{
  305. if (delay>0){
  306. STAlertView *alert = [self showTitle:title message:message];
  307. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  308. [alert hide:YES];
  309. });
  310. return alert;
  311. }
  312. return nil;
  313. }
  314. @end