口袋优选

TYAlertController.m 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. //
  2. // TYAlertController.m
  3. // TYAlertControllerDemo
  4. //
  5. // Created by tanyang on 15/9/1.
  6. // Copyright (c) 2015年 tanyang. All rights reserved.
  7. //
  8. #import "TYAlertController.h"
  9. #import "UIView+TYAutoLayout.h"
  10. @interface TYAlertController ()
  11. @property (nonatomic, strong) UIView *alertView;
  12. @property (nonatomic, assign) TYAlertControllerStyle preferredStyle;
  13. @property (nonatomic, assign) TYAlertTransitionAnimation transitionAnimation;
  14. @property (nonatomic, assign) Class transitionAnimationClass;
  15. @property (nonatomic, weak) UITapGestureRecognizer *singleTap;
  16. @property (nonatomic, strong) NSLayoutConstraint *alertViewCenterYConstraint;
  17. @property (nonatomic, assign) CGFloat alertViewCenterYOffset;
  18. @end
  19. @implementation TYAlertController
  20. #pragma mark - init
  21. - (instancetype)init
  22. {
  23. if (self = [super init]) {
  24. [self configureController];
  25. }
  26. return self;
  27. }
  28. - (id)initWithCoder:(NSCoder *)aDecoder
  29. {
  30. if (self = [super initWithCoder:aDecoder]) {
  31. [self configureController];
  32. }
  33. return self;
  34. }
  35. - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
  36. {
  37. if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
  38. [self configureController];
  39. }
  40. return self;
  41. }
  42. - (instancetype)initWithAlertView:(UIView *)alertView preferredStyle:(TYAlertControllerStyle)preferredStyle transitionAnimation:(TYAlertTransitionAnimation)transitionAnimation transitionAnimationClass:(Class)transitionAnimationClass
  43. {
  44. if (self = [self initWithNibName:nil bundle:nil]) {
  45. _alertView = alertView;
  46. _preferredStyle = preferredStyle;
  47. _transitionAnimation = transitionAnimation;
  48. _transitionAnimationClass = transitionAnimationClass;
  49. }
  50. return self;
  51. }
  52. + (instancetype)alertControllerWithAlertView:(UIView *)alertView
  53. {
  54. return [[self alloc]initWithAlertView:alertView
  55. preferredStyle:TYAlertControllerStyleAlert
  56. transitionAnimation:TYAlertTransitionAnimationFade
  57. transitionAnimationClass:nil];
  58. }
  59. + (instancetype)alertControllerWithAlertView:(UIView *)alertView preferredStyle:(TYAlertControllerStyle)preferredStyle
  60. {
  61. return [[self alloc]initWithAlertView:alertView
  62. preferredStyle:preferredStyle
  63. transitionAnimation:TYAlertTransitionAnimationFade
  64. transitionAnimationClass:nil];
  65. }
  66. + (instancetype)alertControllerWithAlertView:(UIView *)alertView preferredStyle:(TYAlertControllerStyle)preferredStyle transitionAnimation:(TYAlertTransitionAnimation)transitionAnimation
  67. {
  68. return [[self alloc]initWithAlertView:alertView
  69. preferredStyle:preferredStyle
  70. transitionAnimation:transitionAnimation
  71. transitionAnimationClass:nil];
  72. }
  73. + (instancetype)alertControllerWithAlertView:(UIView *)alertView preferredStyle:(TYAlertControllerStyle)preferredStyle transitionAnimationClass:(Class)transitionAnimationClass
  74. {
  75. return [[self alloc]initWithAlertView:alertView
  76. preferredStyle:preferredStyle
  77. transitionAnimation:TYAlertTransitionAnimationCustom
  78. transitionAnimationClass:transitionAnimationClass];
  79. }
  80. #pragma mark - life cycle
  81. - (void)viewDidLoad {
  82. [super viewDidLoad];
  83. // Do any additional setup after loading the view.
  84. self.view.backgroundColor = [UIColor clearColor];
  85. [self addBackgroundView];
  86. [self addSingleTapGesture];
  87. [self configureAlertView];
  88. [self.view layoutIfNeeded];
  89. if (_preferredStyle == TYAlertControllerStyleAlert) {
  90. // UIKeyboard Notification
  91. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
  92. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
  93. }
  94. }
  95. - (void)viewWillAppear:(BOOL)animated
  96. {
  97. [super viewWillAppear:animated];
  98. if (_viewWillShowHandler) {
  99. _viewWillShowHandler(_alertView);
  100. }
  101. }
  102. - (void)viewDidAppear:(BOOL)animated
  103. {
  104. [super viewDidAppear:animated];
  105. if (_viewDidShowHandler) {
  106. _viewDidShowHandler(_alertView);
  107. }
  108. }
  109. - (void)viewWillDisappear:(BOOL)animated
  110. {
  111. [super viewWillDisappear:animated];
  112. if (_viewWillHideHandler) {
  113. _viewWillHideHandler(_alertView);
  114. }
  115. }
  116. - (void)viewDidDisappear:(BOOL)animated
  117. {
  118. [super viewDidDisappear:animated];
  119. if (_viewDidHideHandler) {
  120. _viewDidHideHandler(_alertView);
  121. }
  122. }
  123. - (void)addBackgroundView
  124. {
  125. if (_backgroundView == nil) {
  126. UIView *backgroundView = [[UIView alloc]init];
  127. backgroundView.backgroundColor = _backgroundColor;
  128. _backgroundView = backgroundView;
  129. }
  130. _backgroundView.translatesAutoresizingMaskIntoConstraints = NO;
  131. [self.view insertSubview:_backgroundView atIndex:0];
  132. [self.view addConstraintToView:_backgroundView edgeInset:UIEdgeInsetsZero];
  133. }
  134. - (void)setBackgroundView:(UIView *)backgroundView
  135. {
  136. if (_backgroundView == nil) {
  137. _backgroundView = backgroundView;
  138. } else if (_backgroundView != backgroundView) {
  139. backgroundView.translatesAutoresizingMaskIntoConstraints = NO;
  140. [self.view insertSubview:backgroundView aboveSubview:_backgroundView];
  141. [self.view addConstraintToView:backgroundView edgeInset:UIEdgeInsetsZero];
  142. backgroundView.alpha = 0;
  143. [UIView animateWithDuration:0.3 animations:^{
  144. backgroundView.alpha = 1;
  145. } completion:^(BOOL finished) {
  146. [_backgroundView removeFromSuperview];
  147. _backgroundView = backgroundView;
  148. [self addSingleTapGesture];
  149. }];
  150. }
  151. }
  152. - (void)addSingleTapGesture
  153. {
  154. self.view.userInteractionEnabled = YES;
  155. _backgroundView.userInteractionEnabled = YES;
  156. UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)];
  157. singleTap.enabled = _backgoundTapDismissEnable;
  158. [_backgroundView addGestureRecognizer:singleTap];
  159. _singleTap = singleTap;
  160. }
  161. - (void)setBackgoundTapDismissEnable:(BOOL)backgoundTapDismissEnable
  162. {
  163. _backgoundTapDismissEnable = backgoundTapDismissEnable;
  164. _singleTap.enabled = backgoundTapDismissEnable;
  165. }
  166. #pragma mark - configure
  167. - (void)configureController
  168. {
  169. self.providesPresentationContextTransitionStyle = YES;
  170. self.definesPresentationContext = YES;
  171. self.modalPresentationStyle = UIModalPresentationCustom;
  172. self.transitioningDelegate = self;
  173. _backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.4];
  174. _backgoundTapDismissEnable = NO;
  175. _alertStyleEdging = 15;
  176. _actionSheetStyleEdging = 0;
  177. }
  178. - (void)configureAlertView
  179. {
  180. if (_alertView == nil) {
  181. NSLog(@"%@: alertView is nil",NSStringFromClass([self class]));
  182. return;
  183. }
  184. _alertView.userInteractionEnabled = YES;
  185. [self.view addSubview:_alertView];
  186. _alertView.translatesAutoresizingMaskIntoConstraints = NO;
  187. switch (_preferredStyle) {
  188. case TYAlertControllerStyleActionSheet:
  189. [self layoutActionSheetStyleView];
  190. break;
  191. case TYAlertControllerStyleAlert:
  192. [self layoutAlertStyleView];
  193. break;
  194. default:
  195. break;
  196. }
  197. }
  198. - (void)configureAlertViewWidth
  199. {
  200. // width, height
  201. if (!CGSizeEqualToSize(_alertView.frame.size,CGSizeZero)) {
  202. [_alertView addConstraintWidth:CGRectGetWidth(_alertView.frame) height:CGRectGetHeight(_alertView.frame)];
  203. }else {
  204. BOOL findAlertViewWidthConstraint = NO;
  205. for (NSLayoutConstraint *constraint in _alertView.constraints) {
  206. if (constraint.firstAttribute == NSLayoutAttributeWidth) {
  207. findAlertViewWidthConstraint = YES;
  208. break;
  209. }
  210. }
  211. if (!findAlertViewWidthConstraint) {
  212. [_alertView addConstraintWidth:CGRectGetWidth(self.view.frame)-2*_alertStyleEdging height:0];
  213. }
  214. }
  215. }
  216. #pragma mark - layout
  217. - (void)layoutAlertStyleView
  218. {
  219. // center X
  220. [self.view addConstraintCenterXToView:_alertView centerYToView:nil];
  221. [self configureAlertViewWidth];
  222. // top Y
  223. _alertViewCenterYConstraint = [self.view addConstraintCenterYToView:_alertView constant:0];
  224. if (_alertViewOriginY > 0) {
  225. [_alertView layoutIfNeeded];
  226. _alertViewCenterYOffset = _alertViewOriginY - (CGRectGetHeight(self.view.frame) - CGRectGetHeight(_alertView.frame))/2;
  227. _alertViewCenterYConstraint.constant = _alertViewCenterYOffset;
  228. }else{
  229. _alertViewCenterYOffset = 0;
  230. }
  231. }
  232. - (void)layoutActionSheetStyleView
  233. {
  234. // remove width constaint
  235. for (NSLayoutConstraint *constraint in _alertView.constraints) {
  236. if (constraint.firstAttribute == NSLayoutAttributeWidth) {
  237. [_alertView removeConstraint: constraint];
  238. break;
  239. }
  240. }
  241. // add edge constraint
  242. [self.view addConstraintWithView:_alertView topView:nil leftView:self.view bottomView:self.view rightView:self.view edgeInset:UIEdgeInsetsMake(0, _actionSheetStyleEdging, 0, -_actionSheetStyleEdging)];
  243. if (CGRectGetHeight(_alertView.frame) > 0) {
  244. // height
  245. [_alertView addConstraintWidth:0 height:CGRectGetHeight(_alertView.frame)];
  246. }
  247. }
  248. - (void)dismissViewControllerAnimated:(BOOL)animated
  249. {
  250. [self dismissViewControllerAnimated:YES completion:self.dismissComplete];
  251. }
  252. #pragma mark - action
  253. - (void)singleTap:(UITapGestureRecognizer *)sender
  254. {
  255. [self dismissViewControllerAnimated:YES];
  256. }
  257. #pragma mark - notification
  258. - (void)keyboardWillShow:(NSNotification*)notification
  259. {
  260. CGRect keyboardRect = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
  261. CGFloat alertViewBottomEdge = (CGRectGetHeight(self.view.frame) - CGRectGetHeight(_alertView.frame))/2 - _alertViewCenterYOffset;
  262. //当开启热点时,向下偏移20px
  263. //修复键盘遮挡问题
  264. CGFloat statusBarHeight = [UIApplication sharedApplication].statusBarFrame.size.height;
  265. CGFloat differ = CGRectGetHeight(keyboardRect) - alertViewBottomEdge;
  266. //修复:输入框获取焦点时,会重复刷新,导致输入框文章偏移一下
  267. if (_alertViewCenterYConstraint.constant == -differ -statusBarHeight) {
  268. return;
  269. }
  270. if (differ >= 0) {
  271. _alertViewCenterYConstraint.constant = _alertViewCenterYOffset - differ - statusBarHeight;
  272. [UIView animateWithDuration:0.25 animations:^{
  273. [self.view layoutIfNeeded];
  274. }];
  275. }
  276. }
  277. - (void)keyboardWillHide:(NSNotification*)notification
  278. {
  279. _alertViewCenterYConstraint.constant = _alertViewCenterYOffset;
  280. [UIView animateWithDuration:0.25 animations:^{
  281. [self.view layoutIfNeeded];
  282. }];
  283. }
  284. - (void)didReceiveMemoryWarning {
  285. [super didReceiveMemoryWarning];
  286. // Dispose of any resources that can be recreated.
  287. }
  288. - (void)dealloc
  289. {
  290. [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
  291. [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
  292. }
  293. @end