将搜索添加到 tvOS UITableView

Add Search to tvOS UITableView

我的 tvOS 应用程序上有一个包含 400 多个对象的 TableView,它确实需要具有搜索功能。

在阅读了 Apple 的一些示例代码后,这就是我所拥有的。 SecondViewController 是主要 TableView 所在的位置,而我只是将 resultsViewController 的名称保留为与 Apple 相同的名称。在主要的我有:

-(void)viewDidLoad {
    [super viewDidLoad];
    _resultsTableController = [[APLResultsTableController alloc] init];
    _searchController = [[UISearchController alloc] initWithSearchResultsController:self.resultsTableController];
    self.searchController.searchResultsUpdater = self;
    [self.searchController.searchBar sizeToFit];
    self.tableView.tableHeaderView = self.searchController.searchBar;

    // we want to be the delegate for our filtered table so didSelectRowAtIndexPath is called for both tables
    self.resultsTableController.tableView.delegate = self;
    self.searchController.delegate = self;
    self.searchController.searchBar.delegate = self; // so we can monitor text changes + others

    // Search is now just presenting a view controller. As such, normal view controller
    // presentation semantics apply. Namely that presentation will walk up the view controller
    // hierarchy until it finds the root view controller or one that defines a presentation context.
    //
    self.definesPresentationContext = YES;  // know where you want UISearchController to be displayed

}
- (void)viewWillAppear:(BOOL)animated {
    if (self.searchControllerWasActive) {
        self.searchController.active = self.searchControllerWasActive;
        _searchControllerWasActive = NO;

        if (self.searchControllerSearchFieldWasFirstResponder) {
            [self.searchController.searchBar becomeFirstResponder];
            _searchControllerSearchFieldWasFirstResponder = NO;
        }
    }
    NSBundle *bundle = [NSBundle mainBundle];

    self.files  = [bundle pathsForResourcesOfType:@"pdf" inDirectory:@"AIMPDF"];
    NSString *documentsDirectoryPath = [self.files objectAtIndex:thepath.row];

    self.title = @"Devo Songs";
    self.filenames = [[documentsDirectoryPath lastPathComponent] stringByDeletingPathExtension];
    NSLog(@"%@", filenames);

    if ([self savedSearchTerm])
    {
        //[[[self searchDisplayController] searchBar] setText:[self savedSearchTerm]];
    }
    NSMutableArray *names = [NSMutableArray arrayWithCapacity:[self.files count]];
    for (NSString *path in self.files) {
        [names addObject:[[path lastPathComponent] stringByDeletingPathExtension]];
    }
    self.files = names;


    self.tableView.backgroundColor = [UIColor whiteColor];
    self.parentViewController.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"iphonebackground.png"]];
    [super viewDidLoad];

    UIBarButtonItem *plan = [[UIBarButtonItem alloc] initWithTitle:@"Plan Devo" style:UIBarButtonItemStylePlain target:self action:@selector(picking)];
    self.navigationItem.rightBarButtonItem = plan;


    [super viewWillAppear:animated];

}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
    [searchBar resignFirstResponder];
}
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
    // update the filtered array based on the search text
    NSString *searchText = searchController.searchBar.text;
    NSMutableArray *searchResults = [self.files mutableCopy];

    // strip out all the leading and trailing spaces
    NSString *strippedString = [searchText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

    // break up the search terms (separated by spaces)
    NSArray *searchItems = nil;
    if (strippedString.length > 0) {
        searchItems = [strippedString componentsSeparatedByString:@" "];
    }

    // build all the "AND" expressions for each value in the searchString
    //


    // hand over the filtered results to our search results table
    APLResultsTableController *tableController = (APLResultsTableController *)self.searchController.searchResultsController;
    tableController.filteredProducts = searchResults;
    [tableController.tableView reloadData];
}
- (void)handleSearchForTerm:(NSString *)searchTerm
{
    [self setSavedSearchTerm:searchTerm];

    if ([self searchResults] == nil)
    {
        NSMutableArray *array = [[NSMutableArray alloc] init];
        [self setSearchResults:array];
        array = nil;
    }

    [[self searchResults] removeAllObjects];

    if ([[self savedSearchTerm] length] != 0)
    {
        for (NSString *currentString in [self files])
        {
            if ([currentString rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound)
            {
                [[self searchResults] addObject:currentString];
            }
        }
    }
}

在结果视图控制器中,我有:

@implementation APLResultsTableController

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *filename = [[[self.filteredProducts objectAtIndex:indexPath.row] lastPathComponent] stringByDeletingPathExtension];
    NSInteger row = [indexPath row];
    NSString *contentForThisRow = nil;


    contentForThisRow = filename;

    static NSString *CellIdentifier = @"CellIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }


    [[cell textLabel] setText:contentForThisRow];
    cell.textLabel.font = [UIFont fontWithName:@"Helvetica Neue" size:90];
    cell.textLabel.textColor = [UIColor blackColor];
    cell.backgroundColor = [UIColor lightGrayColor];
    return cell;

}


