当使用becomeFirstResponder为UISearchController的UISearchBar指定焦点时,键盘不会出现。

32
我花了很多时间在网上搜索,并与其他开发人员交谈,但仍然找不到解决此问题的方法。这个问题的具体描述可以在Stack Overflow的这个帖子中找到(Focus on the UISearchBar but the keyboard not appear),虽然它已经很多年了。
最近我从使用已弃用的IB中的UISearchDisplayController和UISearchBar切换到使用iOS8代码中的UISearchController。
但是我遇到的问题是,尽管焦点被正确地分配(您可以看到加载视图后取消按钮会动画显示在搜索栏的右侧),但键盘并没有显示出来。
下面是我的代码。
.h
@property (nonatomic, strong) UISearchController *searchController;

.m

- (void)viewDidLoad {
    [super viewDidLoad];
    ...
    [self initializeSearchController];
    ....
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self.searchController setActive:YES];
    [self.searchController.searchBar becomeFirstResponder];
}

- (void)initializeSearchController {
    self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
    self.searchController.searchResultsUpdater = self;
    self.searchController.dimsBackgroundDuringPresentation = NO;
    self.searchController.delegate = self;
    self.searchController.searchBar.delegate = self;
    [self.searchController.searchBar sizeToFit];

    [self.tableView setTableHeaderView:self.searchController.searchBar];
    self.definesPresentationContext = YES;
}

我目前尝试过的方法:

  • 按照另一个SO帖子的建议,在0.2秒的延迟后调用了becomeFirstResponder。

  • 我在viewDidAppear中设置了断点,并验证了self.searchController和self.searchController.searchBar都是有效的对象,都不为nil。

  • 我尝试遵循UISearchControllerDelegate并使用以下代码片段:

这里:

- (void)didPresentSearchController:(UISearchController *)searchController {
    //no matter what code I put in here to becomeFirstResponder, it doesn't
    //matter because this is never called, despite setting the     
    //self.searchController.delegate = self AND 
    //self.searchController.searchBar.delegate = self.
}
  • 我从storyboards中从头创建了一个新的视图,并进行了跳转,以确保我的视图中没有旧的searchBar残留。但这也没有起作用。

  • 我只在真实设备(iPhone 6)上测试过,这不是模拟器无法显示键盘的问题。

我已经没有更多的想法了,并且我已经看过与此相关的每个问题和答案。什么都没用。

再次澄清一下,searchBar正确地成为第一个响应者,证明了右侧的取消按钮正在屏幕上动画显示,但是键盘没有出现,搜索栏中的光标也没有闪烁。


1
你在实际设备上测试过吗?如果这个问题发生在模拟器上,请尝试按下⌘K(command-k)来弹出键盘。 - benhameen
1
@benhameen 是的,我只在我的 iPhone 6 上测试过这个。 - chris P
10个回答

21

您的代码看起来没问题。您所描述的不是正常行为。 首先,您可以创建一个只有UISearchController功能的新项目,看看情况如何。 您可以在问题中编辑它,以便我们能够更好地了解。

这里有一个很好的例子说明如何实现UISearchController: Sample-UISearchController

添加:

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [self.searchController.searchBar becomeFirstResponder];
}

对于iPad和iPhone使用iOS 8.3,在启动时可以看到期望的结果并弹出键盘,检查这个项目并查看您所做的不同之处。

编辑:

显然,如果在调用[self.searchController setActive:YES]之前调用becomeFirstResponder,则键盘不会显示。我想知道这是否是一个错误。


请注意,此问题不涉及(已弃用的)UISearchDisplayController - Felix
链接中的项目正在使用 UISearchController。抱歉打错字了。(已修正) - Segev
1
成功了!奇怪的是,当在问题中的代码中调用[self.searchController setActive:YES]之前,键盘并没有出现。 - Felix
有趣。我想知道那是不是一个bug。很高兴你找到了问题所在。我会用你的发现来修改我的答案。 - Segev
我尝试在使搜索栏成为第一响应者之后调用set搜索控制器活动的方法。对我来说仍然不起作用。我正在与导航控制器一起使用它。不确定这是否有区别。 - Jeremy Hicks

19

我遇到了同样烦人的问题。你可能认为将SearchController设置为活动状态会同时显示搜索控制器和键盘。不幸的是,它只做了第一部分。

我的解决方案

  • 在viewDidAppear中使搜索控制器处于活动状态:

