适用范围,tabbar的子视图都是NavigationController,其它情况可以根据情况调整
- (UIViewController *)getCurrentVC{
UIViewController *result = nil;
UIWindow * window = [[UIApplication sharedApplication] keyWindow];
//app默认windowLevel是UIWindowLevelNormal,如果不是,找到UIWindowLevelNormal的
if (window.windowLevel != UIWindowLevelNormal)
{
NSArray *windows = [[UIApplication sharedApplication] windows];
for(UIWindow * tmpWin in windows)
{
if (tmpWin.windowLevel == UIWindowLevelNormal)
{
window = tmpWin;
break;
}
}
}
id nextResponder = nil;
UIViewController *appRootVC=window.rootViewController;
// 如果是present上来的appRootVC.presentedViewController 不为nil
if (appRootVC.presentedViewController) {
nextResponder = appRootVC.presentedViewController;
}else{
UIView *frontView = [[window subviews] objectAtIndex:0];
nextResponder = [frontView nextResponder]; <span style="font-family: Arial, Helvetica, sans-serif;">// 这方法下面有详解 </span>
}
if ([nextResponder isKindOfClass:[UITabBarController class]]){
UITabBarController * tabbar = (UITabBarController *)nextResponder;
UINavigationController * nav = (UINavigationController *)tabbar.viewControllers[tabbar.selectedIndex];
// UINavigationController * nav = tabbar.selectedViewController ; 上下两种写法都行
result=nav.childViewControllers.lastObject;
}else if ([nextResponder isKindOfClass:[UINavigationController class]]){
UIViewController * nav = (UIViewController *)nextResponder;
result = nav.childViewControllers.lastObject;
}else{
result = nextResponder;
}
return result;
}
- (nullableUIResponder*)nextResponder 解释
问题1。 如何调用父view的controller里面的方法?
答案如下:
[[self superview ].nextResponder method];
[[[self superview ] nextResponder] method];
[self.nextResponder method];
上面的都可以,看情况使用,使用的时候最好判断一下。
官方解释
UIView implements this method by returning the UIViewController object that manages it (if it has one) or its superview (if it doesn’t); UIViewController implements the method by returning its view’s superview; UIWindow returns the application object, and UIApplication returns nil.
问题2:当一个子view需要接收点击事件,而父view也需要接收点击事件, 如何做?
当然, 你可能会说直接调用mysubview.superView即可, 这样做也确实是可以做到,但有时子view是不一定知道有这个特定的父view的存在的,如动态添加子view。
所以这里就可以用到消息响应链拉技术。
下面要做的也就是,让子view接收这些事件后,同时把这些事件继续向上传,会一直传到UIApplication为止。 而在传的过程中,如果子view接收了这些事件,那么事件会自然终止,我们现在可以做的是同时让子view接收事件,而且还让事件不终止,并继续向上传。
摘取一部分说明:
“当用户 与 iPhone的触摸屏 产生 互动时,硬件 就会探测到 物理接触 并且 通知 操作系统。接着 操作系统 就会创建 相应的事件 并且 将 其 传递给 当前正在运行的应用程序的事件队列。然后 这项事件 会被事件循环 传递给 优先响应者物件。优先响应者物件 是 事件 被触发时 和 用户 交互的物件,比如 按钮物件、视图物件。如果 我们 编写了 代码 让 优先响应者 处理 这种类型的事件,那么 它 就会处理 这种类型的事件。处理完 某项事件后,响应者 有 两个选项:1、将 其 丢弃;2、将 其 传递给 响应链条中的下一个响应者。下一个响应者的地址 存储 在当前响应者物件所包含的变量nextResponder当中。如果 优先响应者 无法处理 一项事件,那么 这项事件 就传递给 下一个响应者,直到 这项事件 到达 能处理它的响应者 或者 到达 响应链条的末端,也就是 UIApplication类型的物件。UIApplication类型的物件 收到 一项事件后,也是 要么 处理,要么 丢弃。“
比如 有 一个视图物件,这个视图物件上 有 一个按钮物件。当用户 触摸 这个按钮物件时,作为优先响应者,这个按钮物件 就会收到 一项事件。如果 这个按钮物件 无法处理 这项事件,就会将 这项事件 传递给 视图物件。如果 视图物件 无法处理 这项事件,就会将 这项事件 传递给 视图控制器物件。以此类推。
应该注意的 是 当我们 在使用 响应链条时,一项事件 并不会自动地 从一个响应者 传递到 下一个响应者。如果 要将 一项事件 从一个响应者 传递到 下一个响应者,我们 必须编写 代码 才能办到。”
要做的如下:
子view的代码如下:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// 这里可以做子view自己想做的事,做完后,事件继续上传,就可以让其父类,甚至父viewcontroller获取到这个事件了
[[self nextResponder]touchesBegan:toucheswithEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[[self nextResponder]touchesEnded:toucheswithEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[[self nextResponder] touchesCancelled:toucheswithEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[[self nextResponder] touchesMoved:toucheswithEvent:event];
}
另外需要注意的是:在重写这几个方法时,最好保证这几个方法都重写,否则事件响应链可能会变混乱。这是我的猜测哈,没有实际验证过。
还有一种方法, cocoa在 app 生命周期变化是注册了系统级的通知,我们只需要在viewcontroller中监听一下就行,下面是常用通知的名字 , 还有很多, 写一个 command 进去看看吧 .
UIKIT_EXTERN NSNotificationName const UIApplicationDidFinishLaunchingNotification;
UIKIT_EXTERN NSNotificationName const UIApplicationDidBecomeActiveNotification;
UIKIT_EXTERN NSNotificationName const UIApplicationWillResignActiveNotification;
UIKIT_EXTERN NSNotificationName const UIApplicationDidReceiveMemoryWarningNotification;
UIKIT_EXTERN NSNotificationName const UIApplicationWillTerminateNotification
这个更加节省代码,而且很好用 .
---------------------
作者:想名真难
来源:CSDN
原文:https://blog.csdn.net/u014600626/article/details/51455354
版权声明:本文为博主原创文章,转载请附上博文链接!
另外需要注意的是:在重写这几个方法时,最好保证这几个方法都重写,否则事件响应链可能会变混乱。这是我的猜测哈,没有实际验证过。