2014-02-05 91 views
1

我有一個根視圖控制器,它組成了頂部的搜索欄和底部的子表視圖控制器。我使用的成分,而不是因爲這些原因指定的搜索欄,以表視圖的標題:UISearchDisplayController不完全覆蓋子視圖控制器

  1. 我不想索引與搜索欄(如聯繫人應用程序)重疊。
  2. 我希望搜索欄變得粘滯。也就是說,當我滾動表格視圖時它不會移動(再次像聯繫人應用程序)。
  3. 我的表格視圖已經有一個標題。

由於搜索欄位於根視圖控制器中,我還在根視圖控制器中實例化了我的搜索顯示控制器。我尋求建議的搜索UI有兩個問題:

  1. 半透明灰色疊加層不覆蓋整個子表視圖。它留下標題的頂部和索引可見。
  2. 同樣,搜索結果表不包括整個子表視圖。我知道如何手動更改此結果表格視圖的框架,但這樣做只能解決此問題......灰色半透明覆蓋圖的框架未鏈接到結果表視圖框架。他們沒有財產訪問覆蓋。

1)閒置

enter image description here

2)輸入搜索欄

enter image description here

3)開始輸入

enter image description here

#import "ContactsRootViewController.h" 
#import "ContactsViewController.h" 
#import "UIView+position.h" 
#import "User.h" 
#import "UserCellView.h" 
#import "UserViewController.h" 

@interface ContactsRootViewController() 

@property(nonatomic, strong) UISearchBar* searchBar; 
@property(nonatomic, strong) ContactsViewController* contactsViewController; 
@property(nonatomic, strong) UISearchDisplayController* searchController; 
@property(nonatomic, strong) NSMutableArray* matchedUsers; 

@end 

@implementation ContactsRootViewController 

#pragma mark UIViewController 

- (NSString*)title 
{ 
    return @"Contacts"; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    self.matchedUsers = [NSMutableArray array]; 

    self.searchBar = [[UISearchBar alloc] init]; 
    self.searchBar.placeholder = @"Search"; 
    [self.searchBar sizeToFit]; 
    [self.view addSubview:self.searchBar]; 
} 

- (void)viewDidAppear:(BOOL)animated 
{ 
    [super viewDidAppear:animated]; 

    if (self.contactsViewController == nil) { 
     self.contactsViewController = [[ContactsViewController alloc] init]; 
     [self addChildViewController:self.contactsViewController]; 
     self.contactsViewController.view.frame = CGRectMake(
      0.0, 
      self.searchBar.bottomY, 
      self.view.frame.size.width, 
      self.view.frame.size.height - self.searchBar.bottomY 
     ); 
     self.contactsViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; 
     [self.view addSubview:self.contactsViewController.view]; 
     [self.contactsViewController didMoveToParentViewController:self]; 

     self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self.contactsViewController]; 
     self.searchController.delegate = self; 
     self.searchController.searchResultsDataSource = self; 
     self.searchController.searchResultsDelegate = self; 
    } 
} 

#pragma mark UITableViewDataSource 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 
    return self.matchedUsers.count; 
} 

- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString* identifier = @"contactsRootViewUserCell"; 
    UserCellView* cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 
    if (cell == nil) { 
     cell = [[UserCellView alloc] initWithIdentifier:identifier]; 
    } 
    cell.user = [self.matchedUsers objectAtIndex:indexPath.row]; 
    return cell; 
} 

#pragma mark UITableViewDelegate 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    [self.navigationController pushViewController:[[UserViewController alloc] initWithUser:[self.matchedUsers objectAtIndex:indexPath.row]] animated:YES]; 
} 

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    return [UserCellView height]; 
} 

#pragma mark UISearchDisplayControllerDelegate 