@end

我在主 TableView 的顶部添加了搜索栏,但是当我开始输入字母时没有任何变化。

Apple 在 iOS 8 中弃用了 UISearchDisplayController,并在 iOS 9 中将其删除,这就是它在 tvOS 上不可用的原因。

您需要使用 UISearchController, which you initialize and present in code. Apple provides an example of how to do this in SearchViewController.swift, in the UIKitCatalog tvOS 示例代码。

好的,所以在我的头撞到砖墙上的 all-day 事件之后,我终于把它设置好了。请注意,我讨厌 Apple 的教程和示例代码如何让它变得过于复杂。他们添加了一个 APLProducts 的 NSObject,一个 BaseTableView,并在他们的教程中创建了几个复合的 NSPredicates,以便在 TableView 中使用搜索。本来可以简单得多。

最后只需要3个类:

原始表格视图 结果表视图 详情查看

在 OTV 中,我为 SearchController 和一个名为 searchResults 的 NSMutableArray 声明了 属性。我所有的 PDF 文件都在目录 AIMPDF 中。我根据这些文件制作数组,删除显示扩展名。正是在代码的“搜索更新”部分,Apple 对他们试图做的所有事情都失去了控制。看在上帝的份上,让教程变得简单。

-(void)viewDidLoad {
    [super viewDidLoad];
    _resultsTableController = [[APLResultsTableController alloc] init];
    _searchController = [[UISearchController alloc] initWithSearchResultsController:self.resultsTableController];
    self.searchController.searchResultsUpdater = self;
    [self.searchController.searchBar sizeToFit];
    self.tableView.tableHeaderView = self.searchController.searchBar;

    self.resultsTableController.tableView.delegate = self;
    self.searchController.delegate = self;
    self.searchController.searchBar.delegate = self; // so we can monitor text changes + others


    self.definesPresentationContext = YES;  // know where you want UISearchController to be displayed

}
- (void)viewWillAppear:(BOOL)animated {
    if (self.searchControllerWasActive) {
        self.searchController.active = self.searchControllerWasActive;
        _searchControllerWasActive = NO;

        if (self.searchControllerSearchFieldWasFirstResponder) {
            [self.searchController.searchBar becomeFirstResponder];
            _searchControllerSearchFieldWasFirstResponder = NO;
        }
    }
    NSBundle *bundle = [NSBundle mainBundle];

    self.files  = [bundle pathsForResourcesOfType:@"pdf" inDirectory:@"AIMPDF"];
    NSString *documentsDirectoryPath = [self.files objectAtIndex:thepath.row];

    self.title = @"Devo Songs";
    self.filenames = [[documentsDirectoryPath lastPathComponent] stringByDeletingPathExtension];
    NSLog(@"%@", filenames);

    NSMutableArray *names = [NSMutableArray arrayWithCapacity:[self.files count]];
    for (NSString *path in self.files) {
        [names addObject:[[path lastPathComponent] stringByDeletingPathExtension]];
    }
    self.files = names;


    self.tableView.backgroundColor = [UIColor whiteColor];
    self.parentViewController.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"iphonebackground.png"]];
    [super viewDidLoad];


    [super viewWillAppear:animated];

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

- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
    // update the filtered array based on the search text
    NSString *searchText = searchController.searchBar.text;
    NSMutableArray *searchResults2 = [self.files mutableCopy];

    // strip out all the leading and trailing spaces
    NSString *strippedString = [searchText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

    // break up the search terms (separated by spaces)
    NSArray *searchItems = nil;
    if (strippedString.length > 0) {
        searchItems = [strippedString componentsSeparatedByString:@" "];
    }



    for (NSString *searchString in searchItems) {

        NSPredicate *sPredicate =
        [NSPredicate predicateWithFormat:@"SELF contains[c] %@", searchString];
        [searchResults2 filterUsingPredicate:sPredicate];


    }


    // hand over the filtered results to our search results table
    APLResultsTableController *tableController = (APLResultsTableController *)self.searchController.searchResultsController;
    tableController.filteredProducts = searchResults2;
    [tableController.tableView reloadData];
}

- (void)handleSearchForTerm:(NSString *)searchTerm
{
    [self setSavedSearchTerm:searchTerm];

    if ([self searchResults] == nil)
    {
        NSMutableArray *array = [[NSMutableArray alloc] init];
        [self setSearchResults:array];
        array = nil;
    }

    [[self searchResults] removeAllObjects];

    if ([[self savedSearchTerm] length] != 0)
    {
        for (NSString *currentString in [self files])
        {
            if ([currentString rangeOfString:searchTerm options:NSCaseInsensitiveSearch].location != NSNotFound)
            {
                [[self searchResults] addObject:currentString];
            }
        }
    }
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    // Return the number of sections.
    return 1;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // Return the number of rows in the section.
    NSInteger rows;

        rows = [[self files] count];
    return rows;
}


// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *filename = [[[self.files objectAtIndex:indexPath.row] lastPathComponent] stringByDeletingPathExtension];
    NSInteger row = [indexPath row];
    NSString *contentForThisRow = nil;


        contentForThisRow = filename;

    static NSString *CellIdentifier = @"CellIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }


           [[cell textLabel] setText:contentForThisRow];
        cell.textLabel.font = [UIFont fontWithName:@"Helvetica Neue" size:90];
        cell.textLabel.textColor = [UIColor blackColor];
        cell.backgroundColor = [UIColor lightGrayColor];
        return cell;

}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    self.selectedCountry = (tableView == self.tableView) ?
    self.files[indexPath.row] : self.resultsTableController.filteredProducts[indexPath.row];

    [self performSegueWithIdentifier:@"ShowSong" sender:self];




}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Make sure your segue name in storyboard is the same as this line
    if ([[segue identifier] isEqualToString:@"ShowSong"])
    {

        NSLog(@"Selecting %@", self.selectedCountry);
        FirstViewController* userViewController = [segue destinationViewController];
        userViewController.selectedCountry = self.selectedCountry;

        //if you need to pass data to the next controller do it here
    }
}

ResultsTableView 只需要这个。我可能需要更少,但以防万一。

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.filteredProducts.count;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    self.selectedCountry = [self.filteredProducts objectAtIndex:indexPath.row];

    [self performSegueWithIdentifier:@"ShowSong" sender:self];




}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Make sure your segue name in storyboard is the same as this line
    if ([[segue identifier] isEqualToString:@"ShowSong"])
    {

        NSLog(@"SelectingSearch %@", self.selectedCountry);
        FirstViewController* userViewController = [segue destinationViewController];
        userViewController.selectedCountry = self.selectedCountry;

        //if you need to pass data to the next controller do it here
    }
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *filename = [[[self.filteredProducts objectAtIndex:indexPath.row] lastPathComponent] stringByDeletingPathExtension];
    NSInteger row = [indexPath row];
    NSString *contentForThisRow = nil;


    contentForThisRow = filename;

    static NSString *CellIdentifier = @"CellIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }


    [[cell textLabel] setText:contentForThisRow];
    cell.textLabel.font = [UIFont fontWithName:@"Helvetica Neue" size:90];
    cell.textLabel.textColor = [UIColor blackColor];
    cell.backgroundColor = [UIColor lightGrayColor];
    return cell;

}


@end