SideSlipFilterController.m 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. //
  2. // SideSlipFilterController.m
  3. // IBOSSMAP
  4. //
  5. // Created by apple on 2017/4/1.
  6. // Copyright © 2017年 apple. All rights reserved.
  7. //
  8. #import "SideSlipFilterController.h"
  9. #import "SideSlipModel.h"
  10. #import "SideSlipBaseTableViewCell.h"
  11. #import "objc/message.h"
  12. #import "SideSlipConfig.h"
  13. #import "UIColor+hexColor.h"
  14. #import "objc/runtime.h"
  15. #define SCREEN_WIDTH [[UIScreen mainScreen] bounds].size.width
  16. #define SCREEN_HEIGHT [[UIScreen mainScreen] bounds].size.height
  17. #define SLIP_ORIGIN_FRAME CGRectMake(SCREEN_WIDTH, 0, SCREEN_WIDTH - _sideSlipLeading, SCREEN_HEIGHT)
  18. #define SLIP_DISTINATION_FRAME CGRectMake(_sideSlipLeading, rectStatusHeight, SCREEN_WIDTH - _sideSlipLeading, SCREEN_HEIGHT-rectStatusHeight)
  19. const CGFloat ANIMATION_DURATION_DEFAULT = 0.3f;
  20. const CGFloat SIDE_SLIP_LEADING_DEFAULT = 20;
  21. id (*objc_msgSendGetCellIdentifier)(id self, SEL _cmd) = (void *)objc_msgSend;
  22. CGFloat (*objc_msgSendGetCellHeight)(id self, SEL _cmd) = (void *)objc_msgSend;
  23. id (*objc_msgSendCreateCellWithIndexPath)(id self, SEL _cmd, NSIndexPath *) = (void *)objc_msgSend;
  24. @interface SideSlipFilterController ()<UITableViewDelegate, UITableViewDataSource, SideSlipBaseTableViewCellDelegate>
  25. @property (copy, nonatomic) SideSlipFilterCommitBlock commitBlock;
  26. @property (copy, nonatomic) SideSlipFilterResetBlock resetBlock;
  27. @property (weak, nonatomic) UINavigationController *filterNavigation;
  28. @property (strong, nonatomic) UITableView *mainTableView;
  29. @property (strong, nonatomic) UIView *backCover;
  30. @property (weak, nonatomic) UIViewController *sponsor;
  31. @property (strong, nonatomic) NSMutableDictionary *templateCellDict;
  32. @end
  33. @implementation SideSlipFilterController
  34. - (instancetype)initWithSponsor:(UIViewController *)sponsor
  35. resetBlock:(SideSlipFilterResetBlock)resetBlock
  36. commitBlock:(SideSlipFilterCommitBlock)commitBlock {
  37. self = [super init];
  38. if (self) {
  39. _sponsor = sponsor;
  40. _resetBlock = resetBlock;
  41. _commitBlock = commitBlock;
  42. UINavigationController *filterNavigation = [[NSClassFromString(FILTER_NAVIGATION_CONTROLLER_CLASS) alloc] initWithRootViewController:self];
  43. [filterNavigation setNavigationBarHidden:YES];
  44. filterNavigation.navigationBar.translucent = NO;
  45. [filterNavigation.view setFrame:SLIP_ORIGIN_FRAME];
  46. self.filterNavigation = filterNavigation;
  47. [self configureStatic];
  48. [self configureUI];
  49. }
  50. return self;
  51. }
  52. - (void)viewDidLoad {
  53. [super viewDidLoad];
  54. [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
  55. [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
  56. }
  57. #pragma mark 键盘出现
  58. -(void)keyboardWillShow:(NSNotification *)note
  59. {
  60. CGRect keyBoardRect=[note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
  61. self.mainTableView.contentInset = UIEdgeInsetsMake(0, 0, keyBoardRect.size.height, 0);
  62. }
  63. #pragma mark 键盘消失
  64. -(void)keyboardWillHide:(NSNotification *)note
  65. {
  66. self.mainTableView.contentInset = UIEdgeInsetsZero;
  67. }
  68. - (void)configureUI {
  69. UIView *topView=[self createTopView];
  70. [self.view setBackgroundColor:[UIColor whiteColor]];
  71. [self.view addSubview:topView];
  72. //bottomView
  73. UIView *bottomView = [self createBottomView];
  74. [self.view addSubview:bottomView];
  75. NSDictionary *views = @{@"topView":topView,@"mainTableView":self.mainTableView, @"bottomView":bottomView};
  76. [self.view addConstraint:[NSLayoutConstraint constraintWithItem:topView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:BOTTOM_BUTTON_HEIGHT]];
  77. [self.view addConstraint:[NSLayoutConstraint constraintWithItem:bottomView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:BOTTOM_BUTTON_HEIGHT]];
  78. [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[mainTableView]|" options:NSLayoutFormatAlignAllCenterX metrics:nil views:views]];
  79. [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[bottomView]|" options:NSLayoutFormatAlignAllCenterX metrics:nil views:views]];
  80. [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[topView]-0-|" options:NSLayoutFormatAlignAllCenterX metrics:nil views:views]];
  81. [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[topView][mainTableView][bottomView]-0-|" options:NSLayoutFormatAlignAllCenterX metrics:nil views:views]];
  82. }
  83. - (void)configureStatic {
  84. self.animationDuration = ANIMATION_DURATION_DEFAULT;
  85. self.sideSlipLeading = SIDE_SLIP_LEADING_DEFAULT;
  86. }
  87. - (void)show {
  88. [_sponsor.navigationController.view addSubview:self.backCover];
  89. [_sponsor.navigationController addChildViewController:self.navigationController];
  90. [_sponsor.navigationController.view addSubview:self.navigationController.view];
  91. _sponsor.navigationController.interactivePopGestureRecognizer.enabled = NO;
  92. [_backCover setHidden:YES];
  93. [UIView animateWithDuration:_animationDuration animations:^{
  94. if(Screen_Height>=812){
  95. [self.navigationController.view setFrame:CGRectMake(_sideSlipLeading, rectStatusHeight, SCREEN_WIDTH - _sideSlipLeading, SCREEN_HEIGHT-rectStatusHeight-34)];
  96. }
  97. else{
  98. [self.navigationController.view setFrame:SLIP_DISTINATION_FRAME];
  99. }
  100. } completion:^(BOOL finished) {
  101. [self->_backCover setHidden:NO];
  102. }];
  103. }
  104. -(void)showPagerView:(UINavigationController*)nav{
  105. [nav.view addSubview:self.backCover];
  106. [nav addChildViewController:self.navigationController];
  107. [nav.view addSubview:self.navigationController.view];
  108. nav.interactivePopGestureRecognizer.enabled = NO;
  109. [_backCover setHidden:YES];
  110. [UIView animateWithDuration:_animationDuration animations:^{
  111. if(Screen_Height>=812){
  112. [self.navigationController.view setFrame:CGRectMake(_sideSlipLeading, rectStatusHeight, SCREEN_WIDTH - _sideSlipLeading, SCREEN_HEIGHT-rectStatusHeight-34)];
  113. }
  114. else{
  115. [self.navigationController.view setFrame:SLIP_DISTINATION_FRAME];
  116. }
  117. } completion:^(BOOL finished) {
  118. [_backCover setHidden:NO];
  119. }];
  120. }
  121. - (void)dismiss {
  122. [UIView animateWithDuration:_animationDuration animations:^{
  123. [self.navigationController.view setFrame:SLIP_ORIGIN_FRAME];
  124. } completion:^(BOOL finished) {
  125. [_backCover removeFromSuperview];
  126. [self.navigationController.view removeFromSuperview];
  127. [self.navigationController removeFromParentViewController];
  128. }];
  129. }
  130. - (UIView *)createTopView {
  131. UIView *topView = [[UIView alloc] init];
  132. [topView setTranslatesAutoresizingMaskIntoConstraints:NO];
  133. UIButton *cancelButton = [[UIButton alloc] init];
  134. [cancelButton setTranslatesAutoresizingMaskIntoConstraints:NO];
  135. [cancelButton addTarget:self action:@selector(clickBackCover:) forControlEvents:UIControlEventTouchUpInside];
  136. [cancelButton.titleLabel setFont:[UIFont systemFontOfSize:BOTTOM_BUTTON_FONT_SIZE]];
  137. [cancelButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
  138. [cancelButton setTitle:@"取消" forState:UIControlStateNormal];
  139. cancelButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;
  140. [topView addSubview:cancelButton];
  141. NSString *Hvfl = @"H:[cancelButton(80)]-margin-|";
  142. NSDictionary *metrics = @{ @"margin":@20};
  143. //constraints
  144. NSDictionary *views = NSDictionaryOfVariableBindings(cancelButton);
  145. [topView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:Hvfl options:NSLayoutFormatAlignAllRight metrics:metrics views:views]];
  146. return topView;
  147. }
  148. - (UIView *)createBottomView {
  149. UIView *bottomView = [[UIView alloc] init];
  150. [bottomView setTranslatesAutoresizingMaskIntoConstraints:NO];
  151. UIButton *resetButton = [[UIButton alloc] init];
  152. [resetButton setTranslatesAutoresizingMaskIntoConstraints:NO];
  153. [resetButton addTarget:self action:@selector(clickResetButton:) forControlEvents:UIControlEventTouchUpInside];
  154. [resetButton.titleLabel setFont:[UIFont systemFontOfSize:BOTTOM_BUTTON_FONT_SIZE]];
  155. [resetButton setTitleColor:[UIColor hexColor:FILTER_BLACK_STRING] forState:UIControlStateNormal];
  156. [resetButton setTitle:@"重置" forState:UIControlStateNormal];
  157. [resetButton setBackgroundColor:[UIColor whiteColor]];
  158. [bottomView addSubview:resetButton];
  159. //commitButton
  160. UIButton *commitButton = [[UIButton alloc] init];
  161. [commitButton setTranslatesAutoresizingMaskIntoConstraints:NO];
  162. [commitButton addTarget:self action:@selector(clickCommitButton:) forControlEvents:UIControlEventTouchUpInside];
  163. [commitButton.titleLabel setFont:[UIFont systemFontOfSize:BOTTOM_BUTTON_FONT_SIZE]];
  164. [commitButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  165. [commitButton setTitle:@"确定" forState:UIControlStateNormal];
  166. [commitButton setBackgroundColor:[UIColor hexColor:FILTER_RED_STRING]];
  167. [bottomView addSubview:commitButton];
  168. //constraints
  169. NSDictionary *views = NSDictionaryOfVariableBindings(resetButton, commitButton);
  170. [bottomView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[resetButton][commitButton]|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:views]];
  171. [bottomView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[resetButton]-0-|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:views]];
  172. [bottomView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[commitButton]-0-|" options:NSLayoutFormatAlignAllCenterY metrics:nil views:views]];
  173. [bottomView addConstraint:[NSLayoutConstraint constraintWithItem:resetButton attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:commitButton attribute:NSLayoutAttributeWidth multiplier:1.f constant:0.f]];
  174. return bottomView;
  175. }
  176. - (void)clickResetButton:(id)sender {
  177. _resetBlock(_dataList);
  178. [[NSNotificationCenter defaultCenter] postNotificationName:FILTER_NOTIFICATION_NAME_DID_RESET_DATA object:nil];
  179. [_mainTableView reloadData];
  180. }
  181. - (void)clickCommitButton:(id)sender {
  182. _commitBlock(_dataList);
  183. [[NSNotificationCenter defaultCenter] postNotificationName:FILTER_NOTIFICATION_NAME_DID_COMMIT_DATA object:nil];
  184. }
  185. - (void)clickBackCover:(id)sender {
  186. [self dismiss];
  187. }
  188. - (void)reloadData {
  189. if (_mainTableView) {
  190. [_mainTableView reloadData];
  191. }
  192. }
  193. #pragma mark - DataSource Delegate
  194. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  195. return _dataList.count;
  196. }
  197. - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
  198. SideSlipModel *model = _dataList[indexPath.row];
  199. Class cellClazz = NSClassFromString(model.containerCellClass);
  200. if ([(id)cellClazz respondsToSelector:@selector(cellHeight)]) {
  201. CGFloat cellHeight = objc_msgSendGetCellHeight(cellClazz, NSSelectorFromString(@"cellHeight"));
  202. return cellHeight;
  203. }
  204. NSString *identifier = objc_msgSendGetCellIdentifier(cellClazz, NSSelectorFromString(@"cellReuseIdentifier"));
  205. SideSlipBaseTableViewCell *templateCell = [self.templateCellDict objectForKey:identifier];
  206. if (!templateCell) {
  207. templateCell = objc_msgSendCreateCellWithIndexPath(cellClazz, NSSelectorFromString(@"createCellWithIndexPath:"), indexPath);
  208. templateCell.delegate = self;
  209. [self.templateCellDict setObject:templateCell forKey:identifier];
  210. }
  211. [templateCell updateFrame:self.view.frame.size.width];
  212. //update
  213. [templateCell updateCellWithModel:&model indexPath:indexPath];
  214. //calculate
  215. NSLayoutConstraint *calculateCellConstraint = [NSLayoutConstraint constraintWithItem:templateCell.contentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:self.view.bounds.size.width];
  216. [templateCell.contentView addConstraint:calculateCellConstraint];
  217. CGSize cellSize = [templateCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
  218. [templateCell.contentView removeConstraint:calculateCellConstraint];
  219. CGFloat height = 0.f;
  220. if (cellSize.height>0) {
  221. height = cellSize.height;
  222. }
  223. else{
  224. height = templateCell.cellHeight;
  225. }
  226. return height;
  227. }
  228. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  229. SideSlipModel *model = _dataList[indexPath.row];
  230. Class cellClazz = NSClassFromString(model.containerCellClass);
  231. NSString *identifier = objc_msgSendGetCellIdentifier(cellClazz, NSSelectorFromString(@"cellReuseIdentifier"));
  232. SideSlipBaseTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
  233. if (!cell) {
  234. cell = objc_msgSendCreateCellWithIndexPath(cellClazz, NSSelectorFromString(@"createCellWithIndexPath:"), indexPath);
  235. cell.delegate = self;
  236. }
  237. cell.selectionStyle=UITableViewCellSelectionStyleNone;
  238. [cell updateCellWithModel:&model indexPath:indexPath];
  239. return cell;
  240. }
  241. - (void)sideSlipTableViewCellNeedsReload:(NSIndexPath *)indexPath {
  242. [_mainTableView reloadData];
  243. }
  244. - (void)sideSlipTableViewCellNeedsPushViewController:(UIViewController *)viewController animated:(BOOL)animated {
  245. [self.navigationController pushViewController:viewController animated:animated];
  246. }
  247. - (void)sideSlipTableViewCellNeedsDismissViewController:(UIViewController *)viewController animated:(BOOL)animated{
  248. [self presentViewController:viewController animated:NO completion:nil];
  249. }
  250. - (void)sideSlipTableViewCellNeedsScrollToCell:(UITableViewCell *)cell atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated {
  251. NSIndexPath *indexPath = [_mainTableView indexPathForRowAtPoint:cell.center];
  252. [_mainTableView scrollToRowAtIndexPath:indexPath atScrollPosition:scrollPosition animated:animated];
  253. }
  254. - (void)didReceiveMemoryWarning {
  255. [super didReceiveMemoryWarning];
  256. }
  257. #pragma mark - GetSet
  258. - (UITableView *)mainTableView {
  259. if (!_mainTableView) {
  260. _mainTableView = [[UITableView alloc] init];
  261. _mainTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
  262. //1.视图漂移或者闪动原因:
  263. //因为iOS 11后系统默认开启Self-Sizing,首先要知道Self-Sizing是个什么东东。官方文档是这样解释的:大概就是说我们不用再自己去计算cell的高度了,只要设置好这两个属性,约束好布局,系统会自动计算好cell的高度。
  264. // IOS11以后,Self-Sizing默认开启,包括Headers, footers。如果项目中没使用estimatedRowHeight属性,在IOS11下会有奇奇怪怪的现象,因为IOS11之前,estimatedRowHeight默认为0,Self-Sizing自动打开后,contentSize和contentOffset都可能发生改变。
  265. _mainTableView.estimatedRowHeight = 0;
  266. _mainTableView.estimatedSectionHeaderHeight = 0;
  267. _mainTableView.estimatedSectionFooterHeight = 0;
  268. _mainTableView.delegate = self;
  269. _mainTableView.dataSource = self;
  270. [_mainTableView setTranslatesAutoresizingMaskIntoConstraints:NO];
  271. [self.view addSubview:_mainTableView];
  272. }
  273. return _mainTableView;
  274. }
  275. - (NSMutableDictionary *)templateCellDict {
  276. if (!_templateCellDict) {
  277. _templateCellDict = [NSMutableDictionary dictionary];
  278. }
  279. return _templateCellDict;
  280. }
  281. - (UIView *)backCover {
  282. if (!_backCover) {
  283. _backCover = [[UIView alloc] initWithFrame:CGRectMake(0, rectStatusHeight, SCREEN_WIDTH, SCREEN_HEIGHT-rectStatusHeight)];
  284. [_backCover setBackgroundColor:[UIColor hexColor:FILTER_BACKGROUND_COVER_COLOR]];
  285. [_backCover setAlpha:FILTER_BACKGROUND_COVER_ALPHA];
  286. [_backCover addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickBackCover:)]];
  287. }
  288. return _backCover;
  289. }
  290. - (UINavigationController *)filterNavigation {
  291. return objc_getAssociatedObject(_sponsor, _cmd);
  292. }
  293. - (void)setFilterNavigation:(UINavigationController *)filterNavigation {
  294. //让sponsor持有filterNavigation
  295. objc_setAssociatedObject(_sponsor, @selector(filterNavigation), filterNavigation, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  296. }
  297. - (void)setDataList:(NSArray *)dataList {
  298. _dataList = [dataList copy];
  299. if (_mainTableView) {
  300. [_mainTableView reloadData];
  301. }
  302. }
  303. @end