最近在项目中处理了一个UIScrollView右滑返回上级页的问题,刚好项目中也使用了FDFullscreenPopGesture这个全屏返回的库,于是来分析它的实现吧。
这个库是sunngxx之前在百度的时候弄的,已经好久没有更新了,不过目前还能用,star也已经有5k多了,而且sunngxx这种runtime小王子,写的这个库几乎所有函数都是runtime实现,还是很有学习的价值的。
FDFullscreenPopGesture是以一个分类文件的形式提供给使用者,在内部重写了+(void)load;方法,只要把代码集成到项目中就可以使用全屏返回了。
先来看一下头文件中的内容,首先是UINavigationController的分类
|
|
第一个属性是当前实际相应右滑的手势对象,这个对象替换了系统的手势对象,具体咋替换的后面在说。
第二个属性设置是否使用fd的方法去控制导航栏的显示隐藏。
然后我们看一下UIViewController的分类:
|
|
- fd_interactivePopDisabled:当前页面是否支持右滑返回
- fd_prefersNavigationBarHidden:控制当前页面导航栏的显示隐藏
- fd_interactivePopMaxAllowedInitialDistanceToLeftEdge:右滑返回触发的位置,这里是距离左边距的距离。
全屏返回
我们先来看一下全屏返回的实现。
|
|
上面的代码展示了fd是怎么一步步的替换了系统的右滑手势的,其他部分比较好理解,这里我们来重点看一下替换代理的部分,如下:
|
|
这里,先判断当前view的手势列表中是否包含我们自定义的右滑手势,如果不包含,先将自定义手势add到手势列表中,然后重点来了,获取interactivePopGestureRecognizer这个系统右滑返回手势的所有target,然后取出该手势的第一响应者,然后生成系统返回手势处理函数(handleNavigationTransition)的SEL结构体,然后设置自定义手势的代理,最后将系统的target和SEL添加给自定义的手势对象,并将系统的返回手势关闭。这样,fd就可以通过自定义的代理控制右滑返回了。
隐藏导航栏
看完了右滑返回,再看一下fd是如何隐藏系统导航栏的。
|
|
隐藏这个就比较简单了,也是在fd_pushViewController里面处理的,具体说一下,这里先生成一个用来隐藏导航栏的block,使用的方法还是系统的setNavigationBarHidden:animation 方式。然后将这个block赋值给self.fd_willAppearInjectBlock,然后再每次fd_viewWillAppear时,会调用一下这个block。
总结
可以看到,代码大量的使用runtime来编写,学习一遍下来对应runtime相关的内容会有更深刻的认识。然后就是fd替换系统方法的这种骚操作,如果有类似的需求的话也是可以参考的。这个库代码也不太多,内容也比较好理解,个人觉得有学习的价值。