CGXVerticalMenuBaseView.m 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. //
  2. // CGXVerticalMenuBaseView.m
  3. // CGXVerticalMenuView-OC
  4. //
  5. // Created by CGX on 2018/05/01.
  6. // Copyright © 2019 CGX. All rights reserved.
  7. //
  8. #import "CGXVerticalMenuBaseView.h"
  9. #import "CGXVerticalMenuBaseCell.h"
  10. @interface CGXVerticalMenuBaseView()
  11. @property (nonatomic, strong,readwrite) CGXVerticalMenuIndicatoCollectionView *collectionView;
  12. @end
  13. @implementation CGXVerticalMenuBaseView
  14. - (instancetype)initWithFrame:(CGRect)frame
  15. {
  16. self = [super initWithFrame:frame];
  17. if (self) {
  18. [self initializeData];
  19. [self initializeViews];
  20. }
  21. return self;
  22. }
  23. - (instancetype)initWithCoder:(NSCoder *)coder
  24. {
  25. self = [super initWithCoder:coder];
  26. if (self) {
  27. [self initializeData];
  28. [self initializeViews];
  29. }
  30. return self;
  31. }
  32. - (void)initializeViews
  33. {
  34. self.collectionView = [[CGXVerticalMenuIndicatoCollectionView alloc] initWithFrame:self.bounds collectionViewLayout:[self preferredFlowLayout]];
  35. self.collectionView.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0];
  36. self.collectionView.showsHorizontalScrollIndicator = NO;
  37. self.collectionView.showsVerticalScrollIndicator = self.showsVerticalScrollIndicator;
  38. self.collectionView.scrollsToTop = NO;
  39. self.collectionView.dataSource = self;
  40. self.collectionView.delegate = self;
  41. self.collectionView.alwaysBounceVertical = YES;
  42. [self.collectionView registerClass:[self preferredCellClass] forCellWithReuseIdentifier:NSStringFromClass([self preferredCellClass])];
  43. [self.collectionView registerClass:[self preferredHeadClass] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:NSStringFromClass([self preferredHeadClass])];
  44. [self.collectionView registerClass:[self preferredFootClass] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:NSStringFromClass([self preferredFootClass])];
  45. if (@available(iOS 11.0, *)) {
  46. self.collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
  47. }
  48. [self addSubview:self.collectionView];
  49. }
  50. - (void)setShowsVerticalScrollIndicator:(BOOL)showsVerticalScrollIndicator
  51. {
  52. _showsVerticalScrollIndicator = showsVerticalScrollIndicator;
  53. self.collectionView.showsVerticalScrollIndicator = showsVerticalScrollIndicator;
  54. }
  55. - (void)layoutSubviews
  56. {
  57. [super layoutSubviews];
  58. self.collectionView.frame = self.bounds;
  59. [self.collectionView reloadData];
  60. }
  61. - (void)setIndicators:(NSArray<UIView<CGXCategoryListIndicatorProtocol> *> *)indicators {
  62. _indicators = indicators;
  63. self.collectionView.indicators = indicators;
  64. }
  65. - (Class)preferredHeadClass {
  66. return UICollectionReusableView.class;
  67. }
  68. - (Class)preferredFootClass {
  69. return UICollectionReusableView.class;
  70. }
  71. - (void)registerCell:(Class)classCell IsXib:(BOOL)isXib
  72. {
  73. if (![classCell isKindOfClass:[UICollectionViewCell class]]) {
  74. NSAssert(![classCell isKindOfClass:[UICollectionViewCell class]], @"注册cell的registerCellAry数组必须是UICollectionViewCell类型");
  75. }
  76. if (isXib) {
  77. [self.collectionView registerNib:[UINib nibWithNibName:[NSString stringWithFormat:@"%@", classCell] bundle:nil] forCellWithReuseIdentifier:[NSString stringWithFormat:@"%@", classCell]];
  78. } else{
  79. [self.collectionView registerClass:classCell forCellWithReuseIdentifier:[NSString stringWithFormat:@"%@", classCell]];
  80. }
  81. }
  82. - (void)registerFooter:(Class)footer IsXib:(BOOL)isXib
  83. {
  84. if (![footer isKindOfClass:[UICollectionReusableView class]]) {
  85. NSAssert(![footer isKindOfClass:[UICollectionReusableView class]], @"注册cell的registerCellAry数组必须是UICollectionReusableView类型");
  86. }
  87. if (isXib) {
  88. [self.collectionView registerNib:[UINib nibWithNibName:[NSString stringWithFormat:@"%@", footer] bundle:nil] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:[NSString stringWithFormat:@"%@", footer]];
  89. } else{
  90. [self.collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:[NSString stringWithFormat:@"%@", footer]];
  91. }
  92. }
  93. - (void)registerHeader:(Class)header IsXib:(BOOL)isXib
  94. {
  95. if (![header isKindOfClass:[UICollectionReusableView class]]) {
  96. NSAssert(![header isKindOfClass:[UICollectionReusableView class]], @"注册cell的registerCellAry数组必须是UICollectionReusableView类型");
  97. }
  98. if (isXib) {
  99. [self.collectionView registerNib:[UINib nibWithNibName:[NSString stringWithFormat:@"%@", header] bundle:nil] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:[NSString stringWithFormat:@"%@", header]];
  100. } else{
  101. [self.collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:[NSString stringWithFormat:@"%@", header]];
  102. }
  103. }
  104. - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
  105. return self.dataArray.count;
  106. }
  107. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
  108. return 1;
  109. }
  110. - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
  111. {
  112. return UIEdgeInsetsMake(0, 0, 0, 0);
  113. }
  114. - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
  115. {
  116. return 0;
  117. }
  118. - (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
  119. {
  120. return 0;
  121. }
  122. - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
  123. {
  124. CGXVerticalMenuBaseModel *model = self.dataArray[indexPath.section];
  125. return CGSizeMake(collectionView.frame.size.width, model.rowHeight);
  126. }
  127. - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section
  128. {
  129. return CGSizeMake(0, 0);
  130. }
  131. - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
  132. {
  133. return CGSizeMake(0, 0);
  134. }
  135. - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
  136. {
  137. CGXVerticalMenuBaseCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([self preferredCellClass]) forIndexPath:indexPath];
  138. CGXVerticalMenuBaseModel *model = (CGXVerticalMenuBaseModel *)self.dataArray[indexPath.section];
  139. [cell reloadData:model];
  140. return cell;
  141. }
  142. - (void)willMoveToSuperview:(UIView *)newSuperview {
  143. [super willMoveToSuperview:newSuperview];
  144. UIResponder *next = newSuperview;
  145. while (next != nil) {
  146. if ([next isKindOfClass:[UIViewController class]]) {
  147. UIViewController *vc = (UIViewController *)next;
  148. if (@available(iOS 11.0, *)) {
  149. vc.automaticallyAdjustsScrollViewInsets = NO;
  150. }
  151. break;
  152. }
  153. next = next.nextResponder;
  154. }
  155. }
  156. - (void)updateMenuWithDataArray:(NSMutableArray<CGXVerticalMenuBaseModel *> *)dataArray
  157. {
  158. if (dataArray.count==0) {
  159. [self.collectionView reloadData];
  160. return;
  161. }
  162. [self.dataArray removeAllObjects];
  163. [self.dataArray addObjectsFromArray:dataArray];
  164. if (self.selectedIndex < 0 || self.selectedIndex >= self.dataArray.count) {
  165. self.selectedIndex = 0;
  166. }
  167. for (int i = 0; i<self.dataArray.count; i++) {
  168. CGXVerticalMenuBaseModel *cellModel = self.dataArray[i];
  169. if (self.selectedIndex==i) {
  170. cellModel.selected = YES;
  171. } else{
  172. cellModel.selected = NO;
  173. }
  174. [self.dataArray replaceObjectAtIndex:i withObject:cellModel];
  175. }
  176. [self.collectionView reloadData];
  177. }
  178. - (void)replaceObjectAtIndex:(NSInteger)index ItemModel:(CGXVerticalMenuBaseModel *)itemModel
  179. {
  180. if (self.dataArray.count==0 || index<0) {
  181. return;
  182. }
  183. if (index>self.dataArray.count-1) {
  184. return;
  185. }
  186. CGXVerticalMenuBaseModel *newModel = (CGXVerticalMenuBaseModel *)itemModel;
  187. [self.dataArray replaceObjectAtIndex:index withObject:newModel];
  188. [self reloadCellAtIndex:index];
  189. }
  190. - (void)reloadCellAtIndex:(NSInteger)index
  191. {
  192. if (index < 0 || index >= self.dataArray.count) {
  193. return;
  194. }
  195. CGXVerticalMenuBaseModel *cellModel = self.dataArray[index];
  196. [self refreshCellModel:cellModel index:index];
  197. CGXVerticalMenuBaseCell *cell = (CGXVerticalMenuBaseCell *)[self.collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:index]];
  198. [cell reloadData:cellModel];
  199. }
  200. /*
  201. // Only override drawRect: if you perform custom drawing.
  202. // An empty implementation adversely affects performance during animation.
  203. - (void)drawRect:(CGRect)rect {
  204. // Drawing code
  205. }
  206. */
  207. @end
  208. @implementation CGXVerticalMenuBaseView (BaseHooks)
  209. - (UICollectionViewFlowLayout *)preferredFlowLayout
  210. {
  211. UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
  212. layout.scrollDirection = UICollectionViewScrollDirectionVertical;
  213. return layout;
  214. }
  215. - (Class)preferredCellClass
  216. {
  217. return CGXVerticalMenuBaseCell.class;
  218. }
  219. - (void)initializeData
  220. {
  221. self.dataArray = [NSMutableArray array];
  222. self.selectedIndex = 0;
  223. self.showsVerticalScrollIndicator = NO;
  224. }
  225. - (void)refreshCellModel:(CGXVerticalMenuBaseModel *)cellModel index:(NSInteger)index
  226. {
  227. }
  228. /**
  229. 选中某个item时,刷新将要选中与取消选中的cellModel
  230. @param selectedCellModel 将要选中的cellModel
  231. @param unselectedCellModel 取消选中的cellModel
  232. */
  233. - (void)refreshSelectedCellModel:(CGXVerticalMenuBaseModel *)selectedCellModel unselectedCellModel:(CGXVerticalMenuBaseModel *)unselectedCellModel
  234. {
  235. selectedCellModel.selected = YES;
  236. unselectedCellModel.selected = NO;
  237. }
  238. @end