WMZPageLoopView.m 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. //
  2. // WMZPageLoopView.m
  3. // WMZPageController
  4. //
  5. // Created by wmz on 2019/9/22.
  6. // Copyright © 2019 wmz. All rights reserved.
  7. //
  8. #import "WMZPageLoopView.h"
  9. #import "WMZPageController.h"
  10. @interface WMZPageLoopView()<UIScrollViewDelegate>
  11. {
  12. WMZPageNaviBtn *_btnLeft ;
  13. WMZPageNaviBtn *_btnRight;
  14. CGFloat lastContentOffset;
  15. WMZPageController *page;
  16. }
  17. //最底部下划线
  18. @property(nonatomic,strong)UIView *bottomView;
  19. @property(nonatomic,strong)WMZPageParam *param;
  20. //图文
  21. @property(nonatomic,assign)BOOL hasImage;
  22. //固定按钮
  23. @property(nonatomic,strong)WMZPageNaviBtn *fixBtn;
  24. @end
  25. @implementation WMZPageLoopView
  26. - (instancetype)initWithFrame:(CGRect)frame param:(WMZPageParam*)param{
  27. if (self = [super initWithFrame:frame]) {
  28. self.param = param;
  29. [self setUp];
  30. }
  31. return self;
  32. }
  33. - (void)setUp{
  34. //标题菜单
  35. NSDictionary *dic = @{
  36. @(PageMenuPositionLeft):[NSValue valueWithCGRect:CGRectMake(0, 0 , self.param.wMenuWidth,0)],
  37. @(PageMenuPositionRight):[NSValue valueWithCGRect:CGRectMake(PageVCWidth-self.param.wMenuWidth, 0 , self.param.wMenuWidth,0)],
  38. @(PageMenuPositionCenter):[NSValue valueWithCGRect:CGRectMake((PageVCWidth-self.param.wMenuWidth)/2, 0 , self.param.wMenuWidth,0)],
  39. @(PageMenuPositionNavi):[NSValue valueWithCGRect:CGRectMake((PageVCWidth-self.param.wMenuWidth)/2, 0 , self.param.wMenuWidth,0)],
  40. @(PageMenuPositionBottom):[NSValue valueWithCGRect:CGRectMake(0, PageVCHeight, self.param.wMenuWidth,0)],
  41. };
  42. if (!self.param.wNoMenu) {
  43. [self addSubview:self.mainView];
  44. self.mainView.frame = [dic[@(self.param.wMenuPosition)] CGRectValue] ;
  45. }
  46. [self addSubview:self.dataView];
  47. self.dataView.scrollEnabled = self.param.wScrollCanTransfer;
  48. self.dataView.contentSize = CGSizeMake(self.param.wTitleArr.count*PageVCWidth,0);
  49. self.dataView.delegate = self;
  50. self.currentTitleIndex = -1;
  51. NSMutableArray *heightArr = [NSMutableArray new];
  52. WMZPageNaviBtn *temp = nil;
  53. for (int i = 0; i<self.param.wTitleArr.count; i++) {
  54. WMZPageNaviBtn *btn = [WMZPageNaviBtn buttonWithType:UIButtonTypeCustom];
  55. [self setPropertiesWithBtn:btn withIndex:i withHeightArr:heightArr withTemp:temp];
  56. temp = btn;
  57. }
  58. //布局frame
  59. if (self.param.wMenuPosition == PageMenuPositionBottom) {
  60. CGRect rect = self.frame;
  61. rect.origin.y -= self.frame.size.height;
  62. if (pageIsIphoneX) {
  63. rect.size.height+=10;
  64. rect.origin.y-=10;
  65. }
  66. self.frame = rect;
  67. }
  68. //指示器
  69. [self setUpIndicator];
  70. //右边固定标题
  71. [self setUpFixRightBtn:temp];
  72. //最底部固定线
  73. if (self.param.wInsertMenuLine) {
  74. self.bottomView = [UIView new];
  75. self.bottomView.backgroundColor = PageColor(0x999999);
  76. self.bottomView.frame = CGRectMake(0, self.mainView.frame.size.height-PageK1px, self.mainView.frame.size.width, PageK1px);
  77. self.param.wInsertMenuLine(self.bottomView);
  78. }
  79. if (self.bottomView) {
  80. CGRect lineRect = self.bottomView.frame;
  81. lineRect.origin.y = self.mainView.frame.size.height- lineRect.size.height;
  82. if (!lineRect.size.width) {
  83. lineRect.size.width = self.mainView.frame.size.width;
  84. }
  85. self.bottomView.frame = lineRect;
  86. [self addSubview:self.bottomView];
  87. }
  88. if (!self.param.wMenuIndicatorY) {
  89. self.param.wMenuIndicatorY = self.param.wMenuCellPadding/4;
  90. }
  91. }
  92. //初始化指示器
  93. - (void)setUpIndicator{
  94. self.lineView = [UIButton buttonWithType:UIButtonTypeCustom];
  95. if (self.param.wMenuIndicatorImage) {
  96. [self.lineView setImage:[UIImage imageNamed:self.param.wMenuIndicatorImage] forState:UIControlStateNormal];
  97. }else{
  98. self.lineView.backgroundColor = self.param.wMenuIndicatorColor;
  99. }
  100. [self.mainView addSubview:self.lineView];
  101. if (self.param.wMenuAnimal == PageTitleMenuCircle) {
  102. self.lineView.userInteractionEnabled = NO;
  103. [self.mainView sendSubviewToBack:self.lineView];
  104. }
  105. self.lineView.hidden = (self.param.wMenuAnimal == PageTitleMenuNone||
  106. self.param.wMenuAnimal == PageTitleMenuTouTiao
  107. );
  108. if (self.param.wMenuIndicatorRadio) {
  109. self.lineView.layer.cornerRadius = self.param.wMenuIndicatorRadio;
  110. self.lineView.layer.masksToBounds = YES;
  111. }
  112. }
  113. //设置右边固定标题
  114. - (void)setUpFixRightBtn:(WMZPageNaviBtn*)temp{
  115. if (self.param.wMenuFixRightData) {
  116. WMZPageNaviBtn *fixBtn = [WMZPageNaviBtn buttonWithType:UIButtonTypeCustom];
  117. id text = [self getTitleData:self.param.wMenuFixRightData key:@"name"];
  118. id image = [self getTitleData:self.param.wMenuFixRightData key:@"image"];
  119. id selectImage = [self getTitleData:self.param.wMenuFixRightData key:@"selectImage"];
  120. if (text) {
  121. [fixBtn setTitle:text forState:UIControlStateNormal];
  122. }
  123. if (image) {
  124. [fixBtn setImage:[UIImage imageNamed:image] forState:UIControlStateNormal];
  125. }
  126. if (selectImage) {
  127. [fixBtn setImage:[UIImage imageNamed:selectImage] forState:UIControlStateSelected];
  128. }
  129. if (text && image) {
  130. [fixBtn TagSetImagePosition:self.param.wMenuImagePosition spacing:self.param.wMenuImageMargin];
  131. self.param.wMenuFixWidth+=30;
  132. }
  133. fixBtn.titleLabel.font = [UIFont systemFontOfSize:self.param.wMenuTitleFont weight:self.param.wMenuTitleWeight];
  134. [fixBtn setTitleColor:self.param.wMenuTitleColor forState:UIControlStateNormal];
  135. fixBtn.frame = CGRectMake(CGRectGetWidth(self.frame)-self.param.wMenuFixWidth, temp.frame.origin.y, self.param.wMenuFixWidth, temp.frame.size.height);
  136. fixBtn.tag = 10086;
  137. [self addSubview:fixBtn];
  138. [self bringSubviewToFront:fixBtn];
  139. if (self.param.wMenuFixShadow) {
  140. [fixBtn viewShadowPathWithColor:PageColor(0x333333) shadowOpacity:0.8 shadowRadius:3 shadowPathType:PageShadowPathLeft shadowPathWidth:2];
  141. fixBtn.alpha = 0.9;
  142. }
  143. [fixBtn setAdjustsImageWhenHighlighted:NO];
  144. [fixBtn addTarget:self action:@selector(fixTap:) forControlEvents:UIControlEventTouchUpInside];
  145. self.fixBtn = fixBtn;
  146. self.mainView.contentSize = CGSizeMake(self.mainView.contentSize.width+self.param.wMenuFixWidth, 0);
  147. [self.btnArr addObject:fixBtn];
  148. }
  149. }
  150. //设置按钮样式
  151. - (void)setPropertiesWithBtn:(WMZPageNaviBtn*)btn withIndex:(int)i withHeightArr:(NSMutableArray*)heightArr withTemp:(WMZPageNaviBtn*)temp{
  152. CGFloat margin = self.param.wMenuCellMargin;
  153. CGFloat padding = self.param.wMenuCellPadding;
  154. btn.param = self.param;
  155. [btn setAdjustsImageWhenHighlighted:NO];
  156. [btn addTarget:self action:@selector(tap:) forControlEvents:UIControlEventTouchUpInside];
  157. id name = [self getTitleData:self.param.wTitleArr[i] key:@"name"];
  158. if (name) {
  159. [btn setTitle:name forState:UIControlStateNormal];
  160. }
  161. CGSize size = btn.maxSize;
  162. //设置图片
  163. id image = [self getTitleData:self.param.wTitleArr[i] key:@"image"];
  164. id selectImage = [self getTitleData:self.param.wTitleArr[i] key:@"selectImage"];
  165. if (image) {
  166. [btn setImage:[UIImage imageNamed:image] forState:UIControlStateNormal];
  167. btn.imageView.contentMode = UIViewContentModeScaleAspectFit;
  168. if (name) {
  169. [btn TagSetImagePosition:self.param.wMenuImagePosition spacing:self.param.wMenuImageMargin];
  170. self.hasImage = YES;
  171. }
  172. }
  173. if (image&&selectImage) {
  174. [btn setImage:[UIImage imageNamed:selectImage] forState:UIControlStateSelected];
  175. }
  176. if (size.width == 0 && image) {
  177. size.width = 20.0f;
  178. }
  179. if (size.height == 0 && image) {
  180. size.height = 20.0f;
  181. }
  182. btn.maxSize = size;
  183. if (self.hasImage) {
  184. if (self.param.wMenuImagePosition == PageBtnPositionLeft || self.param.wMenuImagePosition == PageBtnPositionRight ) {
  185. margin+=20;
  186. margin+=self.param.wMenuImageMargin;
  187. }
  188. if (self.param.wMenuImagePosition == PageBtnPositionTop || self.param.wMenuImagePosition == PageBtnPositionBottom ) {
  189. padding+=20;
  190. padding+=self.param.wMenuImageMargin;
  191. btn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
  192. btn.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
  193. }
  194. }
  195. btn.titleLabel.font = [UIFont systemFontOfSize:self.param.wMenuTitleFont weight:self.param.wMenuTitleWeight];
  196. id selectColor = [self getTitleData:self.param.wTitleArr[i] key:@"titleSelectColor"];
  197. [btn setTitleColor:selectColor?:self.param.wMenuTitleSelectColor forState:UIControlStateSelected];
  198. [btn setTitleColor:self.param.wMenuTitleColor forState:UIControlStateNormal];
  199. btn.tag = i;
  200. if (self.param.wNoMenu) {
  201. btn.frame =CGRectZero;
  202. }else{
  203. btn.frame = CGRectMake(temp?(CGRectGetMaxX(temp.frame)+self.param.wMenuTitleOffset):0, self.param.wMenuCellMarginY, self.param.wMenuTitleWidth?:size.width + margin, size.height + padding);
  204. }
  205. [heightArr addObject:@(btn.frame.size.height+self.param.wMenuCellMarginY)];
  206. [self.mainView addSubview:btn];
  207. [self.btnArr addObject:btn];
  208. //设置右上角红点
  209. if ([self getTitleData:self.param.wTitleArr[i] key:@"badge"]) {
  210. [btn showBadgeWithTopMagin:0];
  211. }
  212. if (self.param.wMenuPosition != PageMenuPositionNavi) {
  213. btn.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
  214. btn.titleLabel.textAlignment = NSTextAlignmentCenter;
  215. }
  216. //设置富文本
  217. id wrapColor = [self getTitleData:self.param.wTitleArr[i] key:@"wrapColor"];
  218. id firstColor = [self getTitleData:self.param.wTitleArr[i] key:@"firstColor"];
  219. if ([btn.titleLabel.text containsString:@"\n"]&&(wrapColor||firstColor)) {
  220. NSMutableAttributedString *mStr = [[NSMutableAttributedString alloc] initWithString:btn.titleLabel.text];
  221. NSMutableAttributedString *mSelectStr = [[NSMutableAttributedString alloc] initWithString:btn.titleLabel.text];
  222. [mSelectStr addAttribute:NSForegroundColorAttributeName value:self.param.wMenuTitleSelectColor range:[btn.titleLabel.text rangeOfString:btn.titleLabel.text]];
  223. NSArray *array = [btn.titleLabel.text componentsSeparatedByString:@"\n"];
  224. if (wrapColor) {
  225. [mStr addAttribute:NSForegroundColorAttributeName value:wrapColor range:[btn.titleLabel.text rangeOfString:array[1]]];
  226. }
  227. if (firstColor) {
  228. [mStr addAttribute:NSForegroundColorAttributeName value:firstColor range:[btn.titleLabel.text rangeOfString:array[0]]];
  229. }
  230. [btn setAttributedTitle:mStr forState:UIControlStateNormal];
  231. [btn setAttributedTitle:mSelectStr forState:UIControlStateSelected];
  232. btn.attributed = YES;
  233. }
  234. //重新设置布局
  235. if (i == (self.param.wTitleArr.count -1)) {
  236. if (CGRectGetMaxX(btn.frame) <= self.frame.size.width) {
  237. self.mainView.scrollEnabled = NO;
  238. }else{
  239. self.mainView.scrollEnabled = YES;
  240. }
  241. float max =[[heightArr valueForKeyPath:@"@max.floatValue"] floatValue];
  242. [self.mainView page_height:max];
  243. self.mainView.contentSize = CGSizeMake(CGRectGetMaxX(btn.frame), 0);
  244. }
  245. }
  246. //解析字典
  247. - (NSString*)getTitleData:(id)model key:(NSString*)key{
  248. if ([model isKindOfClass:[NSString class]]) {
  249. return [key isEqualToString:@"name"]?model:nil;
  250. }else if ([model isKindOfClass:[NSDictionary class]]) {
  251. return [model objectForKey:key]?:nil;
  252. }
  253. return nil;
  254. }
  255. //点击
  256. - (void)tap:(UIButton*)btn{
  257. if (!self.first) {
  258. if (self.param.wEventClick) {
  259. self.param.wEventClick(btn, btn.tag);
  260. }
  261. }
  262. if (self.currentTitleIndex == btn.tag) return;
  263. NSInteger index = btn.tag;
  264. if (self.loopDelegate&&[self.loopDelegate respondsToSelector:@selector(selectBtnWithIndex:)]) {
  265. [self.loopDelegate selectBtnWithIndex:index];
  266. }
  267. if (self.first) {
  268. self.lastPageIndex = self.currentTitleIndex;
  269. self.nextPageIndex = index;
  270. self.currentTitleIndex = index;
  271. UIViewController *newVC = [self getVCWithIndex:index];
  272. [newVC beginAppearanceTransition:YES animated:YES];
  273. [self addChildVC:index VC:newVC];
  274. self.dataView.contentOffset = CGPointMake(index*PageVCWidth, 0);
  275. [newVC endAppearanceTransition];
  276. if (self.loopDelegate&&[self.loopDelegate respondsToSelector:@selector(setUpSuspension:index:end:)]) {
  277. [self.loopDelegate setUpSuspension:newVC index:index end:YES];
  278. }
  279. self.first = NO;
  280. }else{
  281. [self beginAppearanceTransitionWithIndex:index withOldIndex:self.currentTitleIndex];
  282. self.lastPageIndex = self.currentTitleIndex;
  283. self.nextPageIndex = index;
  284. self.currentTitleIndex = index;
  285. [self endAppearanceTransitionWithIndex:self.nextPageIndex withOldIndex:self.lastPageIndex isFlag:NO];
  286. self.dataView.contentOffset = CGPointMake(index*PageVCWidth, 0);
  287. }
  288. [self scrollToIndex:index];
  289. }
  290. //固定标题点击
  291. - (void)fixTap:(UIButton*)btn{
  292. btn.selected = ![btn isSelected];
  293. if (self.param.wEventFixedClick) {
  294. self.param.wEventFixedClick(btn, btn.tag);
  295. }
  296. }
  297. //滚动到中间
  298. - (void)scrollToIndex:(NSInteger)newIndex{
  299. WMZPageNaviBtn *btn = self.btnArr[newIndex] ;
  300. //隐藏右上角红点
  301. [btn hidenBadge];
  302. //改变背景色
  303. id backgroundColor = [self getTitleData:self.param.wTitleArr[newIndex] key:@"backgroundColor"];
  304. //改变指示器颜色
  305. id indicatorColor = [self getTitleData:self.param.wTitleArr[newIndex] key:@"indicatorColor"];
  306. //改变其他未选中标题的颜色
  307. id titleColor = [self getTitleData:self.param.wTitleArr[newIndex] key:@"titleColor"];
  308. //改变标题颜色
  309. for (WMZPageNaviBtn *temp in self.btnArr) {
  310. temp.selected = (temp.tag == newIndex ?YES:NO);
  311. if ([temp isSelected]) {
  312. UIColor *tempBackgroundColor = self.param.wMenuBgColor;
  313. UIColor *fixBackgroundColor = self.param.wMenuBgColor;
  314. if (backgroundColor) {
  315. //渐变色
  316. if ([backgroundColor isKindOfClass:[NSArray class]]) {
  317. if ([(NSArray *)backgroundColor count] == 2) {
  318. tempBackgroundColor = [UIColor bm_colorGradientChangeWithSize:self.mainView.frame.size direction:PageGradientChangeDirectionLevel startColor:backgroundColor[0] endColor:backgroundColor[1]];
  319. fixBackgroundColor = backgroundColor[1];
  320. }else{
  321. tempBackgroundColor = backgroundColor[0];
  322. fixBackgroundColor = tempBackgroundColor;
  323. }
  324. }
  325. else if ([backgroundColor isKindOfClass:[UIColor class]]){
  326. tempBackgroundColor = backgroundColor;
  327. fixBackgroundColor = tempBackgroundColor;
  328. }
  329. }
  330. self.backgroundColor = tempBackgroundColor;
  331. if (!self.param.wMenuIndicatorImage) {
  332. self.lineView.backgroundColor = indicatorColor?:self.param.wMenuIndicatorColor;
  333. }
  334. self.fixBtn.backgroundColor = fixBackgroundColor;
  335. [self.fixBtn setTitleColor:titleColor?:self.param.wMenuTitleColor forState:UIControlStateNormal];
  336. if (self.param.wMenuAnimalTitleBig) {
  337. temp.titleLabel.font = [UIFont systemFontOfSize:self.param.wMenuTitleSelectFont weight:self.param.wMenuTitleWeight];
  338. }
  339. }else{
  340. [temp setTitleColor:titleColor?:self.param.wMenuTitleColor forState:UIControlStateNormal];
  341. if (self.param.wMenuAnimalTitleBig) {
  342. temp.titleLabel.font = [UIFont systemFontOfSize:self.param.wMenuTitleFont weight:self.param.wMenuTitleWeight];
  343. }
  344. }
  345. }
  346. //滚动到中间
  347. CGFloat centerX = self.mainView.frame.size.width/2 ;
  348. CGRect indexFrame = btn.frame;
  349. CGFloat contenSize = self.mainView.contentSize.width;
  350. CGPoint point = CGPointZero;
  351. if (indexFrame.origin.x<= centerX) {
  352. point = CGPointMake(0, 0);
  353. }else if (CGRectGetMaxX(indexFrame) > (contenSize-centerX)) {
  354. point = CGPointMake(self.mainView.contentSize.width-self.mainView.frame.size.width , 0);
  355. }else{
  356. point = CGPointMake(CGRectGetMaxX(indexFrame) - centerX- indexFrame.size.width/2, 0);
  357. }
  358. if ([self.mainView isScrollEnabled]) {
  359. [UIView animateWithDuration:0.25f animations:^(void){
  360. [self.mainView setContentOffset:point];
  361. }];
  362. }
  363. CGFloat dataWidth = btn.titleLabel.frame.size.width?:btn.maxSize.width;
  364. //改变指示器frame
  365. CGRect lineRect = indexFrame;
  366. lineRect.size.height = self.param.wMenuIndicatorHeight?:PageK1px;
  367. lineRect.origin.y = self.mainView.frame.size.height - lineRect.size.height/2 - self.param.wMenuIndicatorY;
  368. lineRect.size.width = self.param.wMenuIndicatorWidth?:(dataWidth+10);
  369. lineRect.origin.x = (indexFrame.size.width - lineRect.size.width)/2 + indexFrame.origin.x;
  370. if (self.param.wMenuAnimal == PageTitleMenuYouKu) {
  371. lineRect.size.height = lineRect.size.width;
  372. self.lineView.layer.masksToBounds = YES;
  373. self.lineView.layer.cornerRadius = lineRect.size.height/2;
  374. }
  375. if (self.param.wMenuAnimal == PageTitleMenuPDD) {
  376. lineRect.origin.y = self.frame.size.height - lineRect.size.height;
  377. lineRect.size.width = self.param.wMenuIndicatorWidth?:dataWidth;
  378. lineRect.origin.x = (indexFrame.size.width - lineRect.size.width)/2 + indexFrame.origin.x;
  379. }
  380. if (self.param.wMenuAnimal == PageTitleMenuCircle) {
  381. lineRect = indexFrame;
  382. lineRect.origin.x = lineRect.origin.x - 2;
  383. lineRect.origin.y = lineRect.origin.y + 4;
  384. lineRect.size.width = lineRect.size.width + 4;
  385. lineRect.size.height = lineRect.size.height - 8 ;
  386. self.lineView.layer.masksToBounds = YES;
  387. self.lineView.layer.cornerRadius = lineRect.size.height/2;
  388. }
  389. [UIView animateWithDuration:0.1 animations:^{
  390. self.lineView.frame = lineRect;
  391. } completion:^(BOOL finished) {
  392. }];
  393. self.currentTitleIndex = newIndex;
  394. if (self.param.wInsertHeadAndMenuBg) {
  395. self.backgroundColor = [UIColor clearColor];
  396. }
  397. if (self.param.wCustomMenuSelectTitle) {
  398. self.param.wCustomMenuSelectTitle(self.btnArr);
  399. }
  400. }
  401. #pragma -mark- scrollerDeleagte
  402. - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
  403. if (scrollView != self.dataView) return;
  404. lastContentOffset = scrollView.contentOffset.x;
  405. }
  406. - (void)scrollViewDidScroll:(UIScrollView *)scrollView{
  407. if (scrollView != self.dataView) return;
  408. if (![scrollView isDecelerating]&&![scrollView isDragging]) return;
  409. if (scrollView.contentOffset.x>0 &&scrollView.contentOffset.x<=self.btnArr.count*PageVCWidth ) {
  410. [self lifeCycleManage:scrollView];
  411. [self animalAction:scrollView lastContrnOffset:lastContentOffset];
  412. }
  413. if (scrollView.contentOffset.y == 0) return;
  414. CGPoint contentOffset = scrollView.contentOffset;
  415. contentOffset.y = 0.0;
  416. scrollView.contentOffset = contentOffset;
  417. }
  418. - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
  419. if (scrollView != self.dataView) return;
  420. if (!decelerate) {
  421. [self endAninamal];
  422. NSInteger newIndex = scrollView.contentOffset.x/PageVCWidth;
  423. self.currentTitleIndex = newIndex;
  424. if (self.loopDelegate && [self.loopDelegate respondsToSelector:@selector(pageScrollEndWithScrollView:)]) {
  425. [self.loopDelegate pageScrollEndWithScrollView:scrollView];
  426. }
  427. }
  428. }
  429. - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
  430. if (scrollView != self.dataView) return;
  431. [self endAninamal];
  432. NSInteger newIndex = scrollView.contentOffset.x/PageVCWidth;
  433. self.currentTitleIndex = newIndex;
  434. if (!self.hasEndAppearance) {
  435. [self endAppearanceTransitionWithIndex:self.nextPageIndex withOldIndex:self.lastPageIndex isFlag:NO];
  436. }
  437. self.hasEndAppearance = NO;
  438. [self scrollToIndex:newIndex];
  439. if (self.loopDelegate && [self.loopDelegate respondsToSelector:@selector(pageScrollEndWithScrollView:)]) {
  440. [self.loopDelegate pageScrollEndWithScrollView:scrollView];
  441. }
  442. }
  443. //管理生命周期
  444. - (void)lifeCycleManage:(UIScrollView*)scrollView{
  445. CGFloat diffX = scrollView.contentOffset.x - lastContentOffset;
  446. if (diffX < 0) {
  447. self.currentTitleIndex = ceil(scrollView.contentOffset.x/PageVCWidth);
  448. }else{
  449. self.currentTitleIndex = (scrollView.contentOffset.x/PageVCWidth);
  450. }
  451. if (self.loopDelegate && [self.loopDelegate respondsToSelector:@selector(pageWithScrollView:left:)]) {
  452. [self.loopDelegate pageWithScrollView:scrollView left:(diffX < 0)];
  453. }
  454. if (diffX > 0) {
  455. if (self.hasDealAppearance&&self.nextPageIndex == self.currentTitleIndex) {
  456. self.hasEndAppearance = YES;
  457. [self endAppearanceTransitionWithIndex:self.nextPageIndex withOldIndex:self.currentTitleIndex-1 isFlag:YES];
  458. [self endAninamal];
  459. return;
  460. }
  461. if (!self.hasDealAppearance || self.nextPageIndex != self.currentTitleIndex + 1) {
  462. self.hasDealAppearance = YES;
  463. if (self.nextPageIndex == self.currentTitleIndex - 1) {
  464. [self endAppearanceTransitionWithIndex:self.nextPageIndex withOldIndex:self.currentTitleIndex isFlag:NO];
  465. self.hasDifferenrDirection = YES;
  466. }
  467. self.nextPageIndex = self.currentTitleIndex + 1;
  468. self.lastPageIndex = self.currentTitleIndex ;
  469. [self beginAppearanceTransitionWithIndex:self.nextPageIndex withOldIndex:self.currentTitleIndex];
  470. }
  471. }else if(diffX < 0){
  472. if (self.hasDealAppearance&&self.nextPageIndex == self.currentTitleIndex) {
  473. self.hasEndAppearance = YES;
  474. [self endAppearanceTransitionWithIndex:self.nextPageIndex withOldIndex:self.currentTitleIndex+1 isFlag:YES];
  475. [self endAninamal];
  476. return;
  477. }
  478. if (!self.hasDealAppearance || self.nextPageIndex != self.currentTitleIndex - 1) {
  479. self.hasDealAppearance = YES;
  480. if (self.nextPageIndex == self.currentTitleIndex + 1) {
  481. [self endAppearanceTransitionWithIndex:self.nextPageIndex withOldIndex:self.currentTitleIndex isFlag:NO];
  482. self.hasDifferenrDirection = YES;
  483. }
  484. self.nextPageIndex = self.currentTitleIndex - 1;
  485. self.lastPageIndex = self.currentTitleIndex ;
  486. [self beginAppearanceTransitionWithIndex:self.nextPageIndex withOldIndex:self.currentTitleIndex];
  487. }
  488. }
  489. }
  490. - (UIViewController*)getVCWithIndex:(NSInteger)index{
  491. if (index < 0|| index >= self.param.wControllers.count) {
  492. return nil;
  493. }
  494. if ([[self findBelongViewControllerForView:self].cache objectForKey:@(index)]) {
  495. return [[self findBelongViewControllerForView:self].cache objectForKey:@(index)];
  496. }
  497. return self.param.wControllers[index];
  498. }
  499. - (void)beginAppearanceTransitionWithIndex:(NSInteger)index withOldIndex:(NSInteger)old{
  500. UIViewController *newVC = [self getVCWithIndex:index];
  501. UIViewController *oldVC = [self getVCWithIndex:old];
  502. if (!newVC||!oldVC||(index==old)) return;
  503. [newVC beginAppearanceTransition:YES animated:YES];
  504. [self addChildVC:index VC:newVC];
  505. [oldVC beginAppearanceTransition:NO animated:YES];
  506. self.currentVC = newVC;
  507. if (self.loopDelegate&&[self.loopDelegate respondsToSelector:@selector(setUpSuspension:index:end:)]) {
  508. [self.loopDelegate setUpSuspension:newVC index:index end:NO];
  509. }
  510. if (self.param.wEventBeganTransferController) {
  511. self.param.wEventBeganTransferController(oldVC, newVC, old, index);
  512. }
  513. }
  514. - (void)addChildVC:(NSInteger)index VC:(UIViewController*)newVC{
  515. if (![[self findBelongViewControllerForView:self].childViewControllers containsObject:newVC]) {
  516. [[self findBelongViewControllerForView:self] addChildViewController:newVC];
  517. newVC.view.frame = [[self findBelongViewControllerForView:self].rectArr[index] CGRectValue];
  518. [self.dataView addSubview:newVC.view];
  519. [newVC didMoveToParentViewController:[self findBelongViewControllerForView:self]];
  520. [[self findBelongViewControllerForView:self].cache setObject:newVC forKey:@(index)];
  521. }
  522. }
  523. - (void)endAppearanceTransitionWithIndex:(NSInteger)index withOldIndex:(NSInteger)old isFlag:(BOOL)flag{
  524. UIViewController *newVC = [self getVCWithIndex:index];
  525. UIViewController *oldVC = [self getVCWithIndex:old];
  526. if (!newVC||!oldVC||(index==old)) return;
  527. if (self.currentTitleIndex == self.nextPageIndex) {
  528. [oldVC willMoveToParentViewController:nil];
  529. [oldVC.view removeFromSuperview];
  530. [oldVC removeFromParentViewController];
  531. [newVC endAppearanceTransition];
  532. [oldVC endAppearanceTransition];
  533. if (flag&&self.hasDifferenrDirection) {
  534. [newVC endAppearanceTransition];
  535. [oldVC endAppearanceTransition];
  536. self.hasDifferenrDirection = NO;
  537. }
  538. if (self.param.wEventEndTransferController) {
  539. self.param.wEventEndTransferController(oldVC, newVC, old, index);
  540. }
  541. self.currentVC = newVC;
  542. self.currentTitleIndex = index;
  543. if (self.loopDelegate&&[self.loopDelegate respondsToSelector:@selector(setUpSuspension:index:end:)]) {
  544. [self.loopDelegate setUpSuspension:newVC index:index end:YES];
  545. }
  546. }else{
  547. [newVC willMoveToParentViewController:nil];
  548. [newVC.view removeFromSuperview];
  549. [newVC removeFromParentViewController];
  550. [oldVC beginAppearanceTransition:YES animated:YES];
  551. [oldVC endAppearanceTransition];
  552. [newVC beginAppearanceTransition:NO animated:YES];
  553. [newVC endAppearanceTransition];
  554. if (self.param.wEventEndTransferController) {
  555. self.param.wEventEndTransferController(newVC, oldVC, index, old);
  556. }
  557. self.currentVC = oldVC;
  558. self.currentTitleIndex = old;
  559. if (self.loopDelegate&&[self.loopDelegate respondsToSelector:@selector(setUpSuspension:index:end:)]) {
  560. [self.loopDelegate setUpSuspension:oldVC index:old end:YES];
  561. }
  562. }
  563. self.hasDealAppearance = NO;
  564. self.nextPageIndex = -999;
  565. }
  566. - (BOOL)canTopSuspension{
  567. if (!self.param.wTopSuspension
  568. ||self.param.wMenuPosition == PageMenuPositionBottom
  569. ||self.param.wMenuPosition == PageMenuPositionNavi){
  570. return NO;
  571. }
  572. return YES;
  573. }
  574. //动画管理
  575. - (void)animalAction:(UIScrollView*)scrollView lastContrnOffset:(CGFloat)lastContentOffset{
  576. CGFloat contentOffsetX = scrollView.contentOffset.x;
  577. CGFloat sWidth = PageVCWidth;
  578. CGFloat content_X = (contentOffsetX / sWidth);
  579. NSArray *arr = [[NSString stringWithFormat:@"%f",content_X] componentsSeparatedByString:@"."];
  580. int num = [arr[0] intValue];
  581. CGFloat scale = content_X - num;
  582. int selectIndex = contentOffsetX/sWidth;
  583. // 拖拽
  584. if (contentOffsetX <= lastContentOffset ){
  585. selectIndex = selectIndex+1;
  586. _btnRight = [self safeObjectAtIndex:selectIndex data:self.btnArr];
  587. _btnLeft = [self safeObjectAtIndex:selectIndex-1 data:self.btnArr];
  588. } else if (contentOffsetX > lastContentOffset ){
  589. _btnRight = [self safeObjectAtIndex:selectIndex+1 data:self.btnArr];
  590. _btnLeft = [self safeObjectAtIndex:selectIndex data:self.btnArr];
  591. }
  592. //跟随滑动
  593. if (self.param.wMenuAnimal == PageTitleMenuAiQY || self.param.wMenuAnimal == PageTitleMenuYouKu) {
  594. CGRect rect = self.lineView.frame;
  595. if (scale < 0.5 ) {
  596. rect.size.width = self.param.wMenuIndicatorWidth + ( _btnRight.center.x-_btnLeft.center.x) * scale*2;
  597. rect.origin.x = _btnLeft.center.x -self.param.wMenuIndicatorWidth/2;
  598. }else if(scale >= 0.5 ){
  599. rect.size.width = self.param.wMenuIndicatorWidth+(_btnRight.center.x-_btnLeft.center.x) * (1-scale)*2;
  600. rect.origin.x = _btnLeft.center.x + 2*(scale-0.5)*(_btnRight.center.x - _btnLeft.center.x)-self.param.wMenuIndicatorWidth/2;
  601. }
  602. if (rect.size.height!= (self.param.wMenuIndicatorHeight?:PageK1px)) {
  603. rect.size.height = self.param.wMenuIndicatorHeight?:PageK1px;
  604. }
  605. if (rect.origin.y != (self.mainView.frame.size.height-self.param.wMenuIndicatorY-rect.size.height/2)) {
  606. rect.origin.y = self.mainView.frame.size.height-self.param.wMenuIndicatorY-rect.size.height/2;
  607. }
  608. self.lineView.frame = rect;
  609. }
  610. //变大
  611. if (self.param.wMenuAnimalTitleBig) {
  612. _btnLeft.transform = CGAffineTransformMakeScale(1+(1-0.9)*(1-scale), 1+(1-0.9)*(1-scale));
  613. _btnRight.transform = CGAffineTransformMakeScale(1+(1-0.9)*scale, 1+(1-0.9)*scale);
  614. }
  615. //渐变
  616. if (self.param.wMenuAnimalTitleGradient) {
  617. WMZPageNaviBtn *tempBtn = _btnLeft?:_btnRight;
  618. CGFloat difR = tempBtn.selectedColorR - tempBtn.unSelectedColorR;
  619. CGFloat difG = tempBtn.selectedColorG - tempBtn.unSelectedColorG;
  620. CGFloat difB = tempBtn.selectedColorB - tempBtn.unSelectedColorB;
  621. UIColor *leftItemColor = [UIColor colorWithRed:tempBtn.unSelectedColorR+scale*difR green:tempBtn.unSelectedColorG+scale*difG blue:tempBtn.unSelectedColorB+scale*difB alpha:1];
  622. UIColor *rightItemColor = [UIColor colorWithRed:tempBtn.unSelectedColorR+(1-scale)*difR green:tempBtn.unSelectedColorG+(1-scale)*difG blue:tempBtn.unSelectedColorB+(1-scale)*difB alpha:1];
  623. _btnLeft.titleLabel.textColor = rightItemColor;
  624. _btnRight.titleLabel.textColor = leftItemColor;
  625. }
  626. }
  627. //结束动画处理
  628. - (void)endAninamal{
  629. if (self.param.wMenuAnimal == PageTitleMenuYouKu) {
  630. CGRect rect = self.lineView.frame;
  631. rect.size.height = rect.size.width;
  632. rect.origin.y = self.mainView.frame.size.height-rect.size.height/2-self.param.wMenuCellPadding/4;
  633. self.lineView.frame = rect;
  634. self.lineView.layer.cornerRadius = rect.size.height/2;
  635. }
  636. }
  637. - (id)safeObjectAtIndex:(NSUInteger)index data:(NSArray*)data
  638. {
  639. if (index < data.count) {
  640. return [data objectAtIndex:index];
  641. } else {
  642. return nil;
  643. }
  644. }
  645. - (nullable WMZPageController *)findBelongViewControllerForView:(UIView *)view {
  646. UIResponder *responder = view;
  647. while ((responder = [responder nextResponder]))
  648. if ([responder isKindOfClass:[WMZPageController class]]) {
  649. return (WMZPageController *)responder;
  650. }
  651. return nil;
  652. }
  653. - (UIScrollView *)mainView{
  654. if (!_mainView) {
  655. _mainView = [UIScrollView new];
  656. _mainView.showsVerticalScrollIndicator = NO;
  657. _mainView.showsHorizontalScrollIndicator = NO;
  658. _mainView.decelerationRate = UIScrollViewDecelerationRateFast;
  659. _mainView.bouncesZoom = NO;
  660. if (@available(iOS 11.0, *)) {
  661. _mainView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
  662. }
  663. }
  664. return _mainView;
  665. }
  666. - (UIScrollView *)dataView{
  667. if (!_dataView) {
  668. _dataView = [UIScrollView new];
  669. _dataView.showsVerticalScrollIndicator = NO;
  670. _dataView.showsHorizontalScrollIndicator = NO;
  671. _dataView.pagingEnabled = YES;
  672. _dataView.bounces = NO;
  673. _dataView.scrollsToTop = NO;
  674. if (@available(iOS 11.0, *)) {
  675. _dataView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
  676. }
  677. _dataView.frame = CGRectMake(0, CGRectGetMaxY(self.mainView.frame),self.bounds.size.width, 0) ;
  678. }
  679. return _dataView;
  680. }
  681. - (NSMutableArray *)btnArr{
  682. if (!_btnArr) {
  683. _btnArr = [NSMutableArray new];
  684. }
  685. return _btnArr;
  686. }
  687. - (void)dealloc{
  688. }
  689. @end