我有一个根视图控制器,它在顶部组成一个搜索栏,在底部是一个子表视图控制器。由于以下原因,我使用组合而不是将搜索栏分配给表视图的标题:

  • 我不希望索引与搜索栏重叠(例如“联系人”应用程序)。
  • 我希望搜​​索栏保持粘性。也就是说,当我滚动表格视图时(同样类似于“联系人”应用程序),它不会移动。
  • 我的表格视图已经有一个标题。

  • 由于搜索栏位于根视图控制器中,因此我也要在根视图控制器中实例化搜索显示控制器。我向其寻求建议的搜索UI存在两个问题:
  • 半透明的灰色覆盖层无法覆盖整个子表视图。它使标题的顶部和索引可见。
  • 同样,搜索结果表并不涵盖整个子表视图。我知道如何手动更改此结果表视图的框架,但这样做只能解决...灰色半透明叠加层的框架未链接到结果表视图框架的情况。他们没有访问叠加层的属性。

  • 1)空闲

    2)输入搜索栏

    3)开始输入
    #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
    

    最佳答案

    我重新实现了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];
    

    10-08 12:31