- (BOOL)searchDisplayController:(UISearchDisplayController*)controller shouldReloadTableForSearchString:(NSString *)searchString 
{ 
    [self.matchedUsers removeAllObjects]; 

    searchString = [searchString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 

    if (searchString.length > 0) { 
     for (User* user in self.contactsViewController.allUsers) { 
      NSRange match = [user.userDisplayName rangeOfString:searchString options:NSCaseInsensitiveSearch]; 
      if (match.location != NSNotFound) { 
       [self.matchedUsers addObject:user]; 
      } 
     } 
    } 

    return YES; 
} 

- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller 
{ 
    [self.searchBar resignFirstResponder]; 
} 

@end 

回答

1

我重新實現UISearchDisplayController,叫我實現SearchController。它執行相同的操作並具有類似的代理回調,但搜索結果的框架可以由程序員控制。

#import <Foundation/Foundation.h> 

@class SearchController; 

@protocol SearchControllerDelegate <NSObject> 

@required 
- (BOOL)searchController:(SearchController*)controller shouldReloadTableForSearchString:(NSString*)searchText; 

@optional 
- (void)searchController:(SearchController*)controller didShowSearchResultsTableView:(UITableView*)tableView; 
- (void)searchController:(SearchController *)controller didHideSearchResultsTableView:(UITableView *)tableView; 
- (void)searchControllerDidBeginSearch:(SearchController*)controller; 
- (void)searchControllerDidEndSearch:(SearchController*)controller; 

@end 

@interface SearchController : UIViewController <UISearchBarDelegate> 

@property(nonatomic, weak) NSObject<SearchControllerDelegate>* delegate; 
@property(nonatomic, weak) NSObject<UITableViewDataSource>* searchResultsDataSource; 
@property(nonatomic, weak) NSObject<UITableViewDelegate>* searchResultsDelegate; 
@property(nonatomic, strong, readonly) UITableView* searchResultsTableView; 

- (id)initWithSearchBar:(UISearchBar*)searchBar; 

@end 

實施

#import "SearchController.h" 
#import "UIView+position.h" 

@interface SearchController() 

@property(nonatomic, strong) UISearchBar* searchBar; 
@property(nonatomic, strong) UIButton* searchResultsVeil; 
@property(nonatomic, strong, readwrite) UITableView* searchResultsTableView; 
@property(nonatomic, assign) BOOL searchResultsTableViewHidden; 

- (void)didTapSearchResultsVeil; 
- (void)hideSearchResults; 

@end 

@implementation SearchController 

#pragma mark UIViewController 

- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:animated]; 

    [self.searchResultsTableView deselectRowAtIndexPath:[self.searchResultsTableView indexPathForSelectedRow] animated:YES]; 
} 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    self.view.userInteractionEnabled = NO; 
} 

#pragma mark SearchController() 

- (void)hideSearchResults 
{ 
    self.searchBar.text = nil; 
    [self.searchResultsTableView reloadData]; 
    self.searchResultsTableViewHidden = YES; 
    [self.searchBar resignFirstResponder]; 
} 

- (void)didTapSearchResultsVeil 
{ 
    [self hideSearchResults]; 
} 

- (void)setSearchResultsTableViewHidden:(BOOL)searchResultsTableViewHidden 
{ 
    if (self.searchResultsTableView != nil) { 
     if (self.searchResultsTableView.hidden && !searchResultsTableViewHidden) { 
      self.searchResultsTableView.hidden = searchResultsTableViewHidden; 
      if ([self.delegate respondsToSelector:@selector(searchController:didShowSearchResultsTableView:)]) { 
       [self.delegate searchController:self didShowSearchResultsTableView:self.searchResultsTableView]; 
      } 
     } else if (!self.searchResultsTableView.hidden && searchResultsTableViewHidden) { 
      self.searchResultsTableView.hidden = searchResultsTableViewHidden; 
      if ([self.delegate respondsToSelector:@selector(searchController:didHideSearchResultsTableView:)]) { 
       [self.delegate searchController:self didHideSearchResultsTableView:self.searchResultsTableView]; 
      } 
     } 
    } 
} 

- (BOOL)searchResultsTableViewHidden 
{ 
    return self.searchResultsTableView == nil || self.searchResultsTableView.hidden; 
} 

#pragma mark SearchController 

- (id)initWithSearchBar:(UISearchBar *)searchBar 
{ 
    if (self = [super init]) { 
     self.searchBar = searchBar; 
     self.searchBar.delegate = self; 
    } 
    return self; 
} 

