【问题标题】:SearchBar disappears from headerview in iOS 7SearchBar 从 iOS 7 的 headerview 中消失
【发布时间】:2013-10-03 08:40:03
【问题描述】:

我有一个tableview 用于在我的应用程序中显示设备列表。当 viewWillAppear 被调用时,我添加了self.searchDisplayController.searchBar as a subview to a headerView。然后我分配self.tableView.tableHeaderView = headerView。它看起来像这样:

我向下滚动 tableview 以使 headerview 消失,然后通过点击单元格转到其他视图控制器。当我回到这个 tableView 时,向上滚动到 headerView,searchBar 变得不可见,但是在点击不可见区域时,searchDisplayController 被激活并且取消按钮不起作用。这仅适用于 iOS 7。为什么会这样?
注意:只有当我返回 tableViewController 时 headerView 不在视图中时才会发生这种情况。

【问题讨论】:

  • 在某处加个断点,看看headerView是否还存在。
  • @LordZsolt headerView 存在,因为我在 searchBar 左侧添加的按钮可见且正在工作。
  • 所以带有两个箭头和线条的按钮会显示,但搜索文本字段不会显示?
  • 是的...它们都作为子视图添加到添加到 headerView 的 UIView 中。出现按钮,但没有出现 searchBar。
  • 然后检查searchBar的视图是否存在。

标签: iphone objective-c uitableview ios7 uisearchbar


【解决方案1】:

我也遇到了同样的问题。当我在结束搜索状态下调试到 UISearchDisplayController 的委托方法时,searchBar 成为 UIView 的子视图,而不是 UITableView。请看以下代码:

- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
    //My Solution: remove the searchBar away from current super view,
    //then add it as subview again to the tableView
    UISearchBar *searchBar = controller.searchBar;
    UIView *superView = searchBar.superview;
    if (![superView isKindOfClass:[UITableView class]]) {
        NSLog(@"Error here");
        [searchBar removeFromSuperview];
        [self.tableView addSubview:searchBar];
    }
    NSLog(@"%@", NSStringFromClass([superView class]));
}

我的解决方案是将 searchBar 从当前超级视图中删除,然后将其作为子视图再次添加到 tableView。我已经测试成功了。 希望有所帮助!

问候

【讨论】:

  • 这很好,你发现了问题!但是关于您的解决方案还有一个警告:当从 superview 中删除 searchBar 并将其添加到 tableview 时,输入焦点会丢失!
【解决方案2】:

我也有同样的问题。搜索栏仍然存在并且可以接收触摸事件。但是它没有被渲染。我相信问题出在 UISearchDisplaycontroller 中,因为如果我不使用 UISearchDisplayController,它会呈现得很好。我最终编写了一个自定义 SearchDisplaycontroller 来替换它。这是非常基本的,只做我需要的。

使用它的方式与普通 UISearchDisplayController 相同,但 self.searchDisplayController 不会返回任何内容。您将不得不使用另一个指针来引用自定义搜索显示控制器。

看起来像一个大而丑陋的工作,但唯一一个对我有用。渴望听到替代方案。

@protocol SearchDisplayDelegate;

@interface SearchDisplayController : NSObject<UISearchBarDelegate>

- (id)initWithSearchBar:(UISearchBar *)searchBar contentsController:(UIViewController *)viewController;

@property(nonatomic,assign)                           id<SearchDisplayDelegate> delegate;

@property(nonatomic,getter=isActive)  BOOL            active;  // configure the view controller for searching. default is NO. animated is NO
- (void)setActive:(BOOL)visible animated:(BOOL)animated;       // animate the view controller for searching

@property(nonatomic,readonly)                         UISearchBar                *searchBar;
@property(nonatomic,readonly)                         UIViewController           *searchContentsController; // the view we are searching (often a UITableViewController)
@property(nonatomic,readonly)                         UITableView                *searchResultsTableView;   // will return non-nil. create if requested
@property(nonatomic,assign)                           id<UITableViewDataSource>   searchResultsDataSource;  // default is nil. delegate can provide
@property(nonatomic,assign)                           id<UITableViewDelegate>     searchResultsDelegate;

