在分组的 UITableView 中搜索

Posted

技术标签:

【中文标题】在分组的 UITableView 中搜索【英文标题】:Search in Grouped UITableView 【发布时间】:2013-05-10 12:42:36 【问题描述】:

我是 Objective-C 开发的新手,我正在尝试过滤分组 UITableView 的内容。

这是我做的,但仍然没有工作:

- (void)filterContentForSearchText:(NSString *)searchText scope:(NSString *)scope

     NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] %@", searchText];;


    //activities is table that contains my objects that I display their contents in the table
    self.filteredData = [activities filteredArrayUsingPredicate:resultPredicate];


- (BOOL)searchDisplayController:(UISearchDisplayController *)controller
shouldReloadTableForSearchScope:(NSInteger)searchOption

    [self filterContentForSearchText:[self.searchDisplayController.searchBar text] scope:
     [[self.searchDisplayController.searchBar scopeButtonTitles]
      objectAtIndex:searchOption]];

    // Return YES to cause the search result table view to be reloaded.
    return YES;

//activite is my object that I use to desplay its attribut in table
IPADActivity *activite ;
    if (ThetableView == self.searchDisplayController.searchResultsTableView) 
        activite = [self.filteredData objectAtIndex:indexPath.row];


     
    else
        activite = [[objects
                      objectForKey:[objectsIndex objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
    

有什么建议

【问题讨论】:

您要在表中匹配的属性是什么? 感谢回复,我的对象activite包含一个名为“DESCRIPTIOIN”的属性,taht显示在桌子上。 尝试 DESCRIPTION CONTAINS[cd] %@", searchText 为你的谓词 【参考方案1】:
//
//  ViewController.m
//  SearchTut
//


#import "ViewController.h"
#import "SearchTableCell.h"
#import "XMLReader.h"

@interface ViewController ()<UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate>

@property (weak, nonatomic) IBOutlet UITableView *tablView;
@property (weak, nonatomic) IBOutlet UISearchBar *searchBr;

@property (nonatomic, strong) NSMutableArray *arrayList; //main table array
@property (nonatomic, strong) NSMutableArray *arrayFilteredList; //array with search results while user types in search bar
@property (nonatomic, strong) NSMutableDictionary *dictList; //need to manufacture an equivalent dictionary like below from the json array
/*
 @
     @"B" : @[@"Bear", @"Black Swan", @"Buffalo"],
     @"C" : @[@"Camel", @"Cockatoo"],
     @"D" : @[@"Dog", @"Donkey"],
     @"E" : @[@"Emu"],
     @"G" : @[@"Giraffe", @"Greater Rhea"],
     @"H" : @[@"Hippopotamus", @"Horse"],
     @"K" : @[@"Koala"],
     @"L" : @[@"Lion", @"Llama"],
     @"M" : @[@"Manatus", @"Meerkat"],
     @"P" : @[@"Panda", @"Peacock", @"Pig", @"Platypus", @"Polar Bear"],
     @"R" : @[@"Rhinoceros"],
     @"S" : @[@"Seagull"],
     @"T" : @[@"Tasmania Devil"],
     @"W" : @[@"Whale", @"Whale Shark", @"Wombat"]
 ;
 Refer: https://www.appcoda.com/ios-programming-index-list-uitableview/
*/

@property (nonatomic, strong) NSMutableDictionary *dictListFiltered; //dictionary when searched
@property (nonatomic, assign) BOOL isFiltered; //If user starts entering text in search bar, this flag is YES. If there is no text in search bar, this flag is NO.

@end

@implementation ViewController

- (void)viewDidLoad 
    [super viewDidLoad];
    // Initialisers
    self.tablView.dataSource = self;
    self.tablView.delegate = self;
    self.searchBr.delegate = self;
    self.arrayList = [NSMutableArray array];
    self.dictList = [NSMutableDictionary dictionary];
    self.dictListFiltered = [NSMutableDictionary dictionary];
    self.isFiltered = NO;

    //Get and parse XML from file and load the result in array
    NSString *strXMLPath = [[NSBundle mainBundle] pathForResource:@"List" ofType:@"xml"];
    NSError *error;
    NSString *strXML = [NSString stringWithContentsOfFile:strXMLPath encoding:NSUTF8StringEncoding error:&error];
    NSDictionary *dict = [XMLReader dictionaryForXMLString:strXML error:&error];
    NSDictionary *dictPriceList = [dict objectForKey:@"PRICELIST"];
    NSArray *arrayLine = [dictPriceList objectForKey:@"LINE"];
    NSMutableArray *arrayTempPriceList = [NSMutableArray array];
    for (NSDictionary *dict in arrayLine) 
        [arrayTempPriceList addObject:dict];
    
    self.arrayList = arrayTempPriceList;
    NSLog(@"%@", self.arrayList);

    //Create dictionary for sectioned table grouped with respect to PRICELISTCATEGORY value. PRICELISTCATEGORY value will be set in the section title. Logic to group table in sections is below
    [self groupXMLinSectionsWithArray:arrayTempPriceList];


- (void)groupXMLinSectionsWithArray:(NSMutableArray *)arrayJson 
    if (arrayJson.count > 0)  //added this condition to reset json during search.
        for (NSDictionary *dict in arrayJson ) 
            NSString *strPriceListCategory = [[dict objectForKey:@"PRICELISTCATEGORY"] objectForKey:@"text"];
            if (self.isFiltered) 
                if ([[self.dictListFiltered allKeys] containsObject:strPriceListCategory]) 
                    NSMutableArray *arrayTemp = [self.dictListFiltered objectForKey:strPriceListCategory];
                    [arrayTemp addObject:dict];
                    [self.dictListFiltered setObject:arrayTemp forKey:strPriceListCategory];
                 else 
                    NSMutableArray *arrayTemp = [[NSMutableArray alloc] initWithObjects:dict, nil];
                    [self.dictListFiltered setObject:arrayTemp forKey:strPriceListCategory];
                
             else 
                if ([[self.dictList allKeys] containsObject:strPriceListCategory]) 
                    NSMutableArray *arrayTemp = [self.dictList objectForKey:strPriceListCategory];
                    [arrayTemp addObject:dict];
                    [self.dictList setObject:arrayTemp forKey:strPriceListCategory];
                 else 
                    NSMutableArray *arrayTemp = [[NSMutableArray alloc] initWithObjects:dict, nil];
                    [self.dictList setObject:arrayTemp forKey:strPriceListCategory];
                
            

        
     else  //if search results yield no json array, then remove all objects from dictionary
        [self.dictList removeAllObjects];
        [self.dictListFiltered removeAllObjects];
    
    [self.tablView reloadData];


- (void)didReceiveMemoryWarning 
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.


#pragma mark - TableView Datasource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
    NSArray *arrayTemp = [NSArray array];
    if (self.isFiltered) 
        NSArray *arrayListAllKeys = [self.dictListFiltered allKeys];
        arrayTemp = [self.dictListFiltered objectForKey:[arrayListAllKeys objectAtIndex:section]];
     else 
        NSArray *arrayListAllKeys = [self.dictList allKeys];
        arrayTemp = [self.dictList objectForKey:[arrayListAllKeys objectAtIndex:section]];
    
    return [arrayTemp count];


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    SearchTableCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SearchTableCellId" forIndexPath:indexPath];
    NSDictionary *dict;
    if (self.isFiltered) 
        NSArray *arrayPriceListAllKeys = [self.dictListFiltered allKeys];
        NSArray *arrayPrice = [self.dictListFiltered objectForKey:[arrayPriceListAllKeys objectAtIndex:indexPath.section]];
        dict = [arrayPrice objectAtIndex:indexPath.row];
     else 
        NSArray *arrayPriceListAllKeys = [self.dictList allKeys];
        NSArray *arrayPrice = [self.dictList objectForKey:[arrayPriceListAllKeys objectAtIndex:indexPath.section]];
        dict = [arrayPrice objectAtIndex:indexPath.row];
    
    cell.lblBarCode.text = [[dict objectForKey:@"APNBARCODE"] objectForKey:@"text"];
    cell.lblPackDescription.text = [[dict objectForKey:@"PACKDESCRIPTION"] objectForKey:@"text"];
    cell.lblProduct.text = [[dict objectForKey:@"PRODUCT"] objectForKey:@"text"];
    cell.lblProductName.text = [[dict objectForKey:@"PRODUCTNAME"] objectForKey:@"text"];

    return cell;


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
    if (self.isFiltered) 
        return [[self.dictListFiltered allKeys] count];
     else 
        return [[self.dictList allKeys] count];
    


- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section 
    NSString *price = @"";
    if (self.isFiltered) 
        price = [[self.dictListFiltered allKeys] objectAtIndex:section];
     else 
        price = [[self.dictList allKeys] objectAtIndex:section];
    
    return price;


- (CGFloat) tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section 
    return 50.0;


- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section 
    NSString *sectionTitle = [self tableView:tableView titleForHeaderInSection:section];
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(8, 8, self.tablView.frame.size.width - 16, 30)];
    //If you add a bit to x and decrease y, it will be more in line with the tableView cell (that is in iPad and landscape)
    label.backgroundColor = [UIColor clearColor];
    label.textColor = [UIColor whiteColor];
    label.shadowColor = [UIColor whiteColor];
    label.shadowOffset = CGSizeMake(0.5, 0.5);
    label.font = [UIFont boldSystemFontOfSize:18];
    label.text = sectionTitle;

    // Create header view and add label as a subview
    UIView *viewHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tablView.frame.size.width, 50)];
    viewHeader.backgroundColor = [UIColor colorWithRed:0.4 green:0.4 blue:0.4 alpha:1];
    [viewHeader addSubview:label];
    return viewHeader;


