WMZPageLoopView.m 32 KB

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