@end


@protocol SearchDisplayDelegate <NSObject>
// implement the protocols you need
@optional
@end

实现

@implementation SearchDisplayController {
    UISearchBar *_searchBar;
    UIViewController *_viewController;
    UITableView *_searchResultsTableView;
    UIView *_overLay;
}

- (void)dealloc {
    [_searchBar release];
    [_searchResultsTableView release];
    [_overLay release];
    [super dealloc];
}

- (UIViewController *)searchContentsController {
    return _viewController;
}

- (UITableView *)searchResultsTableView {
    return _searchResultsTableView;
}

- (id)initWithSearchBar:(UISearchBar *)searchBar contentsController:(UIViewController *)viewController {
    self = [super init];
    if (self) {
        _searchBar = [searchBar retain];
        _searchBar.delegate = self;
        _viewController = viewController;
        _searchResultsTableView = [[UITableView alloc]initWithFrame:CGRectMake(0, CGRectGetMaxY(_searchBar.frame), _viewController.view.frame.size.width, _viewController.view.frame.size.height - CGRectGetMaxY(_searchBar.frame))];
        _overLay = [[UIView alloc]initWithFrame:_searchResultsTableView.frame];
        _overLay.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(overLayTapped)];
        [_overLay addGestureRecognizer:tap];
        [tap release];
    }
    return self;
}
- (void)setSearchResultsDataSource:(id<UITableViewDataSource>)searchResultsDataSource {
    _searchResultsTableView.dataSource = searchResultsDataSource;
}

- (void)setSearchResultsDelegate:(id<UITableViewDelegate>)searchResultsDelegate {
    _searchResultsTableView.delegate = searchResultsDelegate;
}

- (void)overLayTapped {
    [self setActive:NO animated:YES];
    [_searchBar resignFirstResponder];
    _searchBar.text = nil;
    _searchBar.showsCancelButton = NO;
}

- (void)setActive:(BOOL)visible animated:(BOOL)animated {
    UIView *viewToAdd = nil;
    if (!_searchBar.text.length) {
        viewToAdd = _overLay;
    } else {
        viewToAdd = _searchResultsTableView;
    }
    float a = 0;
    if (visible) {
        [_viewController.view addSubview:viewToAdd];
        a = 1.0;
    }
    if ([_viewController.view respondsToSelector:@selectore(scrollEnabled)]) {
        ((UIScrollView *)_viewController.view).scrollEnabled = !visible;
    }

    if (animated) {
        [UIView animateWithDuration:0.2 animations:^{
            _overLay.alpha = a;
            _searchResultsTableView.alpha = a;
        }];
    } else {
        _overLay.alpha = a;
        _searchResultsTableView.alpha = a;
    }
}

- (void)setActive:(BOOL)active {
    [self setActive:active animated:YES];
}

#pragma mark - UISearchBar delegate protocols

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
    [self setActive:YES animated:YES];
    searchBar.showsCancelButton = YES;
    [_searchResultsTableView reloadData];
}

- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {

}

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
    [_searchResultsTableView reloadData];
}

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
    [self overLayTapped];
}

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
    if (searchText.length) {
        [_overLay removeFromSuperview];
        [_viewController.view addSubview:_searchResultsTableView];
    } else {
        [_searchResultsTableView removeFromSuperview];
        [_viewController.view addSubview:_overLay];
    }
        [_searchResultsTableView reloadData];
}

@end

更新:关于如何以编程方式使用它

声明一个 ivar

SearchDisplayController *mySearchDisplayController;

以编程方式初始化它

mySearchDisplayController = [[SearchDisplayController alloc]initWithSearchBar:mySearchBar contentsController:self];

将搜索栏添加到您的表格视图

self.tableView.headerView = mySearchBar;

使用 mySearchDisplayController 作为对 custon 类的引用,而不是 self.searchDisplayController。

