【问题标题】:Show a preloaded search results?显示预加载的搜索结果?
【发布时间】:2012-05-30 20:54:41
【问题描述】:

我有一个带有搜索栏的非 tableview 视图,虽然它工作得很好,但当搜索栏中有一个空字符串时,搜索显示控制器会隐藏 table view 并覆盖一个暗色的视图。我希望它在搜索栏中显示空字符串时显示预加载的数据,而不是隐藏表格视图并覆盖搜索栏下方的暗色视图。就像 iOS 版 Safari 中的 Google 搜索栏的工作方式一样。

我之前在 stackoverflow 上发现了一个类似的问题: UISearchDisplayController - how to preload searchResultTableView,我真的无法让它工作。

获取预加载数据并将当前数据设置为它没有问题,但我不确定如何防止显示控制器删除 searchResultsTableView。

提前致谢。

【问题讨论】:

    标签: objective-c ios uisearchbar xcode4.3 uisearchdisplaycontroller


    【解决方案1】:

    我终于找到了一种方法来做到这一点。

    我发现 searchDisplayController 只是从超级视图中删除了 searchResultsTableView,所以每当显示控制器试图隐藏表格视图时,我就将表格视图添加回超级视图:

    - (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
    {
        // add the tableview back in
        [self.view addSubview:self.searchDisplayController.searchResultsTableView];
    }
    

    然后我还必须在第一次单击搜索栏时显示 tableview,所以我这样做了:

    - (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
    {
        // after the data has been preloaded
        self.searchResults = self.allItems;
        [self.searchDisplayController.searchResultsTableView reloadData];
    }
    
    - (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller
    {
        [self.view addSubview:self.searchDisplayController.searchResultsTableView];
    }
    

    对我来说,“allItems”是我存储所有可搜索项目的位置,“searchResults”是存储过滤项目(搜索后)的位置。当然,您必须在重新加载数据之前预加载项目(例如搜索历史)。

    我不知道这在性能方面是否是一种好方法,但它对我来说非常有效,我希望这对其他人也有用。如果有更好的方法可以做到这一点,请发表评论。

    【讨论】:

    • 几天来一直在尝试解决这个问题!感谢您的解决方案!
    • 在测试了这个实现之后,我现在想弄清楚如何让搜索结果容器在添加到视图时不闪烁。由于它是通过searchDisplayControllerDidBeginSearch: 方法添加的,因此在显示searchResultsTableView 之前,您可以在一瞬间看到昏暗的背景。关于如何解决这个问题的任何想法?我尝试将searchDisplayControllerDidBeginSearch 中的代码行移动到searchDisplayControllerWillBeginSearch' method, but that causes the dim background to be placed in front of the searchResultsTableView`
    • 这不再适用于 iOS 7。有人有可行的解决方案吗?
    • 是的,这在 iOS 8 中不起作用。有人有解决方案吗?
    【解决方案2】:

    当您开始搜索时,此方法会被调用。添加 searchResultsTableView 并取消隐藏它。然后它将显示您已经预加载的数据。我必须预先加载您的数据才能使其正常工作。

    - (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller
    {
        CGRect testFrame = CGRectMake(0, self.notesSearchBar.frame.size.height, self.notesSearchBar.frame.size.width, self.view.frame.size.height - self.notesSearchBar.frame.size.height);
        self.searchDisplayController.searchResultsTableView.frame = testFrame;
        [self.notesSearchBar.superview addSubview:self.searchDisplayController.searchResultsTableView];
    
    //    [self.view addSubview:self.searchDisplayController.searchResultsTableView];
        controller.searchResultsTableView.hidden = NO;
    }
    
    -(void) searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
    {
        CGRect testFrame = CGRectMake(0, self.notesSearchBar.frame.size.height, self.notesSearchBar.frame.size.width, self.view.frame.size.height - self.notesSearchBar.frame.size.height);
        self.searchDisplayController.searchResultsTableView.frame = testFrame;
        [self.notesSearchBar.superview addSubview:self.searchDisplayController.searchResultsTableView];
    
        //    [self.view addSubview:self.searchDisplayController.searchResultsTableView];
        controller.searchResultsTableView.hidden = NO;
    }
    
    
    -(void) searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
    {
        controller.searchResultsTableView.hidden = YES;
    }
    

    【讨论】:

      【解决方案3】:

      数小时后,我终于找到了适用于 iOS 7 的解决方案

      只需在你的 UISearchDisplayDelegate 中实现以下两个方法

      -(void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView {
      
          // We need to prevent the resultsTable from hiding if the search is still active
          if (self.searchDisplayController.active == YES) {
              tableView.hidden = NO;
          }
      }
      

      搜索开始时,searchResultsTableView 会自动隐藏,所以我们需要再次取消隐藏

      - (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
      
          controller.searchResultsTableView.hidden = NO;
      
          // Then we need to remove the semi transparent overlay which is here
          for (UIView *v in [[[controller.searchResultsTableView superview] superview] subviews]) {
      
              if (v.frame.origin.y == 64) {
                  [v setHidden:YES];
              }
          }
      
      }
      

      【讨论】:

      • 这对我来说在 iOS7 上不起作用。相反,我检查了 (v.alpha
      【解决方案4】:

      我为这个问题找到了一个好多更好的解决方案,而且它似乎在 iOS 6 和 7 上完美运行。虽然它仍然是一个 hack,但它比上面的更干净和面向未来的 hack .其他解决方案无法始终如一地工作,并阻止某些 UISearchDisplayDelegate 方法触发!此外,我遇到了复杂的嵌入问题,我无法用上述方法解决。其他解决方案的主要问题是它们严重混淆了 UISearchDisplayController 的内部结构。我的解决方案是基于观察 UISearchDisplayContoller 是 UISearchbarDelegate 并且可以通过模拟搜索字段中的按键来触发结果表的自动取消调暗和显示!所以:

      - (void) searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller 
      {
          if ([controller respondsToSelector: @selector(searchBar:textDidChange:)])
              [(id<UISearchBarDelegate>)controller searchBar: controller.searchBar textDidChange: @" "];
      }
      

      此代码通过检查它是否响应 UISearchbarDelegate 方法来防止崩溃,并发送空格 @" " 以欺骗 UISearchDisplayController 认为用户输入了一个字母。

      现在,如果用户键入内容然后将其删除,表格将再次变暗。其他解决方案尝试通过在 searchDisplayController:didHideSearchResultsTableView: 方法中执行某些操作来解决此问题。但这对我来说没有意义,因为当您取消搜索时,它肯定需要真正隐藏您的结果表,并且在这种情况下您可能需要运行代码。我对此部分的解决方案是子类化(请注意,如果您的项目需要,您可能会使用 Method Swizzled Category 使其在任何地方都能工作):

      // privately declare protocol to suppress compiler warning
      @interface UISearchDisplayController (Super) <UISearchBarDelegate>
      @end
      
      // subclass to change behavior
      @interface GMSearchDisplayController : UISearchDisplayController
      @end
      
      @implementation GMSearchDisplayController
      
      - (void) searchBar: (UISearchBar *) searchBar textDidChange: (NSString *) searchString
      {
          if (searchString.length == 0)
              searchString = @" ";
          if ([super respondsToSelector: @selector(searchBar:textDidChange:)])
              [super searchBar: searchBar textDidChange: searchString];
      }
      
      @end
      

      此代码通过拦截 textDidChange 委托方法并将 nil 或空字符串更改为空格字符串 @" " 来防止在空搜索栏上发生的正常隐藏/变暗。如果您使用的是第二位代码,那么您可以修改第一位以传递 nil 而不是 @" ",因为第二位将为您完成所需的到 @" " 的转换。

      在我自己的项目中,我需要处理用户输入空格的情况,所以我使用了一个定义的标记来代替上面的@" ":

      // arbitrary token used internally
      #define SEARCH_PRELOAD_CONDITIONAL @"_#preresults#_"
      

      然后通过将其转换回 nil 字符串在内部进行处理:

      - (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
      {
          if ([searchString isEqualToString: SEARCH_PRELOAD_CONDITIONAL])
              searchString = nil;
      }
      

      享受吧! :)

      【讨论】:

        【解决方案5】:

        这适用于 iOS 8:

        - (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
        {
          self.searchDisplayController.searchResultsTableView.hidden = NO;
        }
        
        - (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller
        {
            self.searchDisplayController.searchResultsTableView.hidden = NO;
            [self.searchDisplayController.searchResultsTableView.superview.superview bringSubviewToFront:self.searchDisplayController.searchResultsTableView.superview];
        
            CGRect frame = self.searchDisplayController.searchResultsTableView.frame;
            self.searchDisplayController.searchResultsTableView.frame = CGRectMake(frame.origin.x, 64, frame.size.width, frame.size.height);
        }
        

        【讨论】:

          【解决方案6】:

          iOS 9 工作代码。

          - (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
              // Bring the search table view to the view's front
              self.searchDisplayController.searchResultsTableView.hidden = NO;
              [self.searchDisplayController.searchResultsTableView.superview bringSubviewToFront:self.searchDisplayController.searchResultsTableView];
          }
          
          - (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView {
              // We need to prevent the resultsTable from hiding if the search is still active
              if (self.searchDisplayController.active == YES) {
                  tableView.hidden = NO;
              }
          }
          

          【讨论】:

            【解决方案7】:

            Swift 2.0+ 版本

            func searchDisplayControllerDidBeginSearch(controller: UISearchDisplayController) {
                controller.searchResultsTableView.hidden = false
                controller.searchResultsTableView.superview!.bringSubviewToFront(controller.searchResultsTableView)
            }
            
            func searchDisplayController(controller: UISearchDisplayController, didHideSearchResultsTableView tableView: UITableView) {
                if ((searchDisplayController?.active) != nil) {
                    tableView.hidden = false
                }
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-06-26
              • 2021-01-25
              • 2023-04-07
              • 2013-01-14
              • 2014-01-20
              • 1970-01-01
              相关资源
              最近更新 更多