搜索栏从iOS 7中的标题视图中消失

时间:2013-09-27 06:33:44

标签: iphone objective-c uitableview ios7 uisearchbar

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

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

9 个答案:

答案 0 :(得分:18)

我刚才遇到了同样的问题。当我在最终搜索状态下调试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。我已经成功测试了。 希望有所帮助!

此致

答案 1 :(得分:5)

我有完全相同的问题。搜索栏仍然存在,可以接收触摸事件。然而,它没有呈现。我相信问题出在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];

将搜索栏添加到您的tableview

self.tableView.headerView = mySearchBar;

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

答案 2 :(得分:2)


在我的情况下,几乎在视图出现时,正在重新加载在其标题视图中保持搜索显示控制器的搜索栏的表视图。此时搜索栏将停止渲染。当我滚动表格时,它会重新出现。还值得一提的是,我的表包含一个UIRefreshControl,并且不是一个UITableViewController子类。

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

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


有点黑客但它对我有用。

答案 3 :(得分:2)

我支持Phien Tram's answer。请投票。我自己没有足够的分数。

我有一个类似的问题,当我反复点击它,调用和解雇搜索时,从故事板加载的搜索栏会消失。他的解决方案解决了这个问

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

我会说我对解决方案对现有视图层次结构的依赖感到不安。苹果公司似乎每次重大发布都要重新洗牌。此代码可能会破坏iOS 8。

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

答案 4 :(得分:1)

使用调试器,我发现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是否处于活动状态是必要的,否则搜索时sarch栏会消失)

答案 5 :(得分:1)

我有同样的问题,我可以在创建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

答案 6 :(得分:1)

我遇到过类似的问题,经过一番挖掘后,我发现这是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);
}

答案 7 :(得分:1)

在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 :(得分:0)

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

中添加并配置了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];

希望这也可以帮助一些人