iOS 点击状态栏返回顶部(多scrollView的实现)
来源:互联网 发布:灰原穷 知乎 编辑:程序博客网 时间:2024/05/21 06:15
前言
上周有一个小伙子来到公司面试,笔试题目做的还算不错,但是面试的表现一塌糊涂,项目架构、业务逻辑、界面逻辑,基本上十问九不知。其中有一个很简单的问题—-关于
tableView
点击状态栏返回顶部,我后来问了一些朋友,发现还真是有很多人不清楚是怎么实现的,觉得可以拿出来说一说。
- 前言
- 错误的实现方式
- 如何滚动到顶部
- 错误的实现方法
- 第一个问题 状态栏的层级级别
- 第二个问题 点击状态栏回到了顶部
- 正确的实现方式
- 设置scrollsToTop属性
- 自定义一个TopWindow
- 实现代码
- 总结
错误的实现方式
关于这个问题,大部分新手第一个想到的就是在状态栏的地方添加一个view,然后加一个点击效果/手势。
整体思路看上去并没有什么问题,OK,那我们就来按这个思路来实现一下。
如何滚动到顶部
没什么好说的,直接上代码,在任意地方实现以下代码都可以使_needBackToTopView
回到顶部。
CGPoint offset = _needBackToTopView.contentOffset;offset.y = -_needBackToTopView.contentInset.top;[_needBackToTopView setContentOffset:offset animated:YES];
错误的实现方法
创建view绑定手势
_statusBarCoverView = ({ UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, KBLScreenWidth , 20)]; view.backgroundColor = [UIColor redColor]; view;});[self.view addSubview:_statusBarCoverView];UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(statuseBarClick)];[_statusBarCoverView addGestureRecognizer:tap];
手势绑定的方法
NSLog(@"我被点击了");CGPoint offset = _tableView.contentOffset;offset.y = -_tableView.contentInset.top;[_tableView setContentOffset:offset animated:YES];
运行后我们发现,居然成功了。瞬间感觉这东西不就这么简单吗?错
冷静下来,检查一下编译器我们发现,我们在手势绑定方法中,打印的信息并没有显示!!据此我们发现了两件事情:
- 我们实现的点击方法并没有执行。
- 在没有执行的前提下,点击状态栏
tableView
居然还是回到了顶部。
下面我们就一点点的分析一下这些疑问。
第一个问题: 状态栏的层级级别
首先,
statusBar
是一个特殊的view,始终位于程序的topLevel
,我们创建的普通view的level比statusBar
低很多。因此响应事件优先被statusBar截获。
查阅官方文档,关于层级关系有如下定义:
const UIWindowLevel UIWindowLevelNormal; const UIWindowLevel UIWindowLevelAlert; const UIWindowLevel UIWindowLevelStatusBar; typedef CGFloat UIWindowLevel;
- 从高到低依次是
UIWindowLevelAlert
>UIWindowLevelStatusBar
>UIWindowLevelNormal
看到
windowLevel
我们立马想到UIWindow
具有windowLevel
这样一个属性。也就是说,如果我们想实现一个可以覆盖statusBar
的view
,我们需要将这个view继承自UIWindow
,并且将层级Level设置的比UIWindowLevelStatusBar
高才可以。
第二个问题: 点击状态栏回到了顶部
我们发现,在我们方法失效的情况下,点击状态栏,依然完成了tableView返回顶部的功能。
原来,系统的UIScrollView自带有点击顶部状态栏自动返回顶部的效果,但是这个效果是有限制的。
// When the user taps the status bar, the scroll view beneath the touch which is closest to the status bar will be scrolled to top, but only if its `scrollsToTop` property is YES, its delegate does not return NO from `shouldScrollViewScrollToTop`, and it is not already at the top.// 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.@property(nonatomic) BOOL scrollsToTop __TVOS_PROHIBITED; // default is YES.
这个手势只能作用在一个scrollView上,当发现多个时,手势将会失效。
- 但实际开发当中,我们的视图结构里大都包含了很多个
scrollView
,当视图中具备多个scrollView
的时候:- 我们要想实现唯一一个
scrollView
可以响应statusBar
的手势,则只需将其他scrollView的scrollsToTop
属性置为NO
就可以了。 - 我们要想实现多个
scrollView
响应statusBar
的手势,我们只能使用自定义的方式。
- 我们要想实现唯一一个
正确的实现方式
设置scrollsToTop
属性
上面提到,系统的UIScrollView
自带有点击顶部状态栏自动返回顶部的效果,其属性scrollsToTop
的默认值是YES
。
- 当视图中只有一个
UIScrollView
时,默认点击statusBar
,该UIScrollView
具有返回顶部的效果。 - 当视图中有多个
UIScrollView
时- 如果只有一个
UIScrollView
的scrollsToTop
属性值为YES
,则该UIScrollView
具有返回顶部的效果,其他UIScrollView
不具有该效果。 - 如果多个
UIScrollView
的scrollsToTop
属性值为YES
,则所有UIScrollView
都不具有该效果。
- 如果只有一个
自定义一个TopWindow
实际开发中我们经常会有复杂的界面结构,其中会具有多个
UIScrollView
,我们要如何实现点击状态栏,让多个UIScrollView
返回顶部呢?其实前面的思路已经很接近了,自定义一个可以覆盖statusBar
的视图就可以了,当然为了更好的复用,本文中自定义了一个继承自NSObject
的TopWindow
。
实现代码
为了方便在复杂的界面逻辑中,很好的使用,我们自定义一个
TopWindow
继承自NSObject
,由于在AppDelegate
创建一个新的窗口必须给这个窗口设置一个根控制器,否则会报错,我们还要创建一个根控制器TopWindowRootVC
。这样写的好处是可以在任意地方使用。
在TopWindow
的.h中提供两个方法。
+(void)show;+(void)hide;
.m的实现中,在initialize
方法中对window
进行初始化操作
windowTop = [[UIWindow alloc]initWithFrame:CGRectMake(0, 0, KBLScreenWidth, 20)];windowTop.backgroundColor = [UIColor clearColor];windowTop.windowLevel = UIWindowLevelStatusBar + 1.0f;windowTop.rootViewController = [TopWindowRootVC new];
实现.h中提供的两个方法:
+(void)show{ windowTop.hidden = NO;}+(void)hide{ windowTop.hidden = YES;}
TopWindowRootVC
的touchBegan
方法中完成操作,提供了一个searchView
方法
UIWindow *window = [UIApplication sharedApplication].keyWindow;[self searchView:window];
searchView
方法中我们需要找到我们需要滚动的scrollView
-(void)searchNeedScrollView:(UIView *)window{ [self dumpView:window atIndent:0]; for (UIScrollView *scrollV in _arr) { if (/* 需要滚动的视图 */) { CGPoint offset = scrollV.contentOffset; offset.y = -scrollV.contentInset.top; [scrollV setContentOffset:offset animated:YES]; } }}
递归遍历window的所有子视图
- (void)dumpView:(UIView *)aView atIndent:(int)indent{ for (UIView *view in [aView subviews]){ if ([view isKindOfClass:[UIScrollView class]]) { [_arr addObject:view]; } [self dumpView:view atIndent:indent + 1]; }}
运行结果:以两个tableView为例
总结
- 系统的
UIScrollView
自带有点击顶部状态栏自动返回顶部的效果 - 当视图中只有一个
UIScrollView
时,点击顶部状态栏自动返回顶部 - 当视图中有多个
UIScrollView
时:- 如果只有一个
UIScrollView
的scrollsToTop
属性值为YES
,则该UIScrollView
具有返回顶部的效果,其他UIScrollView
不具有该效果。 - 如果多个
UIScrollView
的scrollsToTop
属性值为YES
,则所有UIScrollView
都不具有该效果。
- 如果只有一个
- 如果想同时让多个
UIScrollView
自动返回顶部,需要自定义一个可以覆盖statusBar
的UIWindow,而非UIView。
- iOS 点击状态栏返回顶部(多scrollView的实现)
- iOS点击状态栏回到顶部(一个控制器中包含多个scrollview,系统自带的回到顶部失效)
- iOS 点击状态栏回滚scrollView顶部
- ios 点击返回顶部效果的实现,类似单击状态栏效果
- ios设置点击状态栏返回到顶部
- ios设置点击状态栏返回到顶部
- 多个tableView点击状态栏返回顶部
- Android实现ios点击状态栏回到顶部效果(直接转的网址)
- 点击返回顶部的实现
- 多个tableview 点击状态栏当前scrollView滚动到顶部
- android如何实现类似ios点击状态栏回到顶部功能
- Swift - 点击状态栏使tableView返回顶部(附:状态栏点击事件响应)
- 瀑布流学习、 点击状态栏返回顶部、 点击按钮返回顶部、Label透明度字体跟着变浅的解决方法
- 【Android】Scrollview返回顶部,快速返回顶部的功能实现,详解代码。
- iOS中点击首页返回屏幕顶部的代码实现与步骤
- 用js实现简单的点击返回顶部效果
- 用js实现简单的点击返回顶部效果
- 【web布局】点击按钮返回页面顶部的功能实现
- linux 时间同步
- 前端循路
- 计蒜客 A+B+C
- 何必如此
- wireshark
- iOS 点击状态栏返回顶部(多scrollView的实现)
- android开发中控件editText对应的inputType的类型总结
- 树套树之线段树套线段树(POJ2155 Matrix)
- 《Python编程》笔记(十二)
- Event Handling Guide for iOS--(三)---Event Delivery: The Responder Chain(翻译)
- SMTP与ESMTP的关系和区别
- ios developer tiny share-20160811
- method="get/post",两种方式的区别
- 64位winform程序无法打开设计视图