iOS scrollsToTop失效解决

失效场景:
当一个控制器上有多个UIScrollView

失效的原因:
On iPhone, we execute this gesture only if there’s one on-screen scroll view with scrollsToTop == YES. If more than one is found, none will be scrolled.

scrollview 回顶部的原理:

CGPoint offect = scrollView.contentOffset;
offect.y = - scrollView.contentInset.top;
[scrollView setContentOffset:offect animated:YES];

系统scrollviewToTop工作原理:
当控制器上只有一个UIScrollView时,系统就会去遍历主窗口上所有的view,当遍历到那个UIScrollView时,就会为他设置回顶部原理代码,所以当控制器上面只有一个UIScrollView的时候,系统才会为这个UIScrollView添加这个自动回滚到顶部的功能。当一个控制器上有多个UIScrollView时,系统就懵了,因为他不确定到底要为那个UIScrollView设置这个自动回滚到顶部的功能,这个时候就只能有我们code明确的告诉系统:我们要为哪个UIScrollView设置自动回滚到顶部的功能。

解决思路:
获取statusbar的点击事件
其次,获取在当前窗口显示的scrollview,点击statusbar遍历当前窗口的所有子视图,如果是scrollview,就为它设置scrollview回顶部的原理代码。ps: ios 7.0 之后,statusBar的样式是交给控制器来管理的,但是在iOS7以前statusBar的样式是由UIApplication来管理的,既然window一显示出来,控制器中控制statusBar样式的代码就要失效,可以需要重新把statusBar样式交给UIApplication来管理。很简单,在plist加入如下键值对:
View controller-based status bar appearance = YES。

相关代码:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    CGPoint location = [[[event allTouches] anyObject] locationInView:self.window];
    CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
    //判断给定的点是否被一个CGRect包含,可以用CGRectContainsPoint函数
    if (CGRectContainsPoint(statusBarFrame, location)) {
        [self statusBarTouchedAction];
    }
}

- (void)statusBarTouchedAction
{
    [ScrollviewTop scrollViewScrollToTop];
}
+ (void)scrollViewScrollToTop
{
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    [self searchScrollViewInView:window];
}

+ (void)statusBarWindowClick
{
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    [self searchScrollViewInView:window];
}

+ (BOOL)isShowingOnKeyWindow:(UIView *)view
{
     主窗口
    UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
     以主窗口左上角为坐标原点, 计算self的矩形框
    CGRect newFrame = [keyWindow convertRect:view.frame fromView:view.superview];
    CGRect winBounds = keyWindow.bounds;
    // 主窗口的bounds 和 self的矩形框 是否有重叠
    BOOL intersects = CGRectIntersectsRect(newFrame, winBounds);
    return !view.isHidden && view.alpha > 0.01 && view.window == keyWindow && intersects;
}

+ (void)searchScrollViewInView:(UIView *)supView
{

    for (UIScrollView *subView in supView.subviews) {
        if ([subView isKindOfClass:[UIScrollView class]] && [self isShowingOnKeyWindow:supView]) {
            CGPoint offset = subView.contentOffset;
            offset.y = -subView.contentInset.top;
            [subView setContentOffset:offset animated:YES];
        }

        [self searchScrollViewInView:subView];
    }
}

ps: 你可以在delegate.m文件直接重写下面这个方法。明白后赶紧去试试吧。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

你可能感兴趣的:(Objective-C)