UIScrollView回滚到顶部解决方案
- 根据系统的不同分成两种情况
- iOS9之前,如果页面上有两个UIScroolView,那么点击导航栏将没有反应
- iOS9之后(包括iOS9),页面内多个UIScrollView,点击导航栏将根据不同情况,回滚不同的UIScroolView
iOS9之前的处理方案
- 其实现在写这个方案意义不是很大,iOS11正式版很快就要发布了,对于系统的适配,iOS9-11就可以了,iOS8基本上可以放弃了
- 先说一下思路
- 需要拦截点击导航栏操作-使用UIWindow,在导航栏上面覆盖一层没有颜色的window,级别设置到最高
- 拦截点击操作之后,遍历keyWindow上所有的子控件
- 判断这个子控件是否是UIScrollView
- 判断这个子控件是否显示在keyWindow上
- 都满足之后将找到的子控件的contentOffset的y值设置为0即可
- 这种方式的不足之处:如果有两个UIScrollView都在屏幕上面,都是垂直滚动,那么点击之后,两个都会回到顶部,想要解决个问题,就需要进一步判断是哪一个UIScrollView
// 顶部的window,覆盖在状态栏上面,点击之后将window上显示的scrollView滑动到顶部
#import <Foundation/Foundation.h>
@interface YWTopWindow : NSObject
+ (void)show;
+ (void)hide;
@end
#import "YWTopWindow.h"
#import "UIView+YWExtension.h"
@implementation YWTopWindow
static UIWindow *window_;
+ (void)initialize
{
window_ = [[UIWindow alloc] init];
window_.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 20);
window_.backgroundColor = [UIColor clearColor];
// 将级别设置为最高,这样就能盖住状态栏
window_.windowLevel = UIWindowLevelAlert;
[window_ addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(windowClick)]];
}
+ (void)show
{
// iOS9之前,可以直接写window_.hidden = NO;
// 在iOS9之后,直接写会报错,大概的意思就是:在程序启动结束后,window需要有一个根控制器
// Application windows are expected to have a root view controller at the end of application launch
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
window_.hidden = NO;
});
}
+ (void)hide
{
window_.hidden = YES;
}
/**
窗口点击
*/
+ (void)windowClick
{
UIWindow *window = [UIApplication sharedApplication].keyWindow;
[self searchScrollViewInView:window];
}
+ (void)searchScrollViewInView:(UIView *)superview
{
for (UIScrollView *subView in superview.subviews) {
// 如果是UIScrollView,滚动到最顶部
if([subView isKindOfClass:[UIScrollView class]] && subView.isShowingOnKeyWindow){
CGPoint offset = subView.contentOffset;
offset.y = - subView.contentInset.top;
[subView setContentOffset:offset animated:YES];
}
// 不是UIScrollView或者不是显示在keyWindow上,继续寻找
[self searchScrollViewInView:subView];
}
}
@end
// 写在UIView的分类中的方法
// 判断一个控件是否显示在主窗口上面
- (BOOL)isShowingOnKeyWindow
{
// 主窗口
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
// 以主窗口左上角为坐标原点,计算self的矩形框
CGRect newFrame = [keyWindow convertRect:self.frame fromView:self.superview];
CGRect winBounds = keyWindow.bounds;
// 主窗口的bounds和self的矩形框是否有重叠
BOOL intersects = CGRectIntersectsRect(newFrame, winBounds);
return !self.isHidden && self.alpha > 0.01 && self.window == keyWindow && intersects;
}
iOS9之后(包含iOS9)
- 页面上两个UIScrollView,类似今日头条的布局,第一个横向滑动,第二个也是横向滑动,但是里面有好多UITableView
- 这种可以不用管,系统会自动将当前显示的UITableView滑动到顶部
- 页面上有两个UIScrollView,都是垂直滚动,两个都显示在页面上
- 左右分布,那么点击导航栏位置在那个控件上方,滚动那个UIScrollView
- 上下分布,点击导航栏时,上方的控件在初始位置,那么滚动下方的控件,如果上方的有滚动过,那么就会将上方的UIScrollView滚动到最上方
网友评论