web-dev-qa-db-ja.com

iOS7のヘッダービューに検索バーが表示されなくなります

アプリケーション内のデバイスのリストを表示するためのtableviewがあります。 viewWillAppearが呼び出されたら、self.searchDisplayController.searchBar as a subview to a headerViewを追加します。次に、self.tableView.tableHeaderView = headerViewを割り当てます。次のようになります。 enter image description here

テーブルビューを下にスクロールしてヘッダービューが表示されないようにしてから、セルをタップして他のビューコントローラーに移動します。このtableViewに戻って、headerViewまでスクロールすると、searchBarが非表示になりますが、非表示領域をタップすると、searchDisplayControllerがアクティブになり、キャンセルボタンが機能しません。これはiOS7でのみ発生します。なんでこんなことが起こっているの? enter image description here
注:tableViewControllerに戻ったときにheaderViewがビューの外にある場合にのみ発生します。

25
tech savvy

私はちょうど同じ問題を抱えていました。検索の終了状態でUISearchDisplayControllerのデリゲートメソッドにデバッグする場合、searchBarはUITableViewではなくUIViewのサブビューになります。以下のコードを参照してください。

- (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に再度追加することです。私はすでに正常にテストしました。お役に立てば幸いです。

よろしく

18
Phien Tram

私はまったく同じ問題を抱えています。検索バーはまだそこにあり、タッチイベントを受け取ることができます。ただし、レンダリングされません。 UISearchDisplayControllerを使用しないと正常にレンダリングされるため、問題はUISearchDisplaycontrollerにあると思います。私はそれを置き換えるためにカスタムSearchDisplaycontrollerを書くことになりました。それは非常に基本的で、私が必要なことだけをします。

通常のUISearchDisplayControllerと同じように使用しますが、self.searchDisplayControllerは何も返しません。カスタム検索ディスプレイコントローラーを参照するには、別のポインターを使用する必要があります。

大きな醜い回避策のように見えますが、私のために働いたのは1つだけです。代替案を聞きたがっています。

@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;

self.searchDisplayControllerではなく、custonクラスへの参照としてmySearchDisplayControllerを使用します。

5
tzl

私は支持します Phien Tramの答え 。賛成してください。私自身は十分なポイントがありません。

ストーリーボードから読み込まれた検索バーを繰り返しタップして検索を呼び出したり閉じたりすると、検索バーが消えてしまうという同様の問題がありました。彼の解決策は問題を修復します。

検索ディスプレイコントローラーを繰り返し呼び出したり閉じたりしても、検索バーが常にテーブルビューに戻るとは限らないというバグがあるようです。

ソリューションが既存のビュー階層に依存していることに不快感を覚えます。 Appleはメジャーリリースごとに再シャッフルしているようです。このコードはiOS8で壊れることがあります。

恒久的な解決策にはAppleによる修正が必要だと思います。

2
Bob Wakefield

デバッガーを使用すると、UISearchBarは最初はtableHeaderViewの子ビューであることがわかりましたが、表示されなくなると、tableView自体の子になります。これはおそらくUISearchDisplayControllerによって行われた可能性があります...そこで、UISearchBarをヘッダービューに戻すために次のハックを行いました。

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

IOS7と6で正常に動作するようです:)

(searchDisplayControllerがアクティブでないことを確認する必要があります。アクティブでない場合、検索中にアーチバーが消えます)

2
user2992990


私の場合、検索ディスプレイコントローラーの検索バーをヘッダービューに保持していたテーブルビューは、ビューが表示されるとすぐに再読み込みされていました。検索バーのレンダリングが停止するのはこの時点でした。テーブルをスクロールすると、再び表示されます。私のテーブルにはUIRefreshControlが含まれていて、not UITableViewControllerサブクラスであったことにも言及する価値があります。

私の修正には、テーブルをロードする直前(およびリフレッシュコントロールのリフレッシュを終了する直前)に、検索ディスプレイコントローラーをアクティブにしてからすぐに非アクティブに設定することが含まれていました。

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


ちょっとしたハックですが、私にとってはうまくいきます。

2
imnk

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];
}

それは魅力のように機能します。

1
Anuj Kumar Rai

同様の問題に直面しましたが、少し掘り下げてみると、これはUISearchBar階層のバグであることがわかりました。このハッキーなソリューションはiOS7で機能しましたが、将来の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);
}
1
Maxim Pavlov

同じ問題が発生し、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/107039

1
RemeR

私は同じ問題を抱えていて、このスレッドでここで提案された解決策のいくつかをテストしましたが、それらは私にとって問題を解決しませんでした。以前、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];

これが一部の人々にも役立つことを願っています

0
Heckscheibe