UIScrollView回滾到頂部解決方案

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滾動到最上方
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容