美文网首页
解决吸顶控制器点击状态栏scrollToTop

解决吸顶控制器点击状态栏scrollToTop

作者: wustzhy | 来源:发表于2020-04-07 06:47 被阅读0次

背景:
项目中使用了库ZJScrollPageView,无法在吸顶后,点击状态栏回顶 失效
(尝试了一些方法,发现iOS13获取状态栏点击事件无法获取bug,于是有作此篇的想法)

原因
吸顶效果控制器,一般是一个容器scrollView内带多个子scrollView的情况,why、how处理scrollToTop,具体可查看scrollToTopapi说明

测试Demo:

  1. Demo中,点击"微博&简书个人主页效果示例",进入吸顶页。

  2. 滑动,使完成吸顶 并且子列表部分滑动

    • 若当前childVC内scrollView是collectionView
      点击状态栏,无法滑到顶部
    • 若当前childVC内scrollView是tableView
      点击状态栏,tableView能滑到顶部,并且containerTableView也能滑到顶部

    Demo尚且如此,那么需要自己做吸顶了

搜索:
根据iOS-点击状态栏自动回到顶部功能实现详解
尝试:
1、touchBegin 获取状态栏点击事件
2、添加一个优先级高于statusbar的Window,添加点击事件。
当然此两种方法都需要自行解决滚动事件,但在iOS13之后此两种方法均失效了,点击事件无法响应。

于是,换其它方式

scrollViewShouldScrollToTop:这里找solution

1、若在子scrollView(/childVC的scrollView)所在vc(/childVC)里处理

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    
    // 此句与`ScrollToTop`无关,是原有的处理吸顶逻辑的
    if (self.delegate && [self.delegate respondsToSelector:@selector(scrollViewIsScrolling:)]) {
        [self.delegate scrollViewIsScrolling:scrollView];
    }
    
    //吸顶状态时,让childVC的`scrollsToTop`为YES,这样就能走代理方法`scrollViewShouldScrollToTop`,
    //须遵循任何时候,只有一个scrollView是scrollsToTop = YES,我还没有充分验证【比如:多个子scrollView的是YES,容器scrollView是NO,不知道可不可以】
    if (self.collectionView.contentOffset.y == 0) {
        self.collectionView.scrollsToTop = NO;
        [self superContainerScrollView].scrollsToTop = YES;
    }else {
        self.collectionView.scrollsToTop = YES;
        [self superContainerScrollView].scrollsToTop = NO;
    }
}

-(BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView {
    NSLog(@"%s \n ------- %@", __func__, scrollView);
    BOOL should = (self.collectionView.contentOffset.y != 0);
    if (should) {

// 法(1)可以实现,但是太慢了,childVC的scrollView
//        int delay = 1; //<1时 执行无效(无法回顶),0.9
//        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//            [[self superContainerScrollView] setContentOffset:CGPointZero];
//        });
    }
    return should;
}

- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView {
    NSLog(@"%s \n ------- %@", __func__, scrollView);
//法(2)仍然太慢了
    [[self superContainerScrollView] setContentOffset:CGPointZero];
}

上述 法(1)、(2) 虽然能实现,但是效果比较差,childVC的scrollView滑到CGPointZero后,ContainerScrollView才开始滑到CGPointZero

2、从ContainerScrollView所在的容器VC处理

-(BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView {
    dispatch_async(dispatch_get_main_queue(), ^{
        [self toScrollToTopAndDo:nil];
    });
    return YES;
}

// 滚到顶部 并且doSth
- (void)toScrollToTopAndDo:(VoidBlock)doSth {
    BaseViewController *currentVC = [self getCurrentChildVC];
    UIScrollView *childScrollView;

    if ([currentVC isKindOfClass:[BaseCollectionViewController class]]) {
        childScrollView = [(BaseCollectionViewController *)currentVC collectionView];
    }else if ([currentVC isKindOfClass:[BaseTableViewController class]]) {
        childScrollView = [(BaseTableViewController *)currentVC tableView];
    }
    
    BOOL shouldScrollToFirstTableCell = NO;
    if ([childScrollView isKindOfClass:[UITableView class]]) {
        if ([(UITableView *)childScrollView numberOfSections] &&
            [(UITableView *)childScrollView numberOfRowsInSection:0]) {
            shouldScrollToFirstTableCell = YES;
        }
    }
    if (shouldScrollToFirstTableCell) {
        [(UITableView *)childScrollView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:NO];
        
    }else {
        [childScrollView setContentOffset:CGPointMake(0, 0) animated:NO];
    }
    
    @weakify(self);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        @strongify(self);
        if (self.childScrollView.contentOffset.y != 0) {
            [self.childScrollView setContentOffset:CGPointZero animated:NO];
        }
        [self.tableView setContentOffset:CGPointZero animated:NO];
    });
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        if (doSth) {
            doSth();
        }
    });
}

效果完美~

另外,还有一个方法iOS中scrollToTop无效的解决方案,我还没有尝试

相关文章

  • 解决吸顶控制器点击状态栏scrollToTop

    背景:项目中使用了库ZJScrollPageView,无法在吸顶后,点击状态栏回顶 失效(尝试了一些方法,发现iO...

  • iOS中scrollToTop无效的解决方案

    前言 scrollToTop属性提供了点击iPhone状态栏页面回到顶部的功能,极大的方便了开发者的工作量。但是在...

  • Flutter 的吸顶功能

    Flutter 的吸顶功能 解决方案:CustomScrollView+SliverPersistentHeade...

  • 隐藏状态栏

    隐藏状态栏 如果想要隐藏状态栏,有两种做法: 状态栏是否隐藏默认由控制器管理,也就是说,当前状态栏所对应的控制器决...

  • 点击状态栏栏scrollview自动回到顶部

    iOS自带功能,当前控制器只有一个scrollsToTop = yes时,点击状态栏就会自动滚动到顶部 在标题按钮...

  • 导航条和状态栏相关

    状态栏 1.iOS7之后默认将状态栏的属性交给当前所属控制器管理: 一、若当前控制器不是导航控制器: (1) ...

  • IOS10 更改状态栏颜色

    更改所有控制器颜色和单独控制器颜色 状态栏的字体为黑色:default 状态栏的字体为白色:lightConten...

  • Swift UIStatusBarStyle 设置

    一. 设置全局控制器状态栏样式 1.取消控制器管理状态栏样式,在Supporting Files下的Info.pl...

  • VScode 使用ESlint踩坑

    坑1:状态栏根本无 ESlint 解决办法:点击扩展里面的ESlint ,选择启用即可。注意的是如果开启了状态栏还...

  • UINavigationController-04设置导航条

    前言 '栈顶控制器',当前用户所看见的控制器,就是栈顶控制器 导航条内容,是由'栈顶控制器'的navigation...

网友评论

      本文标题:解决吸顶控制器点击状态栏scrollToTop

      本文链接:https://www.haomeiwen.com/subject/qxgwphtx.html