| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- //
- // ENestScrollPageView.m
- // RingtoneDuoduo
- //
- // Created by 唐天成 on 2020/6/9.
- // Copyright © 2020 duoduo. All rights reserved.
- //
- #import "TCNestScrollPageView.h"
- #pragma mark - TCMainScrollView
- @interface TCMainScrollView ()
- @property (nonatomic, strong) UIView *viewPager;
- @end
- @implementation TCMainScrollView
- /********************** 多手势同时识别 ***************************/
- - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
- UIView *otherGestureRecognizerView = otherGestureRecognizer.view;
- if( [otherGestureRecognizerView isKindOfClass:[UIScrollView class]] && otherGestureRecognizerView != self && gestureRecognizer == self.panGestureRecognizer && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
-
- if([self.viewArray containsObject:(UIScrollView *)otherGestureRecognizerView]) {
- return YES;
- } else {
- return NO;
- }
- }
- return NO;
- }
- //1
- - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
- if(gestureRecognizer == self.panGestureRecognizer) {
- self.isScrolBySelf = YES;
- self.currentSubScrolleView = nil;
- UIView *touchView = touch.view;
- BOOL isContain = NO;
- while (touchView != nil) {
- if(touchView == self.viewPager) {
- isContain = YES;
- break;
- }
- touchView = [touchView nextResponder];
- }
- if(isContain) {
- touchView = touch.view;
- while (touchView != nil) {
- if([touchView isKindOfClass:[UIScrollView class]] && touchView != self) {
- BOOL canContain = NO;
- // if(((UIScrollView *)touchView).contentSize.height > touchView.frame.size.height) {
- // canContain = YES;
- // } else {
- NSInteger scrollCount = 0;
- UIView *tempView = touchView;
- while (tempView != self.viewPager) {
- if([tempView isKindOfClass:[UIScrollView class]]) {
- scrollCount++;
- }
- tempView = [tempView nextResponder];
- }
- if(scrollCount == 2 && ((UIScrollView *)touchView).contentSize.width <= touchView.frame.size.width) {
- canContain = YES;
- }
- // }
-
- if(canContain) {
- self.isScrolBySelf = NO;
- self.currentSubScrolleView = (UIScrollView *)touchView;
- if(![self.viewArray containsObject:self.currentSubScrolleView]) {
- [self.viewArray addObject:self.currentSubScrolleView];
- [self.currentSubScrolleView addObserver:self.superview forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
- }
- break;
- }
- }
- if(touchView == self.viewPager) {
- break;
- }
- touchView = [touchView nextResponder];
- }
- }
-
- }
- return YES;
- }
- - (NSMutableArray *)viewArray {
- if(!_viewArray) {
- _viewArray = [NSMutableArray array];
- }
- return _viewArray;
- }
- - (void)dealloc {
- }
- @end
- #pragma mark - TCNestScrollParam
- @implementation TCNestScrollParam
- - (instancetype)init {
- if(self = [super init]) {
- self.pageType = NestScrollPageViewHeadViewChageType;
- self.yOffset = 0;
- self.bounces = YES;
- }
- return self;
- }
- @end
- #pragma mark - TCNestScrollPageView
- @interface TCNestScrollPageView ()<UITableViewDataSource, UITableViewDelegate>
- @property (nonatomic, strong) TCNestScrollParam *param;
- @property (nonatomic, strong) UIView *headerView;
- @property (nonatomic, strong) TCMainScrollView *mainTabelView;
- @property (nonatomic, strong) UITableViewCell *cell;
- @property (nonatomic, strong) UIView *viewPager;
- @property (nonatomic, assign) CGFloat lastDy;//mainTableView最后停留位置
- @property(nonatomic,assign)BOOL nextReturn;//这个用于记录是否是手动改变contentOffset的conteentOffSet,是的话就不用做监听处理
- @property(nonatomic,assign)CGFloat stayHeight;//头部允许向上滚动的距离
- @property (nonatomic, assign) CGFloat mainTabExchangeDy;//mainTableView最后变化距离
- @end
- @implementation TCNestScrollPageView
- - (instancetype)initWithFrame:(CGRect)frame headView:(UIView *)headView viewPageView:(UIView *)viewPager nestScrollParam:(TCNestScrollParam *)param {
- if(self = [super initWithFrame:frame]) {
- self.param = param;
- self.lastDy = 0.0;
- self.viewPager = viewPager;
- [self setupBaseView];
- self.headerView = headView;
- self.mainTabelView.viewPager = viewPager;
- }
- return self;
- }
- - (void)setupBaseView {
- self.mainTabelView = [[TCMainScrollView alloc] initWithFrame:self.bounds style:UITableViewStylePlain];
- if(@available(iOS 11.0, *)){
- self.mainTabelView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;//UIScrollView也适用
- } else {
- self.viewController.automaticallyAdjustsScrollViewInsets = NO;
- }
- [self.mainTabelView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"reuseIdentifier"];
- self.mainTabelView.dataSource = self;
- self.mainTabelView.delegate = self;
- self.mainTabelView.bounces = self.param.bounces;
- self.mainTabelView.showsVerticalScrollIndicator = NO;
- [self insertSubview:self.mainTabelView atIndex:0];
- }
- - (void)setHeaderView:(UIView *)headerView {
- _headerView = headerView;
- self.stayHeight = ((CGFloat)ceil(headerView.frame.size.height - self.param.yOffset));
- self.mainTabelView.tableHeaderView = self.headerView;
- }
- - (void)resetHeader:(UIView *)headerView {
- self.headerView = headerView;
- }
- - (void)willMoveToSuperview:(UIView *)newSuperview{
- [super willMoveToSuperview:newSuperview];
- if (newSuperview == nil) {
- for (UIScrollView *sc in self.mainTabelView.viewArray) {
- [sc removeObserver:self forKeyPath:@"contentOffset"];
- }
- }
- }
- #pragma mark - ScrollVieeScroll
- //mainScrollView(三种效果都分开写,全写一起我自己都晕了,也不方便其他人阅读)
- - (void)scrollViewDidScroll:(UIScrollView *)scrollView{
- if(self.param.pageType == NestScrollPageViewHeadViewChageType) {
- [self headViewChageTypeScrollViewDidScroll:scrollView];
- } else if(self.param.pageType == NestScrollPageViewHeadViewSuckTopType) {
- [self headViewSuckTopTypeScrollViewDidScroll:scrollView];
- } else if(self.param.pageType == NestScrollPageViewHeadViewNoSuckTopType) {
- [self headViewNoSuckTopTypeScrollViewDidScroll:scrollView];
- }
- if (self.didScrollBlock) {
- self.didScrollBlock(scrollView.contentOffset.y);
- }
- }
- //subScrollView(三种效果都分开写,全写一起我自己都晕了,也不方便其他人阅读)
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
- if ([keyPath isEqualToString:@"contentOffset"]){
- if(self.param.pageType == NestScrollPageViewHeadViewChageType) {
- [self headViewChageTypeObserveValueForKeyPath:keyPath ofObject:object change:change context:context];
- } else if(self.param.pageType == NestScrollPageViewHeadViewSuckTopType) {
- [self headViewSuckTopTypeObserveValueForKeyPath:keyPath ofObject:object change:change context:context];
- } else if(self.param.pageType == NestScrollPageViewHeadViewNoSuckTopType) {
- [self headViewNoSuckTopTypeObserveValueForKeyPath:keyPath ofObject:object change:change context:context];
- }
- }else{
- [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
- }
- }
- #pragma mark headViewChageType
- - (void)headViewChageTypeScrollViewDidScroll:(UIScrollView *)scrollView{
- CGFloat dh = scrollView.contentOffset.y;
- _mainTabExchangeDy = dh - _lastDy;
- if (dh >= _stayHeight) {
- scrollView.contentOffset = CGPointMake(0, _stayHeight);
- // _lastDy = scrollView.contentOffset.y;
- } else if(dh<=0) {
- scrollView.contentOffset = CGPointMake(0, 0);
- // _lastDy = scrollView.contentOffset.y;
- }
- _lastDy = scrollView.contentOffset.y;
- }
- //subScrollView
- - (void)headViewChageTypeObserveValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
- CGFloat new = [change[@"new"] CGPointValue].y;
- CGFloat old = [change[@"old"] CGPointValue].y;
- NSLog(@"%p %lf %lf %lf %lf %p %d %d %d %@",object,self.mainTabelView.contentOffset.y, ((UIScrollView *)object).contentOffset.y, old, new, object, ((UIScrollView *)object).tracking, ((UIScrollView *)object).dragging,((UIScrollView *)object).decelerating,NSStringFromUIEdgeInsets(((UIScrollView *)object).contentInset));
- if (_nextReturn) {
- _nextReturn = false;
- return;
- }
- // CGFloat new = [change[@"new"] CGPointValue].y;
- // CGFloat old = [change[@"old"] CGPointValue].y;
- if (new == old) {
- NSLog(@"相等");
- return;
- }
- CGFloat dh = new - old;
- if (dh < 0) {
- //向下
- NSLog(@"向下old : %lf new : %lf %lf %lf",old,new,((UIScrollView *)object).contentSize.height,((UIScrollView *)object).frame.size.height);
-
- if(self.mainTabelView.contentOffset.y > 0 && ((UIScrollView *)object).contentOffset.y < (((UIScrollView *)object).contentSize.height-((UIScrollView *)object).frame.size.height) && self.mainTabelView.dragging == YES) {
- _nextReturn = true;
- NSLog(@"向下--old : %lf",old);
- ((UIScrollView *)object).contentOffset = CGPointMake(0, old);
- }
- } else if(dh > 0) {
- //向上
- NSLog(@"向上old : %lf",old);
- if(self.mainTabelView.contentOffset.y < _stayHeight && ((UIScrollView *)object).contentOffset.y > 0 && self.mainTabelView.dragging == YES) {
- //加一下这个if判断是因为在tableView的情况下,如果只选reloadData之后,不知道为什么会导致contentOffSet莫名其妙加上40,也就是会照成dh>0.然后当执行((UIScrollView *)object).contentOffset = CGPointMake(0, old)后并不管用,tableView会反复让contentOffSet莫名其妙加上40,最后照成崩溃,所以想法:当maintableView的contentoffset变化没有subScrollView的contentOffset变化那么大时,就表示出现了上述行为,那么就不做强制修改contentoffset
- NSLog(@"uiuiuiu%lf %lf %lf %lf",_mainTabExchangeDy,self.mainTabelView.contentOffset.y,old,new);
- if(dh > (_mainTabExchangeDy/*+2*/)) {
- return;
- }
- _nextReturn = true;
- NSLog(@"向上--old : %lf",old);
- ((UIScrollView *)object).contentOffset = CGPointMake(0, old);
- }
- }
- }
- #pragma mark headViewSuckTopType
- - (void)headViewSuckTopTypeScrollViewDidScroll:(UIScrollView *)scrollView{
- CGFloat dh = scrollView.contentOffset.y;
- if (dh >= _stayHeight) {
- scrollView.contentOffset = CGPointMake(0, _stayHeight);
- _lastDy = scrollView.contentOffset.y;
- } else if(dh<=0) {
- scrollView.contentOffset = CGPointMake(0, 0);
- _lastDy = scrollView.contentOffset.y;
- } else {
- UIScrollView *currenSubScrollView = self.mainTabelView.currentSubScrolleView;//nil;
- if (currenSubScrollView == nil) {
- _lastDy = scrollView.contentOffset.y;
- return;
- }
- NSLog(@"哈哈哈哈%lf %lf %lf ",currenSubScrollView.contentOffset.y,scrollView.contentOffset.y,_stayHeight);
- if(currenSubScrollView.contentOffset.y > 0 && (scrollView.contentOffset.y < _stayHeight) && (scrollView.contentOffset.y - _lastDy)<0 && self.mainTabelView.isScrolBySelf == NO) {
- NSLog(@"main向下%lf",_lastDy);
- //向下拖拽
- scrollView.contentOffset = CGPointMake(0, _lastDy);
- } else if((scrollView.contentOffset.y - _lastDy)>0 && currenSubScrollView.contentOffset.y<0) {
- NSLog(@"main向上%lf",_lastDy);
- //向上
- scrollView.contentOffset = CGPointMake(0, _lastDy);
- }
- _lastDy = scrollView.contentOffset.y;
- }
- }
- //subScrollView
- - (void)headViewSuckTopTypeObserveValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
- if (_nextReturn) {
- _nextReturn = false;
- return;
- }
- CGFloat new = [change[@"new"] CGPointValue].y;
- CGFloat old = [change[@"old"] CGPointValue].y;
- if (new == old) {return;}
- CGFloat dh = new - old;
- if (dh < 0) {
- //向下
- if(((UIScrollView *)object).contentOffset.y < 0){
- if (self.mainTabelView.contentOffset.y > 0) {
- _nextReturn = true;
- ((UIScrollView *)object).contentOffset = CGPointMake(0, 0);
- }
- }
- }else{
- //向上
- if (self.mainTabelView.contentOffset.y < _stayHeight) {
- if (((UIScrollView *)object).contentOffset.y > 0) {
- _nextReturn = true;
- if(old < 0) {
- old = 0;
- }
- ((UIScrollView *)object).contentOffset = CGPointMake(0, old);
- }
- }else{
- }
- }
- }
- #pragma mark headViewNoSuckTopType
- - (void)headViewNoSuckTopTypeScrollViewDidScroll:(UIScrollView *)scrollView{
- NSLog(@" %lf %lf %lf %lf",scrollView.contentOffset.y,_stayHeight,scrollView.contentOffset.y,_lastDy);
- CGFloat dh = scrollView.contentOffset.y;
- if(_lastDy == dh) {
- return;
- }
- if (dh >= _stayHeight) {
- scrollView.contentOffset = CGPointMake(0, _stayHeight);
- _lastDy = scrollView.contentOffset.y;
- } else {
- UIScrollView *currenSubScrollView = self.mainTabelView.currentSubScrolleView;
- if (currenSubScrollView == nil) {
- _lastDy = scrollView.contentOffset.y;
- return;
- }
- //向下拖拽
- if (currenSubScrollView.contentOffset.y > 0 && (self.mainTabelView.contentOffset.y < _stayHeight) && (self.mainTabelView.contentOffset.y - _lastDy)<0 && self.mainTabelView.isScrolBySelf == NO) {
- scrollView.contentOffset = CGPointMake(0, _lastDy);
- }
- _lastDy = scrollView.contentOffset.y;
- }
- }
- //subScrollView
- - (void)headViewNoSuckTopTypeObserveValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
- if (_nextReturn) {
- _nextReturn = false;
- return;
- }
- CGFloat new = [change[@"new"] CGPointValue].y;
- CGFloat old = [change[@"old"] CGPointValue].y;
- if (new == old) {return;}
- CGFloat dh = new - old;
- if (dh < 0) {
- //向下
- if(((UIScrollView *)object).contentOffset.y < 0){
- _nextReturn = true;
- ((UIScrollView *)object).contentOffset = CGPointMake(0, 0);
- }
- }else{
- //向上
- if (self.mainTabelView.contentOffset.y < _stayHeight) {
- _nextReturn = true;
- ((UIScrollView *)object).contentOffset = CGPointMake(0, old);
- }else{
- }
- }
- }
- #pragma mark - UITableViewDataSource && UITableViewDlegate
- - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
- return 1;
- }
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
- return 1;
- }
- - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
- NSLog(@"%lf",self.frame.size.height - self.param.yOffset);
- return self.frame.size.height - self.param.yOffset;
- }
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"reuseIdentifier" forIndexPath:indexPath];
- self.cell = cell;
- if(![cell.contentView.subviews containsObject:self.viewPager]) {
- self.viewPager.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height - self.param.yOffset);
- [cell.contentView addSubview:self.viewPager];
- }
- return cell;
- }
- - (void)resetViewPage:(UIView *)viewPage {
-
- [self.viewPager removeFromSuperview];
- self.viewPager = viewPage;
- self.viewPager.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height - self.param.yOffset);
- [self.cell.contentView addSubview:self.viewPager];
- self.mainTabelView.viewPager = self.viewPager;
-
- }
- - (void)dealloc {
- NSLog(@"%@销毁了",self);
- }
- -(UIViewController*)viewController
- {
- UIResponder *nextResponder = self;
- do
- {
- nextResponder = [nextResponder nextResponder];
- if ([nextResponder isKindOfClass:[UIViewController class]])
- return (UIViewController*)nextResponder;
- } while (nextResponder != nil);
- return nil;
- }
- @end
|