谈一谈拦截导航控制器返回事件(上)——OPP
2017-06-19 10:43
381 查看
iOS中,UINavigationController 是一个很好用的导航栏控制器,它可以很方便的控制controller 的显示,弹出。操作原理是一个栈,先进后出。
导航栏点击返回时, 会把刚压入栈的controller 弹出,这些已经封装好,不用我们做什么。但有时我们会有一个场景:比如我们填写一个表单时,用户点击了返回按钮,我们这时应该弹出提示,确定退出,但用户确定后,才pop 出这个controller。这时就需要我们拦截返回事件,通常做法就是在当前controller自定义返回按钮,这种做法最简单,但缺点也很明显:
1.每个需要拦截的controller都需要自定义按钮,造成代码冗余。
2.自定义的按钮与系统按钮样式有差别。
那我们这里利用OPP的思想,我们自己封装一个CustomizedNavigationController,继承于UINavigationController,扩展它的功能。CustomizedNavigationController 扩展的功能就是当 push 进来一个controller 时,给他们设置统一样式的返回按钮。所以我们在CustomizedNavigationController 重写:
继承父类行为的同时,也扩展相应的功能,添加自定义的返回按钮,拥有它的点击事件:
通过上面的方法,我们都所有push 进来的控制器统一的添加了返回按钮,但有的controller 需要拦截,有的controller 不需要拦截,这就需要controller 告诉我们,对于所有push 进来的控制器来说,这是一个统一的行为。所以我们需要一个父类拥有这个行为,那么他的子类也会继承父类这个行为,只不过每个子类的实现不同。
需要拦截子类的实现:
但用户点击返回按钮时,执行 viewControllerShouldPop 方法,返回true,我们pop controller,返回false,不执行任何操作。
效果如下:
面向对象编程中,我们在父类中定义了一个行为,然后他的子类也都拥有了此行为,不用我们每个子类中在定义一遍,不必造成代码冗余。我们也可以在子类中重写父类的方法,实现不同的功能。但缺点也很明显,从上面的例子我们可以看出:
1.我们必须使用自定义的NavigationController,如果我们不使用CustomizedNavigationController,就无法实现给controller设置自定义的返回按钮。
2.我们要想拥有 viewControllerShouldPop 这个行为时,必须要继承于 BaseViewController,如果controller 不继承于BaseViewController,但push 进来时,因找不到viewControllerShouldPop 方法,程序势必会崩溃。
这不我们不愿看到的。其实我们只想在push 这个点去执行一段我们自己的代码片段,难道只能重写父类的方法吗?
还好我们有AOP(面向切面编程),这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。
OK,那下章我们就来讨论一下如何用AOP实现上述功能。
源码:https://github.com/pzhtpf/CustomizedNavigationController
导航栏点击返回时, 会把刚压入栈的controller 弹出,这些已经封装好,不用我们做什么。但有时我们会有一个场景:比如我们填写一个表单时,用户点击了返回按钮,我们这时应该弹出提示,确定退出,但用户确定后,才pop 出这个controller。这时就需要我们拦截返回事件,通常做法就是在当前controller自定义返回按钮,这种做法最简单,但缺点也很明显:
1.每个需要拦截的controller都需要自定义按钮,造成代码冗余。
2.自定义的按钮与系统按钮样式有差别。
那我们这里利用OPP的思想,我们自己封装一个CustomizedNavigationController,继承于UINavigationController,扩展它的功能。CustomizedNavigationController 扩展的功能就是当 push 进来一个controller 时,给他们设置统一样式的返回按钮。所以我们在CustomizedNavigationController 重写:
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
继承父类行为的同时,也扩展相应的功能,添加自定义的返回按钮,拥有它的点击事件:
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated{ [super pushViewController:viewController animated:animated]; [self setBackBarButtonItem:viewController]; }
通过上面的方法,我们都所有push 进来的控制器统一的添加了返回按钮,但有的controller 需要拦截,有的controller 不需要拦截,这就需要controller 告诉我们,对于所有push 进来的控制器来说,这是一个统一的行为。所以我们需要一个父类拥有这个行为,那么他的子类也会继承父类这个行为,只不过每个子类的实现不同。
#import "BaseViewController.h" @interface BaseViewController () @end @implementation BaseViewController -(BOOL)viewControllerShouldPop{ return true; //默认不拦截 }
需要拦截子类的实现:
#import "OPPInterceptViewController.h" @interface OPPInterceptViewController () @end @implementation OPPInterceptViewController -(BOOL)viewControllerShouldPop{ // 这里写 UIAlertController 询问用户 return NO; }
但用户点击返回按钮时,执行 viewControllerShouldPop 方法,返回true,我们pop controller,返回false,不执行任何操作。
if([viewController viewControllerShouldPop]){ [self popViewControllerAnimated:YES]; }
效果如下:
面向对象编程中,我们在父类中定义了一个行为,然后他的子类也都拥有了此行为,不用我们每个子类中在定义一遍,不必造成代码冗余。我们也可以在子类中重写父类的方法,实现不同的功能。但缺点也很明显,从上面的例子我们可以看出:
1.我们必须使用自定义的NavigationController,如果我们不使用CustomizedNavigationController,就无法实现给controller设置自定义的返回按钮。
2.我们要想拥有 viewControllerShouldPop 这个行为时,必须要继承于 BaseViewController,如果controller 不继承于BaseViewController,但push 进来时,因找不到viewControllerShouldPop 方法,程序势必会崩溃。
这不我们不愿看到的。其实我们只想在push 这个点去执行一段我们自己的代码片段,难道只能重写父类的方法吗?
还好我们有AOP(面向切面编程),这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。
OK,那下章我们就来讨论一下如何用AOP实现上述功能。
源码:https://github.com/pzhtpf/CustomizedNavigationController
相关文章推荐
- 谈一谈拦截导航控制器返回事件(下)——AOP
- 截获导航控制器系统返回按钮的点击pop及右滑pop事件
- 导航控制器全屏滑动返回效果
- 自定义导航栏返回按钮--拦截push方法实现
- ios 8行代码教你搞定导航控制器全屏滑动返回效果
- iOS 中导航控制器全屏向右滑动返回上一界面
- 8行代码教你搞定导航控制器全屏滑动返回效果
- Android AccessibilityService拦截事件及VR眼镜返回按键捕捉
- Springmvc前端控制器以.html后缀拦截,访问接口返回406问题
- 8行代码教你搞定iOS导航控制器全屏滑动返回效果
- [一句秒懂]拦截iOS系统导航栏返回按钮事件-三种方法
- 8行代码教你搞定导航控制器全屏滑动返回效果
- 从当前带导航的控制器返回到前面的某个控制器
- 重写导航控制器,利用重写pop和push方法来隐藏底层的tabbar和其他一些事件
- Android开发-- 拦截返回键事件
- Android拦截、监听系统返回键事件
- Swift - 导航控制器(navigationController)全屏滑动返回功能实现
- 系统返回按钮事件拦截
- ios 8行代码教你搞定导航控制器全屏滑动返回效果
- ios 导航控制器UInavigationController跳转以及返回传值