UISearchBar 在 UISplitviewController Master 中不会响应

UISearchBar will not respond in UISplitviewController Master

我有一个非常标准的设置 UITableview 作为 UISplitviewController 中的主控制器,通用 iOS9 应用程序。

同样,标准票价,我插入了一个UISearchBar作为table的header。

self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.hidesNavigationBarDuringPresentation = NO;

[self.searchController.searchBar sizeToFit];
self.tableView.tableHeaderView = self.searchController.searchBar;

self.definesPresentationContext = YES;

无需在 iPhone 上显示我的其余代码、搜索和所有预期工作。我的问题是,当 iPad 上的 运行 时,搜索栏永远不会获得焦点或显示键盘。没有反应,似乎没有收到触摸。甚至不响应以编程方式尝试 becomeFirstResponder.

没有任何反应。

搜索栏可见且放置适当,没有底层或重叠问题。

它在 iPhone 上运行良好。接收触摸,呈现键盘,搜索工作。据推测,当 UISplitviewController 折叠时,呈现方式存在重大差异。经过数小时的搜索、大量的文档和我遇到的每个教程,我没有找到类似的经历,这令人惊讶。

补充说明:如果我在 iPad 上使用多任务处理将拆分视图缩小到折叠状态,搜索栏就会起作用,与在 iPhone 上一样。肯定和split view的折叠状态有关

更新:(越来越近)

经过进一步试验,我发现如果您横向启动应用程序,搜索栏可以在 iPad 上运行。在纵向模式下,我的主控制器是隐藏的。它通过选择 displayModeButtonItem 滑入,该 displayModeButtonItem 设置为细节控制器的 leftBarButtonItem。那就是当 searchBar 中断并且不再响应触摸时。

如果我从横向开始,然后旋转到纵向,它也会停止工作。旋转回横向并不能解决问题。一旦坏了,它就会一直坏到重新启动。

我尝试将 definesPresentationContext 移动到主控制器的 viewWillAppear 方法,但是没有效果。

进一步更新:

另外一个意想不到的情况是iPhone6plus的搜索栏完全没有问题。无论方向如何,折叠或不折叠都可以工作,也不管它从哪个状态开始。我希望这与横向时的 iPad 相同。完全适用于 iPhone.

我还是没弄明白。我最近的修复尝试是将所有搜索控制器初始化移至 viewDidLayoutSubviews 方法。没有任何变化。

此外,我注意到当搜索处于活动状态时,屏幕上的键盘,如果我旋转 iPad,键盘就会消失,但搜索栏仍然处于活动状态。一开始我没发现,然后我看到取消按钮仍然显示。它不会接收触摸并且没有键盘,但它显然仍然是第一响应者。

上传到 GitHub 的示例项目: Github Repository

注意 - 在我将 UISplitview Delegate 方法添加到项目之前没有任何问题。我想立即将其添加到我的问题中,因此,我什至还没有尝试确切地了解这些委托方法如何影响搜索栏,但显然问题是在某处产生的。

更新:

我尝试了更多变体但没有成功。

我还查看了分析器中的视图层次结构,搜索栏位于顶层,未被其他任何内容覆盖。

最终包装:

@tomSwift 解决方法确实解决了我在 iPad 上的问题。在进一步测试中,我发现它破坏了我的 iPhone UI。据推测,这更多是我自己的设置和创建 Master/Detail 视图控制器的时间问题。似乎一些重要的 objects 不再及时创建,因为可能细节视图控制器还不存在。我通过将关键项目移动到 App Delegate 来解决问题,但这变得笨拙而且我无法轻易缩小范围,所以我破解了一个修复程序:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
    splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
}

可能会有更优雅的解决方案,但这已经占用了我足够多的时间。现在一切正常。雷达归档- 28304096

这显然是 UISplitViewController and/or UISearchController 中的错误。一定要用 Apple 提交一份雷达并附上你的代码示例。

我认为该错误涉及 UISplitViewController.displayMode UISplitViewControllerDisplayModeAutomatic。当我将 preferredDisplayMode 更改为 UISplitViewControllerDisplayModeAllVisible 然后一切开始工作:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
    UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
    navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem;
    splitViewController.delegate = self;
    splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;

    return YES;
}

此更改的主要内容是 iPad 上纵向的默认布局,据我所知这可能并不理想。我还尝试将 preferredDisplayMode 设置为 UISplitViewControllerDisplayModeAllVisible,然后将其设置回 UISplitViewControllerDisplayModeAutomatic;在屏幕方向改变之前,这一直很好用——然后它又坏了。你可能会在这条路上走得更远。

我还在 AppDelegate 中添加了以下内容,以强制搜索控制器在 displayMode 更改时停用。 (我还必须在 MasterViewController 上公开公开 searchController 属性)。

- (void)splitViewController:(UISplitViewController *)svc willChangeToDisplayMode:(UISplitViewControllerDisplayMode)displayMode {

    UINavigationController *navigationController = [svc.viewControllers firstObject];
    MasterViewController* mvc = (MasterViewController*) navigationController.topViewController;
    [mvc.searchController setActive: NO];
}

研究了您的项目,发现问题在于您的搜索控制器从未设置为活动状态。所以我将 UISplitViewController 子类化并使其成为自己的委托,这样它就可以在模式更改时通知子视图控制器,这样您就可以在正确的时间将其设置为活动状态。

使用此委托方法创建通知:

- (void)splitViewController:(UISplitViewController *)svc willChangeToDisplayMode:(UISplitViewControllerDisplayMode)displayMode {
    NSLog(@"WILL CHANGE TO DISPLAY MODE: %ld", (long)displayMode);

    NSNumber *displayNumber = [NSNumber numberWithInteger:displayMode];
    NSDictionary *userInfo = @{ @"displayMode": displayNumber };
    NSNotification *modeChangedNotif = [NSNotification notificationWithName:@"modeChanged" object:nil userInfo:userInfo];
    [[NSNotificationCenter defaultCenter] postNotification:modeChangedNotif];
}

然后在您的 MasterViewController 中,您可以在 viewDidLoad 中执行此操作:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(modeChanged) name:@"modeChanged" object:nil];

在该方法中,您可以检查特定的 displayMode 枚举,但为了让它正常工作,我只是这样做了:

- (void) modeChanged {
    [self.searchController setActive:YES];
}