【Objective-C】インクリメンタルサーチ(検索中連動検索結果表示)の実装について【Xcode10.2対応】
こういう人に向けて発信しています。
・インクリメンタルサーチのコードをみたい人
・ポップオーバーで検索結果を表示する方法がみたい人
・Objective-C初心者向け
インクリメンタルサーチとは?
インクリメンタルサーチ(英語: incremental search)は、アプリケーションにおける検索方法のひとつ。 検索したい単語をすべて入力した上で検索するのではなく、入力のたびごとに即座に候補を表示させる。
アプリ完成イメージ
インクリメンタルサーチ:仕様
今回はインクリメンタルサーチは前方一致にしました。
たとえばAで打った時に「EDCBA」はヒットせず、
「ABCDE」と出ます。
現場でインクリメンタルサーチを実装した時に検索結果数が、
膨大になってしまった事があって以来、
インクリメンタルサーチでは前方一致でなるべく数を減らして、
表示してますね。
ちなみにですが、ポップオーバー上のTableViewを押下すると
テキストフィールドに検索結果の候補が反映されます。
(例:AAAタップしたら、テキストフィールドにAAA)
実装の構成
(1)ViewController(h/m/xib)
(2)TableViewController(h/m)
上記で実装していますね。
ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (nonatomic) NSMutableArray *dataArray; //外部から渡されたマスタデータを格納できるようにhファイルに記載
@end
ViewController.m
#import "ViewController.h"
#import "TableViewController.h"
@interface ViewController ()<UIPopoverPresentationControllerDelegate,UITextFieldDelegate>
@property (weak,nonatomic) IBOutlet UITextField *textField;
@property (nonatomic) UIPopoverPresentationController *presentationController;
@end
@implementation ViewController
//testDemo
- (void)viewDidLoad {
[super viewDidLoad];
self.textField.delegate = self; //UITextFieldのデリゲートを指定している。
if(!self.dataArray){
self.dataArray = @[@"AAAA",@"BBBB",@"CCCC",@"DDDD",@"EEEE"].mutableCopy;
}
[self.textField addTarget:self
action:@selector(textFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
}
#pragma mark インクリメンタルサーチ関連処理
-(NSMutableArray *)checkIncrementalSearch{
NSMutableArray *incrementalArray = @[].mutableCopy;
for(NSString *str in self.dataArray){
if([str hasPrefix:self.textField.text]){
[incrementalArray addObject:str];
}
}
return incrementalArray;
}
#pragma mark UIPopoverPresentationController
- (void)presentPopOverWithViewController:(UIViewController *)viewController sourceView:(UIView *)sourceView
{
viewController.modalPresentationStyle = UIModalPresentationPopover;
viewController.preferredContentSize = CGSizeMake(120.0, [self checkIncrementalSearch].count*44);
self.presentationController = viewController.popoverPresentationController;
self.presentationController.delegate = self;
self.presentationController.permittedArrowDirections = UIPopoverArrowDirectionUp;
self.presentationController.sourceView = sourceView;
self.presentationController.sourceRect = sourceView.bounds;
//吹き出しの根本が色変わるのでおすすめ。
self.presentationController.backgroundColor = [UIColor whiteColor];
[self presentViewController:viewController animated:YES completion:NULL];
}
#pragma mark UITextField
//TextFieldの値が変わるたびに呼び出されるメソッド(TextFieldの値は常に更新後で拾える)
-(void)textFieldDidChange:(UITextField *)sender{
//本来であればpopOverが開かれている時のみ、という処理が好ましい。後に更新します。
if(self.presentationController){
self.presentationController = nil;
[self dismissViewControllerAnimated:YES completion:nil];
}
TableViewController *tableVC = [[TableViewController alloc]init];
if([self checkIncrementalSearch].count > 0){ //検索結果が1件以上ある
tableVC.receivedArray = [self checkIncrementalSearch];
tableVC.customBlock = ^(NSString *string){
self.textField.text = string;
[self dismissViewControllerAnimated:YES completion:nil];
};
//sourceView = ポップオーバーを出すオブジェクトという認識
[self presentPopOverWithViewController:tableVC sourceView:self.textField];
}
}
@end
TableViewController.h
#import <UIKit/UIKit.h>
typedef void(^MyCustomBlock)(NSString *);
@interface TableViewController : UITableViewController
@property (nonatomic) NSMutableArray *receivedArray;
@property (nonatomic, copy) MyCustomBlock customBlock;
@end
TableViewController.m
#import "TableViewController.h"
@interface TableViewController ()
@end
@implementation TableViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//必ずNSInteger型を返してあげている。
return self.receivedArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//標準で用意されているTableViewを利用する場合。
NSString *cellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = self.receivedArray[indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
self.customBlock(selectedCell.textLabel.text);
}
@end