// // WMZPageLoopView.m // WMZPageController // // Created by wmz on 2019/9/22. // Copyright © 2019 wmz. All rights reserved. // #import "WMZPageLoopView.h" #import "WMZPageController.h" @interface WMZPageLoopView() { WMZPageNaviBtn *_btnLeft ; WMZPageNaviBtn *_btnRight; CGFloat lastContentOffset; WMZPageController *page; } //最底部下划线 @property(nonatomic,strong)UIView *bottomView; @property(nonatomic,strong)WMZPageParam *param; //图文 @property(nonatomic,assign)BOOL hasImage; //固定按钮 @property(nonatomic,strong)WMZPageNaviBtn *fixBtn; @end @implementation WMZPageLoopView - (instancetype)initWithFrame:(CGRect)frame param:(WMZPageParam*)param{ if (self = [super initWithFrame:frame]) { self.param = param; [self setUp]; } return self; } - (void)setUp{ //标题菜单 NSDictionary *dic = @{ @(PageMenuPositionLeft):[NSValue valueWithCGRect:CGRectMake(0, 0 , self.param.wMenuWidth,0)], @(PageMenuPositionRight):[NSValue valueWithCGRect:CGRectMake(PageVCWidth-self.param.wMenuWidth, 0 , self.param.wMenuWidth,0)], @(PageMenuPositionCenter):[NSValue valueWithCGRect:CGRectMake((PageVCWidth-self.param.wMenuWidth)/2, 0 , self.param.wMenuWidth,0)], @(PageMenuPositionNavi):[NSValue valueWithCGRect:CGRectMake((PageVCWidth-self.param.wMenuWidth)/2, 0 , self.param.wMenuWidth,0)], @(PageMenuPositionBottom):[NSValue valueWithCGRect:CGRectMake(0, PageVCHeight, self.param.wMenuWidth,0)], }; if (!self.param.wNoMenu) { [self addSubview:self.mainView]; self.mainView.frame = [dic[@(self.param.wMenuPosition)] CGRectValue] ; } [self addSubview:self.dataView]; self.dataView.scrollEnabled = self.param.wScrollCanTransfer; self.dataView.contentSize = CGSizeMake(self.param.wTitleArr.count*PageVCWidth,0); self.dataView.delegate = self; self.currentTitleIndex = -1; NSMutableArray *heightArr = [NSMutableArray new]; WMZPageNaviBtn *temp = nil; for (int i = 0; i (contenSize-centerX)) { point = CGPointMake(self.mainView.contentSize.width-self.mainView.frame.size.width , 0); }else{ point = CGPointMake(CGRectGetMaxX(indexFrame) - centerX- indexFrame.size.width/2, 0); } if ([self.mainView isScrollEnabled]) { [UIView animateWithDuration:0.25f animations:^(void){ [self.mainView setContentOffset:point]; }]; } CGFloat dataWidth = btn.titleLabel.frame.size.width?:btn.maxSize.width; //改变指示器frame CGRect lineRect = indexFrame; lineRect.size.height = self.param.wMenuIndicatorHeight?:PageK1px; lineRect.origin.y = self.mainView.frame.size.height - lineRect.size.height/2 - self.param.wMenuIndicatorY; lineRect.size.width = self.param.wMenuIndicatorWidth?:(dataWidth+10); lineRect.origin.x = (indexFrame.size.width - lineRect.size.width)/2 + indexFrame.origin.x; if (self.param.wMenuAnimal == PageTitleMenuYouKu) { lineRect.size.height = lineRect.size.width; self.lineView.layer.masksToBounds = YES; self.lineView.layer.cornerRadius = lineRect.size.height/2; } if (self.param.wMenuAnimal == PageTitleMenuPDD) { lineRect.origin.y = self.frame.size.height - lineRect.size.height; lineRect.size.width = self.param.wMenuIndicatorWidth?:dataWidth; lineRect.origin.x = (indexFrame.size.width - lineRect.size.width)/2 + indexFrame.origin.x; } if (self.param.wMenuAnimal == PageTitleMenuCircle) { lineRect = indexFrame; lineRect.origin.x = lineRect.origin.x - 2; lineRect.origin.y = lineRect.origin.y + 4; lineRect.size.width = lineRect.size.width + 4; lineRect.size.height = lineRect.size.height - 8 ; self.lineView.layer.masksToBounds = YES; self.lineView.layer.cornerRadius = lineRect.size.height/2; } [UIView animateWithDuration:0.1 animations:^{ self.lineView.frame = lineRect; } completion:^(BOOL finished) { }]; self.currentTitleIndex = newIndex; if (self.param.wInsertHeadAndMenuBg) { self.backgroundColor = [UIColor clearColor]; } if (self.param.wCustomMenuSelectTitle) { self.param.wCustomMenuSelectTitle(self.btnArr); } } #pragma -mark- scrollerDeleagte - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{ if (scrollView != self.dataView) return; lastContentOffset = scrollView.contentOffset.x; } - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ if (scrollView != self.dataView) return; if (![scrollView isDecelerating]&&![scrollView isDragging]) return; if (scrollView.contentOffset.x>0 &&scrollView.contentOffset.x<=self.btnArr.count*PageVCWidth ) { [self lifeCycleManage:scrollView]; [self animalAction:scrollView lastContrnOffset:lastContentOffset]; } if (scrollView.contentOffset.y == 0) return; CGPoint contentOffset = scrollView.contentOffset; contentOffset.y = 0.0; scrollView.contentOffset = contentOffset; } - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ if (scrollView != self.dataView) return; if (!decelerate) { [self endAninamal]; NSInteger newIndex = scrollView.contentOffset.x/PageVCWidth; self.currentTitleIndex = newIndex; if (self.loopDelegate && [self.loopDelegate respondsToSelector:@selector(pageScrollEndWithScrollView:)]) { [self.loopDelegate pageScrollEndWithScrollView:scrollView]; } } } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{ if (scrollView != self.dataView) return; [self endAninamal]; NSInteger newIndex = scrollView.contentOffset.x/PageVCWidth; self.currentTitleIndex = newIndex; if (!self.hasEndAppearance) { [self endAppearanceTransitionWithIndex:self.nextPageIndex withOldIndex:self.lastPageIndex isFlag:NO]; } self.hasEndAppearance = NO; [self scrollToIndex:newIndex]; if (self.loopDelegate && [self.loopDelegate respondsToSelector:@selector(pageScrollEndWithScrollView:)]) { [self.loopDelegate pageScrollEndWithScrollView:scrollView]; } } //管理生命周期 - (void)lifeCycleManage:(UIScrollView*)scrollView{ CGFloat diffX = scrollView.contentOffset.x - lastContentOffset; if (diffX < 0) { self.currentTitleIndex = ceil(scrollView.contentOffset.x/PageVCWidth); }else{ self.currentTitleIndex = (scrollView.contentOffset.x/PageVCWidth); } if (self.loopDelegate && [self.loopDelegate respondsToSelector:@selector(pageWithScrollView:left:)]) { [self.loopDelegate pageWithScrollView:scrollView left:(diffX < 0)]; } if (diffX > 0) { if (self.hasDealAppearance&&self.nextPageIndex == self.currentTitleIndex) { self.hasEndAppearance = YES; [self endAppearanceTransitionWithIndex:self.nextPageIndex withOldIndex:self.currentTitleIndex-1 isFlag:YES]; [self endAninamal]; return; } if (!self.hasDealAppearance || self.nextPageIndex != self.currentTitleIndex + 1) { self.hasDealAppearance = YES; if (self.nextPageIndex == self.currentTitleIndex - 1) { [self endAppearanceTransitionWithIndex:self.nextPageIndex withOldIndex:self.currentTitleIndex isFlag:NO]; self.hasDifferenrDirection = YES; } self.nextPageIndex = self.currentTitleIndex + 1; self.lastPageIndex = self.currentTitleIndex ; [self beginAppearanceTransitionWithIndex:self.nextPageIndex withOldIndex:self.currentTitleIndex]; } }else if(diffX < 0){ if (self.hasDealAppearance&&self.nextPageIndex == self.currentTitleIndex) { self.hasEndAppearance = YES; [self endAppearanceTransitionWithIndex:self.nextPageIndex withOldIndex:self.currentTitleIndex+1 isFlag:YES]; [self endAninamal]; return; } if (!self.hasDealAppearance || self.nextPageIndex != self.currentTitleIndex - 1) { self.hasDealAppearance = YES; if (self.nextPageIndex == self.currentTitleIndex + 1) { [self endAppearanceTransitionWithIndex:self.nextPageIndex withOldIndex:self.currentTitleIndex isFlag:NO]; self.hasDifferenrDirection = YES; } self.nextPageIndex = self.currentTitleIndex - 1; self.lastPageIndex = self.currentTitleIndex ; [self beginAppearanceTransitionWithIndex:self.nextPageIndex withOldIndex:self.currentTitleIndex]; } } } - (UIViewController*)getVCWithIndex:(NSInteger)index{ if (index < 0|| index >= self.param.wControllers.count) { return nil; } if ([[self findBelongViewControllerForView:self].cache objectForKey:@(index)]) { return [[self findBelongViewControllerForView:self].cache objectForKey:@(index)]; } return self.param.wControllers[index]; } - (void)beginAppearanceTransitionWithIndex:(NSInteger)index withOldIndex:(NSInteger)old{ UIViewController *newVC = [self getVCWithIndex:index]; UIViewController *oldVC = [self getVCWithIndex:old]; if (!newVC||!oldVC||(index==old)) return; [newVC beginAppearanceTransition:YES animated:YES]; [self addChildVC:index VC:newVC]; [oldVC beginAppearanceTransition:NO animated:YES]; self.currentVC = newVC; if (self.loopDelegate&&[self.loopDelegate respondsToSelector:@selector(setUpSuspension:index:end:)]) { [self.loopDelegate setUpSuspension:newVC index:index end:NO]; } if (self.param.wEventBeganTransferController) { self.param.wEventBeganTransferController(oldVC, newVC, old, index); } } - (void)addChildVC:(NSInteger)index VC:(UIViewController*)newVC{ if (![[self findBelongViewControllerForView:self].childViewControllers containsObject:newVC]) { [[self findBelongViewControllerForView:self] addChildViewController:newVC]; newVC.view.frame = [[self findBelongViewControllerForView:self].rectArr[index] CGRectValue]; [self.dataView addSubview:newVC.view]; [newVC didMoveToParentViewController:[self findBelongViewControllerForView:self]]; [[self findBelongViewControllerForView:self].cache setObject:newVC forKey:@(index)]; } } - (void)endAppearanceTransitionWithIndex:(NSInteger)index withOldIndex:(NSInteger)old isFlag:(BOOL)flag{ UIViewController *newVC = [self getVCWithIndex:index]; UIViewController *oldVC = [self getVCWithIndex:old]; if (!newVC||!oldVC||(index==old)) return; if (self.currentTitleIndex == self.nextPageIndex) { [oldVC willMoveToParentViewController:nil]; [oldVC.view removeFromSuperview]; [oldVC removeFromParentViewController]; [newVC endAppearanceTransition]; [oldVC endAppearanceTransition]; if (flag&&self.hasDifferenrDirection) { [newVC endAppearanceTransition]; [oldVC endAppearanceTransition]; self.hasDifferenrDirection = NO; } if (self.param.wEventEndTransferController) { self.param.wEventEndTransferController(oldVC, newVC, old, index); } self.currentVC = newVC; self.currentTitleIndex = index; if (self.loopDelegate&&[self.loopDelegate respondsToSelector:@selector(setUpSuspension:index:end:)]) { [self.loopDelegate setUpSuspension:newVC index:index end:YES]; } }else{ [newVC willMoveToParentViewController:nil]; [newVC.view removeFromSuperview]; [newVC removeFromParentViewController]; [oldVC beginAppearanceTransition:YES animated:YES]; [oldVC endAppearanceTransition]; [newVC beginAppearanceTransition:NO animated:YES]; [newVC endAppearanceTransition]; if (self.param.wEventEndTransferController) { self.param.wEventEndTransferController(newVC, oldVC, index, old); } self.currentVC = oldVC; self.currentTitleIndex = old; if (self.loopDelegate&&[self.loopDelegate respondsToSelector:@selector(setUpSuspension:index:end:)]) { [self.loopDelegate setUpSuspension:oldVC index:old end:YES]; } } self.hasDealAppearance = NO; self.nextPageIndex = -999; } - (BOOL)canTopSuspension{ if (!self.param.wTopSuspension ||self.param.wMenuPosition == PageMenuPositionBottom ||self.param.wMenuPosition == PageMenuPositionNavi){ return NO; } return YES; } //动画管理 - (void)animalAction:(UIScrollView*)scrollView lastContrnOffset:(CGFloat)lastContentOffset{ CGFloat contentOffsetX = scrollView.contentOffset.x; CGFloat sWidth = PageVCWidth; CGFloat content_X = (contentOffsetX / sWidth); NSArray *arr = [[NSString stringWithFormat:@"%f",content_X] componentsSeparatedByString:@"."]; int num = [arr[0] intValue]; CGFloat scale = content_X - num; int selectIndex = contentOffsetX/sWidth; // 拖拽 if (contentOffsetX <= lastContentOffset ){ selectIndex = selectIndex+1; _btnRight = [self safeObjectAtIndex:selectIndex data:self.btnArr]; _btnLeft = [self safeObjectAtIndex:selectIndex-1 data:self.btnArr]; } else if (contentOffsetX > lastContentOffset ){ _btnRight = [self safeObjectAtIndex:selectIndex+1 data:self.btnArr]; _btnLeft = [self safeObjectAtIndex:selectIndex data:self.btnArr]; } //跟随滑动 if (self.param.wMenuAnimal == PageTitleMenuAiQY || self.param.wMenuAnimal == PageTitleMenuYouKu) { CGRect rect = self.lineView.frame; if (scale < 0.5 ) { rect.size.width = self.param.wMenuIndicatorWidth + ( _btnRight.center.x-_btnLeft.center.x) * scale*2; rect.origin.x = _btnLeft.center.x -self.param.wMenuIndicatorWidth/2; }else if(scale >= 0.5 ){ rect.size.width = self.param.wMenuIndicatorWidth+(_btnRight.center.x-_btnLeft.center.x) * (1-scale)*2; rect.origin.x = _btnLeft.center.x + 2*(scale-0.5)*(_btnRight.center.x - _btnLeft.center.x)-self.param.wMenuIndicatorWidth/2; } if (rect.size.height!= (self.param.wMenuIndicatorHeight?:PageK1px)) { rect.size.height = self.param.wMenuIndicatorHeight?:PageK1px; } if (rect.origin.y != (self.mainView.frame.size.height-self.param.wMenuIndicatorY-rect.size.height/2)) { rect.origin.y = self.mainView.frame.size.height-self.param.wMenuIndicatorY-rect.size.height/2; } self.lineView.frame = rect; } //变大 if (self.param.wMenuAnimalTitleBig) { _btnLeft.transform = CGAffineTransformMakeScale(1+(1-0.9)*(1-scale), 1+(1-0.9)*(1-scale)); _btnRight.transform = CGAffineTransformMakeScale(1+(1-0.9)*scale, 1+(1-0.9)*scale); } //渐变 if (self.param.wMenuAnimalTitleGradient) { WMZPageNaviBtn *tempBtn = _btnLeft?:_btnRight; CGFloat difR = tempBtn.selectedColorR - tempBtn.unSelectedColorR; CGFloat difG = tempBtn.selectedColorG - tempBtn.unSelectedColorG; CGFloat difB = tempBtn.selectedColorB - tempBtn.unSelectedColorB; UIColor *leftItemColor = [UIColor colorWithRed:tempBtn.unSelectedColorR+scale*difR green:tempBtn.unSelectedColorG+scale*difG blue:tempBtn.unSelectedColorB+scale*difB alpha:1]; UIColor *rightItemColor = [UIColor colorWithRed:tempBtn.unSelectedColorR+(1-scale)*difR green:tempBtn.unSelectedColorG+(1-scale)*difG blue:tempBtn.unSelectedColorB+(1-scale)*difB alpha:1]; _btnLeft.titleLabel.textColor = rightItemColor; _btnRight.titleLabel.textColor = leftItemColor; } } //结束动画处理 - (void)endAninamal{ if (self.param.wMenuAnimal == PageTitleMenuYouKu) { CGRect rect = self.lineView.frame; rect.size.height = rect.size.width; rect.origin.y = self.mainView.frame.size.height-rect.size.height/2-self.param.wMenuCellPadding/4; self.lineView.frame = rect; self.lineView.layer.cornerRadius = rect.size.height/2; } } - (id)safeObjectAtIndex:(NSUInteger)index data:(NSArray*)data { if (index < data.count) { return [data objectAtIndex:index]; } else { return nil; } } - (nullable WMZPageController *)findBelongViewControllerForView:(UIView *)view { UIResponder *responder = view; while ((responder = [responder nextResponder])) if ([responder isKindOfClass:[WMZPageController class]]) { return (WMZPageController *)responder; } return nil; } - (UIScrollView *)mainView{ if (!_mainView) { _mainView = [UIScrollView new]; _mainView.showsVerticalScrollIndicator = NO; _mainView.showsHorizontalScrollIndicator = NO; _mainView.decelerationRate = UIScrollViewDecelerationRateFast; _mainView.bouncesZoom = NO; if (@available(iOS 11.0, *)) { _mainView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; } } return _mainView; } - (UIScrollView *)dataView{ if (!_dataView) { _dataView = [UIScrollView new]; _dataView.showsVerticalScrollIndicator = NO; _dataView.showsHorizontalScrollIndicator = NO; _dataView.pagingEnabled = YES; _dataView.bounces = NO; _dataView.scrollsToTop = NO; if (@available(iOS 11.0, *)) { _dataView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; } _dataView.frame = CGRectMake(0, CGRectGetMaxY(self.mainView.frame),self.bounds.size.width, 0) ; } return _dataView; } - (NSMutableArray *)btnArr{ if (!_btnArr) { _btnArr = [NSMutableArray new]; } return _btnArr; } - (void)dealloc{ } @end