HDMultipleScrollListView.m 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. //
  2. // HDMultipleScrollListView.m
  3. // HDCollectionView_Example
  4. //
  5. // Created by HaoDong chen on 2019/5/20.
  6. // Copyright © 2019 donggelaile. All rights reserved.
  7. //
  8. #import "HDMultipleScrollListView.h"
  9. #import "HDCollectionView+MultipleScroll.h"
  10. #import "HDMultipleScrollListSubVC.h"
  11. #import <objc/runtime.h>
  12. @implementation HDMultipleScrollListViewTitleHeader
  13. - (void)layoutSubviews
  14. {
  15. [super layoutSubviews];
  16. if (![self.subviews containsObject:[self rootView].jxTitle]) {
  17. [self insertSubview:self.rootView.jxTitle atIndex:0];
  18. }
  19. self.rootView.jxTitle.frame = self.bounds;
  20. }
  21. - (void)updateSecVUI:(__kindof HDSectionModel *)model
  22. {
  23. }
  24. - (HDMultipleScrollListView *)rootView
  25. {
  26. HDMultipleScrollListView *resultView;
  27. if (!resultView) {
  28. UIView *view = self;
  29. while (view!=nil && ![view isKindOfClass:NSClassFromString(@"HDMultipleScrollListView")]) {
  30. view = view.superview;
  31. }
  32. resultView = (HDMultipleScrollListView*)view;
  33. }
  34. return resultView;
  35. }
  36. @end
  37. @interface HDMultipleScrollListViewContentCell : HDCollectionCell
  38. @end
  39. @implementation HDMultipleScrollListViewContentCell
  40. - (void)updateCellUI:(__kindof HDCellModel *)model
  41. {
  42. [self.contentView.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  43. [obj removeFromSuperview];
  44. }];
  45. HDMultipleScrollListSubVC <HDMultipleScrollListViewScrollViewDidScroll>*VC = model.orgData;
  46. __weak typeof(self) weakSelf = self;
  47. if ([VC isKindOfClass:[UIViewController class]] && [VC respondsToSelector:@selector(HDMultipleScrollListViewScrollViewDidScroll:)]) {
  48. [VC HDMultipleScrollListViewScrollViewDidScroll:^(UIScrollView * _Nonnull sc) {
  49. if ([sc isKindOfClass:[UIScrollView class]]) {
  50. [weakSelf hd_setSubScrollViewDidScrollCallback:sc];
  51. }
  52. }];
  53. VC.view.frame = self.bounds;
  54. [self.contentView addSubview:VC.view];
  55. }
  56. if ([VC isKindOfClass:[HDMultipleScrollListSubVC class]]) {
  57. //监听主HDCollectionView的滑动回调
  58. HDMultipleScrollListView *rootView = [self rootView];
  59. [rootView.mainCollecitonV hd_autoDealScrollViewDidScrollEvent:self.superCollectionV topH:[self topH]];
  60. }
  61. }
  62. - (void)hd_setSubScrollViewDidScrollCallback:(UIScrollView *)sc
  63. {
  64. UIScrollView *mainRealSc = [self mainScrollV];
  65. HDCollectionView *mainHDCV = [self rootView].mainCollecitonV;
  66. [mainHDCV setCurrentSubSc:sc];
  67. CGFloat topH = [self topH];
  68. if (mainRealSc.contentOffset.y < topH) {
  69. sc.contentOffset = CGPointMake(0, -sc.contentInset.top);
  70. }else{
  71. mainRealSc.contentOffset = CGPointMake(mainRealSc.contentOffset.x, topH);
  72. }
  73. }
  74. - (UIScrollView*)mainScrollV
  75. {
  76. HDMultipleScrollListView *rootView = [self rootView];
  77. UIScrollView *mainRealSc = rootView.mainCollecitonV.collectionV;
  78. return mainRealSc;
  79. }
  80. - (CGFloat)topH
  81. {
  82. HDMultipleScrollListView *rootView = [self rootView];
  83. NSIndexPath *titleHeaderIndexP = [NSIndexPath indexPathWithIndex:rootView.confingers.topSecArr.count];
  84. UICollectionViewLayoutAttributes*titleHeaderAtt = [rootView.mainCollecitonV.collectionV layoutAttributesForSupplementaryElementOfKind:UICollectionElementKindSectionHeader atIndexPath:titleHeaderIndexP];
  85. CGFloat titleHeaderY = titleHeaderAtt.frame.origin.y;
  86. UIScrollView *mainRealSc = rootView.mainCollecitonV.collectionV;
  87. CGFloat topH = [self convertRect:self.frame toView:mainRealSc].origin.y;
  88. if (rootView.confingers.isHeaderNeedStop) {
  89. topH = titleHeaderY;
  90. }
  91. return topH;
  92. }
  93. - (HDMultipleScrollListView*)rootView
  94. {
  95. HDMultipleScrollListView *resultView;
  96. if (!resultView) {
  97. UIView *view = self;
  98. while (view!=nil && ![view isKindOfClass:NSClassFromString(@"HDMultipleScrollListView")]) {
  99. view = view.superview;
  100. }
  101. resultView = (HDMultipleScrollListView*)view;
  102. }
  103. return resultView;
  104. }
  105. @end
  106. @interface HDMultipleScrollListViewContentHeader:HDSectionView
  107. @property (nonatomic, strong) HDCollectionView *contentCV;
  108. @end
  109. @implementation HDMultipleScrollListViewContentHeader
  110. - (instancetype)initWithFrame:(CGRect)frame
  111. {
  112. self = [super initWithFrame:frame];
  113. if (self) {
  114. self.contentCV = [HDCollectionView hd_makeHDCollectionView:^(HDCollectionViewMaker *maker) {
  115. maker
  116. .hd_scrollDirection(UICollectionViewScrollDirectionHorizontal)
  117. .hd_isCalculateCellHOnCommonModes(YES);
  118. }];
  119. self.contentCV.collectionV.pagingEnabled = YES;
  120. self.contentCV.collectionV.bounces = NO;
  121. if (@available(iOS 11.0, *)) {
  122. _contentCV.collectionV.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
  123. } else {
  124. // Fallback on earlier versions
  125. }
  126. [self addSubview:self.contentCV];
  127. }
  128. __hd_WeakSelf
  129. [self.contentCV hd_setShouldRecognizeSimultaneouslyWithGestureRecognizer:^BOOL(UIGestureRecognizer *selfGestture, UIGestureRecognizer *otherGesture) {
  130. return [weakSelf dealFullScrrenBackGesture:otherGesture];
  131. }];
  132. return self;
  133. }
  134. - (BOOL)dealFullScrrenBackGesture:(UIGestureRecognizer*)otherGes
  135. {
  136. BOOL isRes = NO;
  137. NSInteger curPage = self.contentCV.collectionV.contentOffset.x/self.contentCV.frame.size.width;
  138. if (curPage == 0) {
  139. if ([otherGes isKindOfClass:[UIPanGestureRecognizer class]] &&
  140. [otherGes.view isKindOfClass:NSClassFromString(@"UILayoutContainerView")]) {
  141. isRes = YES;
  142. }
  143. }
  144. return isRes;
  145. }
  146. - (void)updateSecVUI:(__kindof HDSectionModel *)model
  147. {
  148. HDSectionModel *firstSec = [self.contentCV.innerAllData firstObject];
  149. if (!firstSec.sectionDataArr.count) {
  150. [self.contentCV hd_setAllDataArr:model.headerObj];
  151. }
  152. [self rootView].jxTitle.contentScrollView = self.contentCV.collectionV;
  153. }
  154. - (HDMultipleScrollListView*)rootView
  155. {
  156. HDMultipleScrollListView *resultView;
  157. if (!resultView) {
  158. UIView *view = self;
  159. while (view!=nil && ![view isKindOfClass:NSClassFromString(@"HDMultipleScrollListView")]) {
  160. view = view.superview;
  161. }
  162. resultView = (HDMultipleScrollListView*)view;
  163. }
  164. return resultView;
  165. }
  166. - (void)layoutSubviews
  167. {
  168. [super layoutSubviews];
  169. self.contentCV.frame = self.bounds;
  170. }
  171. @end
  172. #pragma mark - configer
  173. @implementation HDMultipleScrollListConfiger
  174. @end
  175. @interface HDMultipleScrollListView()
  176. {
  177. void(^configFinishGlobal)(HDMultipleScrollListConfiger*);
  178. }
  179. @property (nonatomic, strong) NSMutableArray *finalSecArr;
  180. @end
  181. #pragma mark - HDMultipleScrollListView
  182. @implementation HDMultipleScrollListView
  183. {
  184. CGRect lastViewFrame;
  185. }
  186. @synthesize mainCollecitonV = _mainCollecitonV,jxTitle = _jxTitle, jxLineView = _jxLineView, confingers = _confingers;
  187. - (instancetype)init
  188. {
  189. self = [super init];
  190. if (self) {
  191. }
  192. lastViewFrame = CGRectZero;
  193. return self;
  194. }
  195. - (instancetype)initWithFrame:(CGRect)frame
  196. {
  197. self = [super initWithFrame:frame];
  198. if (self) {
  199. }
  200. lastViewFrame = CGRectZero;
  201. return self;
  202. }
  203. - (NSMutableArray *)finalSecArr
  204. {
  205. if (!_finalSecArr) {
  206. _finalSecArr = @[].mutableCopy;
  207. }
  208. return _finalSecArr;
  209. }
  210. - (JXCategoryTitleView *)jxTitle
  211. {
  212. if (!_jxTitle) {
  213. _jxTitle = [[JXCategoryTitleView alloc] init];
  214. _jxTitle.indicators = @[self.jxLineView];
  215. _jxTitle.backgroundColor = [UIColor whiteColor];
  216. }
  217. return _jxTitle;
  218. }
  219. - (JXCategoryIndicatorLineView *)jxLineView
  220. {
  221. if (!_jxLineView) {
  222. _jxLineView = [[JXCategoryIndicatorLineView alloc] init];
  223. _jxLineView.indicatorHeight = 2;
  224. _jxLineView.indicatorCornerRadius = JXCategoryViewAutomaticDimension;
  225. }
  226. return _jxLineView;
  227. }
  228. - (HDCollectionView *)mainCollecitonV
  229. {
  230. if (!_mainCollecitonV) {
  231. _mainCollecitonV = [HDCollectionView hd_makeHDCollectionView:^(HDCollectionViewMaker *maker) {
  232. maker.hd_isNeedTopStop(YES)
  233. .hd_isCalculateCellHOnCommonModes(YES);
  234. }];
  235. // _mainCollecitonV.collectionV.bounces = NO;
  236. _mainCollecitonV.collectionV.showsVerticalScrollIndicator = NO;
  237. _mainCollecitonV.collectionV.showsHorizontalScrollIndicator = NO;
  238. if (@available(iOS 11.0, *)) {
  239. _mainCollecitonV.collectionV.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
  240. } else {
  241. // Fallback on earlier versions
  242. }
  243. //让主滑动view contentSize不至于过小,从而存在一个滑动惯性。
  244. //这样可以使顶部高度过低时,从底部滑动到顶部时不卡顿
  245. _mainCollecitonV.collectionV.contentInset = UIEdgeInsetsMake(HDMainDefaultTopEdge, 0, 0, 0);
  246. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  247. self->_mainCollecitonV.collectionV.contentOffset=CGPointZero;
  248. });
  249. //初始化时仅保证大于0
  250. [_mainCollecitonV hd_setScrollViewDidScrollCallback:^(UIScrollView *scrollView) {
  251. if (scrollView.contentOffset.y<0) {
  252. scrollView.contentOffset = CGPointZero;
  253. }
  254. }];
  255. }
  256. [self addSubview:_mainCollecitonV];
  257. _mainCollecitonV.collectionV.bounces = NO;
  258. return _mainCollecitonV;
  259. }
  260. - (void)layoutSubviews
  261. {
  262. [super layoutSubviews];
  263. self.mainCollecitonV.frame = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width, self.bounds.size.height);
  264. if (!CGRectEqualToRect(lastViewFrame, self.frame)) {
  265. [self updateData];
  266. }
  267. lastViewFrame = self.frame;
  268. }
  269. - (void)configWithConfiger:(void (^)(HDMultipleScrollListConfiger * _Nonnull configer))config
  270. {
  271. HDMultipleScrollListConfiger *configer = [HDMultipleScrollListConfiger new];
  272. if (config) {
  273. config(configer);
  274. }
  275. _confingers = configer;
  276. self.jxTitle.titles = configer.titles;
  277. if (configFinishGlobal) {
  278. configFinishGlobal(configer);
  279. }
  280. [self updateData];
  281. }
  282. - (void)configFinishCallback:(void (^)(HDMultipleScrollListConfiger * _Nonnull))configFinish
  283. {
  284. if (configFinish) {
  285. configFinishGlobal = configFinish;
  286. }
  287. }
  288. - (void)updateData
  289. {
  290. if (self.confingers.controllers.count != self.confingers.titles.count) {
  291. return;
  292. }
  293. self.finalSecArr = @[].mutableCopy;
  294. [self.finalSecArr addObjectsFromArray:self.confingers.topSecArr];
  295. if (self.confingers.controllers && self.confingers.controllers.count > 0) {
  296. [self addMiddleData];
  297. }
  298. [self.finalSecArr addObjectsFromArray:self.confingers.bottomSecArr];
  299. [self.mainCollecitonV hd_setAllDataArr:self.finalSecArr];
  300. }
  301. - (void)addMiddleData
  302. {
  303. [self.finalSecArr addObject:[self HDMultipleScrollListViewTitleHeaderSec]];
  304. [self.finalSecArr addObject:[self HDMultipleScrollListViewContentHeaderSec]];
  305. }
  306. - (HDSectionModel*)HDMultipleScrollListViewTitleHeaderSec
  307. {
  308. NSString *clsStr = @"HDMultipleScrollListViewTitleHeader";
  309. if (self.confingers.diyHeaderClsStr) {
  310. Class cls = NSClassFromString(self.confingers.diyHeaderClsStr);
  311. if ([cls isKindOfClass:object_getClass(NSClassFromString(clsStr))]) {
  312. clsStr = self.confingers.diyHeaderClsStr;
  313. }
  314. }
  315. HDSectionModel *titleSec = [self normalSecWithCellModelArr:nil headerSize:self.confingers.titleContentSize headerClsStr:clsStr autoCountCellH:NO];
  316. titleSec.headerObj = self.confingers.titles;;
  317. titleSec.headerTopStopType = self.confingers.isHeaderNeedStop?HDHeaderStopOnTopTypeNormal:HDHeaderStopOnTopTypeNone;
  318. return titleSec;
  319. }
  320. - (HDSectionModel*)HDMultipleScrollListViewContentHeaderSec
  321. {
  322. HDSectionModel *secModel = [self normalSecWithCellModelArr:@[].mutableCopy headerSize:[self realContentSize] headerClsStr:@"HDMultipleScrollListViewContentHeader" autoCountCellH:NO];
  323. secModel.headerObj = @[[self realContentSec]];
  324. secModel.headerTopStopType = HDHeaderStopOnTopTypeNormal;
  325. return secModel;
  326. }
  327. - (HDSectionModel *)realContentSec
  328. {
  329. //该段cell数据源
  330. static NSInteger index = 0;
  331. NSMutableArray *cellModelArr = @[].mutableCopy;
  332. NSInteger cellCount = self.confingers.controllers.count;
  333. for (int i =0; i<cellCount; i++) {
  334. UIViewController *vc = self.confingers.controllers[i];
  335. HDCellModel *model = [HDCellModel new];
  336. model.orgData = vc;
  337. model.cellSize = [self realContentSize];
  338. model.cellClassStr = @"HDMultipleScrollListViewContentCell";
  339. model.reuseIdentifier = [NSString stringWithFormat:@"HDMultipleScrollListViewContentCell_%zd",index];
  340. [cellModelArr addObject:model];
  341. index ++;
  342. }
  343. //该段layout
  344. HDYogaFlowLayout *layout = [HDYogaFlowLayout new];//isUseSystemFlowLayout为YES时只支持HDBaseLayout
  345. //该段的所有数据封装
  346. HDSectionModel *secModel = [HDSectionModel new];
  347. secModel.sectionDataArr = cellModelArr;
  348. secModel.layout = layout;
  349. return secModel;
  350. }
  351. - (CGSize)realContentSize {
  352. if (self.confingers.controllers && self.confingers.controllers.count > 0) {
  353. if (self.confingers.isHeaderNeedStop) {
  354. if (self.confingers.listHeight) {
  355. return CGSizeMake(self.mainCollecitonV.frame.size.width, self.confingers.listHeight);
  356. }else {
  357. return CGSizeMake(self.mainCollecitonV.frame.size.width, self.mainCollecitonV.frame.size.height - self.confingers.titleContentSize.height);
  358. }
  359. }else{
  360. return self.mainCollecitonV.frame.size;
  361. }
  362. }else {
  363. return CGSizeMake(self.mainCollecitonV.frame.size.width, 0);
  364. }
  365. }
  366. - (HDSectionModel*)normalSecWithCellModelArr:(NSArray*)cellModelArr headerSize:(CGSize)headerSize headerClsStr:(NSString*)headerClsStr autoCountCellH:(BOOL)autoCountCellH
  367. {
  368. //该段layout
  369. HDYogaFlowLayout *layout = [HDYogaFlowLayout new];//isUseSystemFlowLayout为YES时只支持HDBaseLayout
  370. layout.justify = YGJustifySpaceBetween;
  371. layout.headerSize = headerSize;
  372. //该段的所有数据封装
  373. HDSectionModel *secModel = [HDSectionModel new];
  374. secModel.sectionHeaderClassStr = headerClsStr;
  375. secModel.isNeedAutoCountCellHW = autoCountCellH;
  376. secModel.sectionDataArr = cellModelArr.mutableCopy;
  377. secModel.layout = layout;
  378. return secModel;
  379. }
  380. - (void)dealloc
  381. {
  382. }
  383. @end