获取uiview的uiviewcontroller和rootviewcontroller

我们知道,对于一个视图控制器类UIViewController,可以通过[self view]来获取到它所管理的视图UIView,反过来,对于一个视图类UIView,我们怎么获取到它的UIViewController?

       UIView继承自UIResponder,UIResponder有一个实例方法- (UIResponder *)nextResponder,该方法返回响应链(responder chain)上的下一个对象。

       有关- (UIResponder *)nextResponder方法,更具体的说明可参考UIResponder Class Reference,主要有几个重点:

       1)UIResponder类不会自动存储和设置它的下一个响应者(the next responder),默认情况下nextResponder方法放回nil;

       2)UIResponder的子类必须重载nextResponder方法,设置下一个响应者。比如UIView类,当管理它的UIViewController对象存在时,返回该UIViewController,否则返回它的父视图(superview);UIViewController类返回它所管理的视图的父视图;UIWindow类返回应用对象(the application object);UIApplication类返回nil。


      一、获取view的controller对象:

  通过以上的分析,对于一个视图类UIView,我们可以利用- (UIResponder *)nextResponder方法遍历响应链,获取到它的UIViewController,具体代码:

[plain] view plaincopy
  1. @implementation UIView (FindUIViewController)  
  2.   
  3. - (UIViewController *)viewController {  
  4.     /// Finds the view's view controller.  
  5.       
  6.     // Traverse responder chain. Return first found view controller, which will be the view's view controller.  
  7.     UIResponder *responder = self;  
  8.     while ((responder = [responder nextResponder]))  
  9.         if ([responder isKindOfClass: [UIViewController class]])  
  10.             return (UIViewController *)responder;  
  11.       
  12.     // If the view controller isn't found, return nil.  
  13.     return nil;  
  14. }  
  15.   
  16. @end  


      二、获取rootViewcontroller对象:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. - (UIViewController *)getCurrentRootViewController {  
  2.   
  3.     UIViewController *result;  
  4.   
  5.     if (rootViewController)  
  6.     {  
  7.         // If developer provieded a root view controler, use it  
  8.         result = rootViewController;  
  9.     }  
  10.     else  
  11.     {  
  12.         // Try to find the root view controller programmically  
  13.   
  14.         // Find the top window (that is not an alert view or other window)  
  15.         UIWindow *topWindow = [[UIApplication sharedApplication] keyWindow];  
  16.         if (topWindow.windowLevel != UIWindowLevelNormal)  
  17.         {  
  18.             NSArray *windows = [[UIApplication sharedApplication] windows];  
  19.             for(topWindow in windows)  
  20.             {  
  21.                 if (topWindow.windowLevel == UIWindowLevelNormal)  
  22.                     break;  
  23.             }  
  24.         }  
  25.   
  26.         UIView *rootView = [[topWindow subviews] objectAtIndex:0];    
  27.         id nextResponder = [rootView nextResponder];  
  28.   
  29.         if ([nextResponder isKindOfClass:[UIViewController class]])  
  30.             result = nextResponder;  
  31.         else if ([topWindow respondsToSelector:@selector(rootViewController)] && topWindow.rootViewController != nil)  
  32.             result = topWindow.rootViewController;  
  33.         else  
  34.             NSAssert(NO, @"ShareKit: Could not find a root view controller.  You can assign one manually by calling [[SHK currentHelper] setRootViewController:YOURROOTVIEWCONTROLLER].");  
  35.     }  
  36.     return result;      
  37. }  

      三、让子类和父类都接收事件
当然, 你可能会说直接调用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获取到这个事件了

[[selfnextResponder]touchesBegan:toucheswithEvent:event];

}


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

{

[[selfnextResponder]touchesEnded:toucheswithEvent:event];

}


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

{

[[selfnextRespondertouchesCancelled:toucheswithEvent:event];

}


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

{

[[selfnextRespondertouchesMoved:toucheswithEvent:event];

}

另外需要注意的是:在重写这几个方法时,最好保证这几个方法都重写,否则事件响应链可能会变混乱。这是我的猜测哈,没有实际验证过。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值