【讨论】:

  • 实际上我也在使用一个自定义类来实现 searchBar 和 searchDisplaycontroller 委托功能。我在上述视图控制器的xib中将searchDisplayController分配给这个类。
  • 对不起,我错过了你说你使用 xib 的部分。我以编程方式使用它。 searchBar 的自定义类应该没问题,只要它是 UISearchbar 的子类
  • 我创建了一个自定义类,它是 searchDisplayController 的子类,就像您在上面所做的一样。我将这个类分配给 xib 文件中的 searchDisplayController。如何以编程方式分配它?
  • 如果我以编程方式创建一个 searchBar 并添加它可以正常工作。但是,如果我使用 UISearchBar *searchBar = self.searchDisplayController.searchBar;并将这个放在 headerView 中,问题就来了。
  • self.searchDisplayController 是只读属性。如果以编程方式或通过 xib 未初始化,则它指向 nil。为自定义搜索显示控制器初始化一个 ivar,并将其用作代码中的引用。忽略 self.searchDisplayController。请参阅更新后的帖子。还更新了搜索显示实现。
【解决方案3】:


在我的例子中,在其标题视图中包含搜索显示控制器的搜索栏的表格视图几乎在视图出现时就被重新加载。正是在这一点上,搜索栏将停止呈现。当我滚动表格时,它会重新出现。还值得一提的是,我的表包含一个 UIRefreshControl,并且不是一个 UITableViewController 子类。

我的修复涉及在加载表格(并结束刷新控件刷新)之前将搜索显示控制器设置为活动状态,然后非常快速地变为非活动状态:

[self.tableView reloadData];    
[self.refreshControl endRefreshing];
[self.searchDisplayController setActive:YES animated:NO];
[self.searchDisplayController setActive:NO];


有点小技巧,但对我有用。

