背景:
项目中使用了库ZJScrollPageView,无法在吸顶后,点击状态栏回顶 失效
(尝试了一些方法,发现iOS13获取状态栏点击事件无法获取bug,于是有作此篇的想法)
原因
吸顶效果控制器,一般是一个容器scrollView内带多个子scrollView的情况,why、how处理scrollToTop,具体可查看scrollToTop
api说明
测试Demo:
-
Demo中,点击"微博&简书个人主页效果示例",进入吸顶页。
-
滑动,使完成吸顶 并且子列表部分滑动
- 若当前childVC内scrollView是collectionView
点击状态栏,无法滑到顶部 - 若当前childVC内scrollView是tableView
点击状态栏,tableView能滑到顶部,并且containerTableView也能滑到顶部
Demo尚且如此,那么需要自己做吸顶了
- 若当前childVC内scrollView是collectionView
搜索:
根据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无效的解决方案,我还没有尝试
网友评论