override func viewDidAppear(animated: Bool) {
  super.viewDidAppear(animated)
  resultSearchController.active = true 
}
  • 一旦它被激活,在didPresentSearchController中将其设为第一个响应者

  • func didPresentSearchController(searchController: UISearchController) {
      searchController.searchBar.becomeFirstResponder() 
    }
    

    6
    对我来说不起作用。didPresentSearchController被调用了,但键盘没有出现。 - Felix
    它对我有效,尽管第二个代码示例似乎有一个小错误(我将提交一个编辑)。我宁愿控制器和键盘同时出现,但现在这样做也可以。 - Garrett Albright
    在我的iOS9上也可以运行。非常烦人的问题。我快要放弃了。谢谢。 - AXE
    7
    有人知道为什么当搜索栏在导航栏中时,这个功能在iOS9上不起作用吗? - Valentin
    9
    只有当我在主线程上将搜索栏设置为第一响应者时,这个方法对我有效: dispatch_async(dispatch_get_main_queue(), { searchController.searchBar.becomeFirstResponder() }) - vinsanity555

    13

    解决方案:Swift 3.0 (iOS 10):

        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
            searchController.isActive = true
            DispatchQueue.main.async { [unowned self] in
                self.searchController.searchBar.becomeFirstResponder()
            }
        }
    

    1
    对我没用。我的搜索栏在导航栏中。不知道是否与此有关。 - Bagusflyer
    不确定这是否是最干净的解决方案,但对我来说有效。谢谢! - Cesare
    1
    这对我在iOS 11上起作用,去掉了isActive设置,其他上面的解决方案没有帮助。 - C. Bess

    7
    在iOS 9上,我发现将becomeFirstResponder()延迟到下一个运行循环就足够了。
    func focusSearchField() {
        searchController?.active = true
    
        // skipping to the next run loop is required, otherwise the keyboard does not appear
        dispatch_async(dispatch_get_main_queue(), { [weak self] in
            self?.searchController?.searchBar.becomeFirstResponder()
        })
    }
    

    在 iOS 9 上,对我有效的唯一方法是使用[unowned self]来避免对self的强制解包操作。在我看来,这样更加干净、安全。 - tonymontana

    3

    解决方案:

    在调用becomeFirstResponder之前不要使用[self.searchController setActive:YES]。

    - (void)viewDidAppear:(BOOL)animated {
       [super viewDidAppear:animated];
       dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_async(dispatch_get_main_queue(), ^{
           // [self.searchController setActive:YES];
            [self.searchController.searchBar becomeFirstResponder];
         });
     });
    }
    

    1
    在iOS 11中对我有效。 - SAHM

    2
    以下是可行的解决方案:
    1.在显示UISearchController的视图控制器中覆盖ViewDidLayoutSubviews 2.覆盖ViewDidLayoutSubviews,并使搜索栏成为第一个响应者。
    已在iOS > 9.0上测试
    注意:在使其成为第一个响应者之前,请进行空值检查。
    if((searchController != null)&&(searchController.SearchBar != null))
                searchController.SearchBar.BecomeFirstResponder();
    

    这是因为在按下取消按钮时,ViewDidLayoutSubviews也会被调用。

    这对我在Xamarin中起作用了。


    2

    在iOS 10中,我必须在主线程上运行委托方法中的代码。首先,我在viewDidAppear中将active设置为YES。

    -(void)viewDidAppear:(BOOL)animated{
        [super viewDidAppear:animated];
          [self.searchController setActive:YES];
    }
    

    然后在委托方法中:

    - (void)didPresentSearchController:(UISearchController *)searchController
    {
      dispatch_async(dispatch_get_main_queue(), ^{
      [searchController.searchBar becomeFirstResponder];
      });
    }
    

    0

    0

    我在使用UISearchBar时遇到了问题,无法显示键盘。

    [searchBar becomeFirstResponder];
    

    通过在网络上搜索,我发现这个thread位于苹果开发者网站上,它帮助我发现如果没有关键窗口,键盘是不会打开的。
    我正在处理的应用程序像这样做:
    1. 窗口 A(关键窗口)
    2. 做一些事情
    3. 打开窗口 B(关键窗口)
    4. 做一些事情
    5. 关闭窗口 B(放弃关键窗口)
    我只需要做:
    [[[[UIApplication sharedApplication] windows] firstObject] makeKeyWindow];
    

    在窗口B退出后,键盘不再出现问题。


    0
    -(void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
        [self.searchController setActive:YES];
    }
    
    //and then in the delegate method:
    
    - (void)didPresentSearchController:(UISearchController *)searchController
    {
      dispatch_async(dispatch_get_main_queue(), ^{
      [searchController.searchBar becomeFirstResponder];
      });
    }
    
    //The above works for me in addition to this I had to add:
    -(void)viewWillDisappear:(BOOL)animated {
        [searchController setActive:NO];
    }
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接