【讨论】:

    【解决方案4】:

    使用调试器,我发现 UISearchBar 最初是 tableHeaderView 的子视图 - 但当它消失时,它已成为 tableView 本身的子视图。这可能是由 UISearchDisplayController 以某种方式完成的......所以我做了以下 hack 来简单地将 UISearchBar 返回到标题视图:

    - (void)viewWillAppear:(BOOL)animated
    {
      [super viewWillAppear:animated];
      if(!self.searchDisplayController.isActive && self.searchBar.superview != self.tableView.tableHeaderView) {
        [self.tableView.tableHeaderView addSubview:self.searchBar];
      }
    }
    

    似乎在 iOS 7 和 6 上都可以正常工作 :)

    (需要检查 searchDisplayController 是否处于活动状态,否则搜索栏会在搜索过程中消失)

    【讨论】:

      【解决方案5】:

      我支持Phien Tram's answer。请点赞。我自己积分不够。

      我有一个类似的问题,当我反复点击它时,从情节提要加载的搜索栏会消失,调用和关闭搜索。他的解决方案解决了这个问题。

      似乎存在一个错误,即重复调用和解除搜索显示控制器并不总是将搜索栏返回给表格视图。

      我会说我对解决方案对现有视图层次结构的依赖感到不舒服。 Apple 似乎会在每个主要版本中重新调整它。此代码可能会在 iOS 8 中中断。

      我认为永久解决方案需要 Apple 进行修复。

      【讨论】:

      • 取消按钮不起作用似乎已在 7.1 beta 2 中得到修复,但我仍然遇到类似的问题,搜索栏消失了。
      【解决方案6】:

      我有同样的问题,我可以在创建 UISearchDisplayController 后调用下一行来修复它

      [self performSelector:@selector(setSearchDisplayController:) withObject:displayController];
      

      我的 viewDidLoad 函数如下所示:

      UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, 44)];
      searchBar.placeholder = NSLocalizedString(@"Search", @"Search");
      
      UISearchDisplayController *displayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
      displayController.delegate = self;
      displayController.searchResultsDataSource = self;
      displayController.searchResultsDelegate = self;
      
      [self performSelector:@selector(setSearchDisplayController:) withObject:displayController];
      
      self.tableView.contentOffset = CGPointMake(0, 44);
      self.tableView.tableHeaderView = searchBar;
      

      感谢这个答案:https://stackoverflow.com/a/17324921/1070393

      【讨论】:

        【解决方案7】:

        使用 UITableView 上方的 UISearchBar,然后制作 IBOutlet 并将它们与文件所有者连接到 UISearchbar

        示例-.h 文件

        #import <UIKit/UIKit.h>
        
        @interface LocationViewController : UIViewController<UISearchBarDelegate>
        {
        
           BOOL IsSearchOn;
        
        }
        
        @property (strong, nonatomic) IBOutlet UISearchBar *searchBar;
        
        @property (strong, nonatomic) IBOutlet UITableView *TBVLocation;
        

        .m 文件

        #pragma mark -
        
        
        #pragma mark UISearchBar Delegate Methods
        
        
        
        -(void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
        
        {
        
            [self.searchResult removeAllObjects];
        
             if(searchText.length == 0)
              {
                   IsSearchOn=NO;
                // [filteredTableData removeAllObjects];
                   [self.searchBar resignFirstResponder];
                // [self .tblView reloadData];
        
        
             }
           else
             {
               IsSearchOn=YES;
        
               if(searchText != nil && ![searchText isEqualToString:@""])
               {
        
                /*            NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@", searchText];
        
                self.searchResult = [NSMutableArray arrayWithArray: [searchArray filteredArrayUsingPredicate:resultPredicate]];*/
                for(int i=0;i<[[arrCountryList valueForKey:@"country_name"] count];i++)
                {
        
        
                    NSRange titleRange =    [[[[arrCountryList valueForKey:@"country_name"] objectAtIndex:i] lowercaseString] rangeOfString:[searchText lowercaseString]];
        
                    if(titleRange.location != NSNotFound)
                        [self.searchResult addObject:[arrCountryList objectAtIndex:i]];
        
                }
        
                [TBVLocation reloadData];
            }
           }
        
         }
        
        
        
        - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
        
         {
        
        
         [searchBar resignFirstResponder];
        
        
         }
        
        
        -(void)searchBarCancelButtonClicked:(UISearchBar *) searchBar
        
        
        {
        
        
          [searchBar resignFirstResponder];
        
          IsSearchOn=NO;
        
          searchBar.text = nil;
        
          [TBVLocation reloadData];
        
        
        
        }
        
        - (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
        
        {
        
          [searchBar resignFirstResponder];
          return YES;
        }
        
        - (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
        {
           searchBar.showsCancelButton = YES;
           searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
           // IsSearchOn=YES;
        }
        - (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
        
        {
            IsSearchOn=NO;
            searchBar.showsCancelButton = NO;
           [TBVLocation reloadData];
           [searchBar resignFirstResponder];
        }
        

        它会像魅力一样发挥作用。

        【讨论】:

          【解决方案8】:

          我遇到过类似的问题,经过一番挖掘,我发现这是 UISearchBar 层次结构中的一个错误。这个 hacky 解决方案在 iOS 7 中对我有用,但请注意,这可能会在未来的 iOS 版本中中断:

          - (void)viewDidAppear:(BOOL)animated {
              [super viewDidAppear:animated];
          
              UIView *buggyView = [self.searchDisplayController.searchBar.subviews firstObject];
              // buggyView bounds and center are incorrect after returning from controller, so adjust them.
              buggyView.bounds = self.searchDisplayController.searchBar.bounds;
              buggyView.center = CGPointMake(CGRectGetWidth(buggyView.bounds)/2, CGRectGetHeight(buggyView.bounds)/2);
          }
          

          【讨论】:

            【解决方案9】:

            我遇到了同样的问题,并测试了此线程中提出的一些解决方案,但它们并没有为我解决问题。 之前我在

            中添加并配置了UISearchBar
             - (void)viewDidLoad
            

            代码中我的 ViewController 的方法。

            UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:searchBarView.frame];
            searchBar.delegate = self;
            searchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;
            ect...
            

            为我解决了这个问题的是,我在 InterfaceBuilder 中添加了一个 UISearchbar,在我的 ViewController 中创建了一个插座,并将这个 UISearchBar 添加到我的 UISearchDisplayController。

            self.searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar(<--outlet) contentsController:self];
            

            希望这也能帮助一些人

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-04-20
              • 1970-01-01
              • 2015-12-17
              • 2013-09-30
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-09-26
              相关资源
              最近更新 更多