美文网首页
UIScrollView回滚到顶部解决方案

UIScrollView回滚到顶部解决方案

作者: Coder007 | 来源:发表于2017-09-06 18:28 被阅读486次

    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滚动到最上方

    相关文章

      网友评论

          本文标题:UIScrollView回滚到顶部解决方案

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