- (void)setSearchResultsDataSource:(NSObject<UITableViewDataSource> *)searchResultsDataSource 
{ 
    _searchResultsDataSource = searchResultsDataSource; 
    if (self.searchResultsTableView != nil) { 
     self.searchResultsTableView.dataSource = searchResultsDataSource; 
    } 
} 

- (void)setSearchResultsDelegate:(NSObject<UITableViewDelegate> *)searchResultsDelegate 
{ 
    _searchResultsDelegate = searchResultsDelegate; 
    if (self.searchResultsTableView != nil) { 
     self.searchResultsTableView.delegate = searchResultsDelegate; 
    } 
} 

#pragma mark UISearchBarDelegate 

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText 
{ 
    if ([self.delegate searchController:self shouldReloadTableForSearchString:searchText]) { 
     [self.searchResultsTableView reloadData]; 
     self.searchResultsTableViewHidden = [self.searchResultsTableView.dataSource tableView:self.searchResultsTableView numberOfRowsInSection:0] == 0; 
    } 
} 

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar 
{ 
    [searchBar setShowsCancelButton:YES animated:YES]; 
    if (self.searchResultsVeil == nil) { 
     self.searchResultsVeil = [[UIButton alloc] initWithFrame:self.view.bounds]; 
     self.searchResultsVeil.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.6]; 
     self.searchResultsVeil.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 
     [self.searchResultsVeil addTarget:self action:@selector(didTapSearchResultsVeil) forControlEvents:UIControlEventTouchUpInside]; 

     self.searchResultsTableView = [[UITableView alloc] initWithFrame:self.searchResultsVeil.bounds style:UITableViewStylePlain]; 
     self.searchResultsTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 
     if ([self.searchResultsTableView respondsToSelector:@selector(setSeparatorInset:)]) { 
      self.searchResultsTableView.separatorInset = UIEdgeInsetsMake(
       0.0, 
       self.searchResultsTableView.width, 
       0.0, 
       0.0 
      ); 
     } 
     self.searchResultsTableViewHidden = YES; 
     if (self.searchResultsDataSource != nil) { 
      self.searchResultsTableView.dataSource = self.searchResultsDataSource; 
     } 
     if (self.searchResultsDelegate != nil) { 
      self.searchResultsTableView.delegate = self.searchResultsDelegate; 
     } 

     [self.view addSubview:self.searchResultsVeil]; 
     [self.searchResultsVeil addSubview:self.searchResultsTableView]; 
    } 
    self.view.userInteractionEnabled = YES; 
    self.searchResultsVeil.hidden = NO; 

    if ([self.delegate respondsToSelector:@selector(searchControllerDidBeginSearch:)]) { 
     [self.delegate searchControllerDidBeginSearch:self]; 
    } 
} 

- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar 
{ 
    [searchBar setShowsCancelButton:NO animated:YES]; 
    self.view.userInteractionEnabled = NO; 
    self.searchResultsVeil.hidden = YES; 

    if ([self.delegate respondsToSelector:@selector(searchControllerDidEndSearch:)]) { 
     [self.delegate searchControllerDidEndSearch:self]; 
    } 
} 

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

@end 

使用

self.searchController = [[SearchController alloc] initWithSearchBar:self.searchBar]; 
self.searchController.delegate = self; 
self.searchController.searchResultsDataSource = self; 
self.searchController.searchResultsDelegate = self; 
[self addChildViewController:self.searchController]; 
self.searchController.view.frame = CGRectMake(
    self.searchBar.x, 
    self.searchBar.bottomY, 
    self.searchBar.width, 
    self.view.height - self.searchBar.bottomY 
); 
[self.view addSubview:self.searchController.view]; 
[self.searchController didMoveToParentViewController:self]; 
0

它看起來像您的視圖控制器不界定呈現上下文。我有類似的問題,並能夠通過設置來解決它

self.definesPresentationContext = YES; 

in viewDidLoad。根據文檔,此屬性爲

一個布爾值,指示當視圖控制器或其某個後代呈現視圖控制器時是否覆蓋此視圖控制器的視圖。