#pragma mark - SearchBar Delegates

- (void)updateSearchResults

    //You can use the below commented code in case you need an exact match of the PRODUCT value text you entered in search bar
    /*
     NSMutableArray *searchResults = [self.arrayList mutableCopy];
     NSString *strippedString = [searchText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
     NSPredicate *predicate = [NSPredicate predicateWithFormat:@"PRODUCT.text==[c] %@", strippedString];
     searchResults = [[searchResults filteredArrayUsingPredicate:predicate] mutableCopy];
     // hand over the filtered results to our search results table
     self.arrayFilteredList = searchResults;
     //NSLog(@"%@", self.arrayFilteredPriceList);
     [self groupXMLinSectionsWithArray:self.arrayFilteredList];
     */


    //Below code searches depending on Product / Product Name / APNBarCode values
    NSString *searchText = self.searchBr.text;
    NSMutableArray *searchResults = [self.arrayList mutableCopy];
    NSString *strippedString = [searchText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
    NSArray *searchItems = nil;
    if (strippedString.length > 0) 
        searchItems = [strippedString componentsSeparatedByString:@" "];
    

    NSMutableArray *andMatchPredicates = [NSMutableArray array];

    for (NSString *searchString in searchItems) 
        NSMutableArray *searchItemsPredicate = [NSMutableArray array];

        // Below we use NSExpression represent expressions in our predicates.
        // NSPredicate is made up of smaller, atomic parts: two NSExpressions (a left-hand value and a right-hand value)

        // Product
        NSExpression *lhsProduct = [NSExpression expressionForKeyPath:@"PRODUCT.text"];
        NSExpression *rhsProduct = [NSExpression expressionForConstantValue:searchString];
        NSPredicate *finalPredicateProduct = [NSComparisonPredicate
                                              predicateWithLeftExpression:lhsProduct
                                              rightExpression:rhsProduct
                                              modifier:NSDirectPredicateModifier
                                              type:NSContainsPredicateOperatorType
                                              options:NSCaseInsensitivePredicateOption];
        [searchItemsPredicate addObject:finalPredicateProduct];

        // Product Name
        NSExpression *lhsProductName = [NSExpression expressionForKeyPath:@"PRODUCTNAME.text"];
        NSExpression *rhsProductName = [NSExpression expressionForConstantValue:searchString];
        NSPredicate *finalPredicateProductName = [NSComparisonPredicate
                                                  predicateWithLeftExpression:lhsProductName
                                                  rightExpression:rhsProductName
                                                  modifier:NSDirectPredicateModifier
                                                  type:NSContainsPredicateOperatorType
                                                  options:NSCaseInsensitivePredicateOption];
        [searchItemsPredicate addObject:finalPredicateProductName];


        // APN Bar Code
        NSExpression *lhsAPNBarCode = [NSExpression expressionForKeyPath:@"APNBARCODE.text"];
        NSExpression *rhsAPNBarCode = [NSExpression expressionForConstantValue:searchString];
        NSPredicate *finalPredicateAPNBarCode= [NSComparisonPredicate
                                                predicateWithLeftExpression:lhsAPNBarCode
                                                rightExpression:rhsAPNBarCode
                                                modifier:NSDirectPredicateModifier
                                                type:NSContainsPredicateOperatorType
                                                options:NSCaseInsensitivePredicateOption];
        [searchItemsPredicate addObject:finalPredicateAPNBarCode];

        // AVERAGECOST
        NSExpression *lhsPACKDESCRIPTION = [NSExpression expressionForKeyPath:@"PACKDESCRIPTION.text"];
        NSExpression *rhsPACKDESCRIPTION = [NSExpression expressionForConstantValue:searchString];
        NSPredicate *finalPredicatePACKDESCRIPTIONt = [NSComparisonPredicate
                                                predicateWithLeftExpression:lhsPACKDESCRIPTION
                                                rightExpression:rhsPACKDESCRIPTION
                                                modifier:NSDirectPredicateModifier
                                                type:NSContainsPredicateOperatorType
                                                options:NSCaseInsensitivePredicateOption];
        [searchItemsPredicate addObject:finalPredicatePACKDESCRIPTIONt];

        // at this OR predicate to our master AND predicate
        NSCompoundPredicate *orMatchPredicates = [NSCompoundPredicate orPredicateWithSubpredicates:searchItemsPredicate];
        [andMatchPredicates addObject:orMatchPredicates];

    

    // match up the fields of the Product object
    NSCompoundPredicate *finalCompoundPredicate =
    [NSCompoundPredicate andPredicateWithSubpredicates:andMatchPredicates];
    searchResults = [[searchResults filteredArrayUsingPredicate:finalCompoundPredicate] mutableCopy];
    // hand over the filtered results to our search results table
    self.arrayFilteredList = searchResults;
    //NSLog(@"%@", self.arrayFilteredPriceList);

    [self groupXMLinSectionsWithArray:self.arrayFilteredList];


//This method gets called when user starts entering text in search bar
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText 
    if (searchText.length == 0) 
        self.isFiltered = NO;
        [self.dictList removeAllObjects];
        [self groupXMLinSectionsWithArray:self.arrayList];
        [self.tablView reloadData];
     else 
        self.isFiltered = YES;
        self.arrayFilteredList = [NSMutableArray new];
        [self.dictListFiltered removeAllObjects];
        [self updateSearchResults];
    


- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar 
    [searchBar resignFirstResponder];
    [self.dictList removeAllObjects];
    [self groupXMLinSectionsWithArray:self.arrayList];
    [self.tablView reloadData];


- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar 
    [searchBar resignFirstResponder];
    [self.tablView reloadData];



@end

以上代码逻辑基于 json 数组,字典包含在数组中,我们根据 PRICELISTCATEGORY 值创建部分

 [
     
       "PRODUCT": 
          "text": "GELDCMFRAME"
       ,
       "PRODUCTMAJORGROUP": 
          "text": "IC"
       ,
       "PRICELISTCATEGORY": 
          "text": "GELDISP"
       ,
       "APNBARCODE": 
          "text": "931000"
       ,
       "PACKDESCRIPTION": 
          "text": "Some Description"
       ,
       "PRODUCTNAME": 
          "text": "Description"
       
       and so on
    , and so on
 ]

请参阅下面的屏幕截图以获取搜索结果

【讨论】:

以上是关于在分组的 UITableView 中搜索的主要内容,如果未能解决你的问题,请参考以下文章

UITableView的contentSize

在 UITableView 单元格中定位 UIImageViews

iOS UITableView在过滤时滚动插入

如何在同一个视图中呈现 UITableView 及其详细视图

在 Swift 中删除分组 UITableView 上方的空间

数据未显示在 UITableView 的自定义单元格中