我正在研究BNR iOS编程手册的第7章,但我遇到了一个问题。在本章开头,我设置了一个UIViewController(HypnosisViewController)和一个UIView(HypnosisView),它响应了上一章中的运动事件。
我在AppDelegate.m文件中创建了UIViewController:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
HypnosisViewController *hvc = [[HypnosisViewController alloc] init];
[[self window] setRootViewController:hvc];
...
}
在HypnosisViewController中,我将HypnosisView设置为第一响应者:
- (void)loadView
{
// Create a view
CGRect frame = [[UIScreen mainScreen] bounds];
HypnosisView *view = [[HypnosisView alloc] initWithFrame:frame];
[self setView:view];
[view becomeFirstResponder];
}
在HypnosisView中,我确保向canBecomeFirstResponder返回YES。不幸的是,HypnosisView没有像以前那样对动作事件作出反应。当我最终继续前进时,我发现了一个有趣的发现。如果我将HypnosisViewController移动到UITabBarController中,HypnosisView会开始响应运动事件。代码看起来像这样:
HypnosisViewController *hvc = [[HypnosisViewController alloc] init];
UITabBarController *tabBarController = [[UITabBarController alloc] init];
NSArray *viewControllers = [NSArray arrayWithObjects:hvc, <insert more objs here>, nil];
[tabBarController setViewControllers:viewControllers];
[[self window] setRootViewController:tabBarController];
当HypnosisViewController设置为RootViewController时,为什么HypnosisView不成为第一响应者?为什么一旦HypnosisViewController放在另一个控制器内,它就开始工作了?我对RootViewController缺少什么?
谢谢!
答案 0 :(得分:2)
你的问题很贴切。我也在研究同一本书并且在同一章。问题是,在我们使用UITabBarController之前,我们要么使用HypnosisViewController,要么使用TimeViewController。然后我们将在AppDelegate.m文件中执行[self.window setRootViewController:hvc]或[self.window setRootViewController:tvc]。在这种情况下,setRootViewController方法在内部调用loadView方法。因此,如果loadView应该被调用,那么winsFirstResponder(根据你的代码作为方法调用驻留在其中)也应该被触发。所以内部的canBecomeFirstResponder应该被调用 现在当我们使用UITabBarController时,事情往往会破裂。会发生什么,而不是通过'[[self window] setRootViewController:tabBarController]调用loadView;'代码行,它通过'[tabBarController setViewControllers:viewControllers];'调用。所以底线是rootViewController属性(当设置为tabBarController时)不调用loadView方法,因此不调用'becomeFirstResponder'。您可能会争辩说,通过'[tabBarController setViewControllers:viewControllers];'调用loadView。但是setViewControllers不用于设置root viewController。 当我遇到这个问题时,我明确地调用了firstFirstResponder。方法如下: -
@implementation HypnoTimeAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions //method of UIApplicationDelegate protocol
{
NSLog(@"lets begin");
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
HypnosisViewController *viewController= [[HypnosisViewController alloc] init];
TimeViewController *viewController2= [[TimeViewController alloc] init];
NSLog(@"view controllers are done initializing!");
UITabBarController *tabBarController= [[UITabBarController alloc] init];
NSArray *viewControllers= [NSArray arrayWithObjects:viewController,viewController2, nil];
[tabBarController setViewControllers:viewControllers];//loadView of HypnosisViewController gets called internally since the 'app view' isn't going to load from a XIB file but from 'HypnosisView.m'.loadView method of TimeViewController loads its own view from the XIB file.
[self.window setRootViewController:tabBarController];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
@implementation HypnosisViewController
-(void)loadView{
NSLog(@"HypnosisView loading...");
HypnosisView *myView= [[HypnosisView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.view= myView;
[self configureFirstResponder];//configuring first responder
}
-(void) configureFirstResponder{
BOOL viewDidBecomeFirstResponder= [self.view becomeFirstResponder];
NSLog(@"Is First Responder set as HypnosisView? %i",viewDidBecomeFirstResponder);
}