/**
最近做的項目中需要到一個仿照網(wǎng)易云音樂的搜索功能,我把它抽離出來供大家分享诵冒,有一些寫的不好的地方撑碴,歡迎大家指正
我在這里用朋友的測試接口展示數(shù)據(jù),僅供測試使用叹话,請勿進行商業(yè)用途
/
/
這里會講一下基本的搜索功能的搭建偷遗,首先是當點擊搜索框的時候,調(diào)起鍵盤并顯示搜索歷史記錄驼壶,然后在點擊記錄時返回搜索數(shù)據(jù)
當點擊鍵盤時候氏豌,顯示匹配到的關鍵字,點擊字段返回數(shù)據(jù)并將該字段存入到歷史記錄中
雖然搜索功能很小很簡單热凹,但是不細心的話也會出現(xiàn)很多bug泵喘,我會把我想到的一些注意事項寫在項目中,歡迎大家指正補充
**/
效果圖如下:
我們先來分析一下:首先點擊搜索框的時候般妙,彈出鍵盤纪铺,顯示歷史記錄;點擊鍵盤開始輸入時碟渺,需要匹配關鍵字鲜锚;點擊鍵盤上的搜索,點擊歷史記錄苫拍,點擊匹配到的關鍵字的時候都要返回值芜繁,然后界面刷新UI。
我們需要搭建一個本地數(shù)據(jù)庫來存儲搜索的歷史記錄
DataBase.h
<pre>
import <Foundation/Foundation.h>
import "SearchModel.h"
@interface DataBase : NSObject
/**
- 創(chuàng)建單例接口
*/
- (DataBase *)shareDataBase;
pragma mark -
/**
- 收藏接口
*/
- (void)saveModel:(SearchModel )model;
/*
- 判斷是否已經(jīng)收藏
*/
- (BOOL)isHadSaveModel:(SearchModel )model;
/*
- 獲取收藏的所有數(shù)據(jù)
*/
- (NSArray )selectAllModel;
/*
- 刪除一個收藏
*/
- (void)deleteOneModelByStr:(NSString *)str;
@end
</pre>
.m
<pre>
import "DataBase.h"
import "FMDB.h"
@interface DataBase ()
@property (nonatomic, strong) FMDatabase *db;
@end
@implementation DataBase
// 創(chuàng)建單例
- (DataBase *)shareDataBase
{
static DataBase *single = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
single = [[DataBase alloc] init];
[single creatDataBase];
});
return single;
}
// 創(chuàng)建數(shù)據(jù)庫
-
(void)creatDataBase
{
// 在Documents文件夾下創(chuàng)建db.sqlite
NSString *dbPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"db.splite"];// 初始化
self.db = [FMDatabase databaseWithPath:dbPath];
// 打開數(shù)據(jù)庫
[self.db open];
// 創(chuàng)建表格
[self creatTable];
}
(void)creatTable
{
BOOL isSuccess = [self.db executeUpdate:@"create table if not exists MV(id integer primary key autoincrement, historyStr text)"];
NSLog(@"%@", isSuccess ? @"表格創(chuàng)建成功":@"表格創(chuàng)建失敗");
}(BOOL)isHadSaveModel:(SearchModel *)model
{
FMResultSet *set = [self.db executeQuery:@"select * from MV where historyStr = ?", model.historyStr];
while ([set next]) {
NSString *historyStr = [set stringForColumn:@"historyStr"];
if ([model.historyStr isEqualToString:historyStr]) {
return YES;
}
}
return NO;
}-
(void)saveModel:(SearchModel *)model
{
BOOL isSuccess = [self.db executeUpdate:@"insert into MV(historyStr) values (?)", model.historyStr];NSLog(@"%@", isSuccess ? @"收藏成功":@"收藏失敗");
} (NSArray *)selectAllModel
{
FMResultSet *set = [self.db executeQuery:@"select *from MV"];
NSMutableArray *arr = [NSMutableArray array];
while ([set next]) {
NSString *historyStr = [set stringForColumn:@"historyStr"];
SearchModel *model = [[SearchModel alloc] init];
model.historyStr = historyStr;
[arr addObject:model];
}
return arr;
}-
(void)deleteOneModelByStr:(NSString *)str
{
BOOL isSuccess = [self.db executeUpdate:@"delete from MV where historyStr = ?", str];NSLog(@"%@", isSuccess ? @"刪除成功":@"刪除失敗");
}
</pre>
搭建一下主界面绒极,這里我是用一個collectionView寫的. 實現(xiàn)代理方法
<pre>
/**
- 創(chuàng)建一個collectionView
*/
-
(void)creatCollectionView
{
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
self.myCollection = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 60, ScreenWidth, ScreenHeight - 60) collectionViewLayout:flowLayout];
self.myCollection.backgroundColor = [UIColor orangeColor];
_myCollection.dataSource = self;
_myCollection.delegate = self;
[self.view addSubview:_myCollection];
[_myCollection registerClass:[UserCollectionViewCell class] forCellWithReuseIdentifier:cellID];
[self.view addSubview:_myCollection];// 在collection上添加一個搜索框
self.searchTextField = [[UITextField alloc] initWithFrame:CGRectMake(50, 20, ScreenWidth-100, 40)];
_searchTextField.placeholder = @"??輸入關鍵字查詢";
_searchTextField.textColor = [UIColor redColor];
_searchTextField.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:_searchTextField];
// 設置textfield的return鍵為搜索鍵
_searchTextField.returnKeyType = UIReturnKeySearch;
// 設置textfield的代理
_searchTextField.delegate = self;
}
</pre>
然后我們需要再寫一個tableView骏令,用來展示歷史記錄和匹配到的關鍵字
<pre>
**
- table的cell有兩種,一種是歷史的cell集峦,一種是匹配關鍵字的cell伏社,這里我建了兩個cell
- 分別展示抠刺,根據(jù)傳入的一個標識分別創(chuàng)建(因為兩個cell只有一個button的區(qū)別,也可以創(chuàng)建一
- 個cell再來控制button的顯隱性摘昌。不過我特么就是想創(chuàng)建兩個)
*/
-
(void)creatTableViewWithStr:(NSString *)str
{
self.myTable = [[UITableView alloc] initWithFrame:CGRectMake(0, 60, ScreenWidth, ScreenHeight-60) style:(UITableViewStylePlain)];
if ([str isEqualToString:@"history"]) {
[_myTable registerNib:[UINib nibWithNibName:@"HistoryTableViewCell" bundle:nil] forCellReuseIdentifier:tableCellId];
}else {
[_myTable registerNib:[UINib nibWithNibName:@"KeyWordTableViewCell" bundle:nil] forCellReuseIdentifier:tableCellId];
} _myTable.delegate = self;
_myTable.dataSource = self;// 當tableView滑動時收起鍵盤
_myTable.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
// 取消tableView的分割線
_myTable.separatorStyle = UITableViewCellSeparatorStyleNone;[self.view addSubview:_myTable];
}
</pre>
在這里看一下我在主控制器中所定義的屬性速妖,都是要用到的。
<pre>
@interface ViewController ()<UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) UICollectionView *myCollection; //
@property (nonatomic, strong) UITableView *myTable; //
@property (nonatomic, strong) UITextField *searchTextField; // 搜索框
@property (nonatomic, strong) NSMutableArray dataSource; // cell數(shù)據(jù)源
@property (nonatomic, strong) NSMutableArray textFieldDataSource; // 匹配字段數(shù)據(jù)源
@property (nonatomic, strong) NSMutableArray historyDataSource; // 搜索歷史數(shù)據(jù)源
/我在這里用一個替換字段接收請求下來的匹配字段的數(shù)據(jù)聪黎。罕容。不這樣做的話,在匹配字段返回的cell時稿饰,如果是在漢語模式下編輯锦秒,在沒有確定輸入字段時,此時已經(jīng)匹配到了字段喉镰,但是如果點擊的時候旅择,在點擊事件中,原來的數(shù)據(jù)源是空的侣姆,可能是我在哪里清空了原來的數(shù)據(jù)源生真,我沒有找到,只能用一個新的數(shù)據(jù)源來替代捺宗。英文模式下輸入柱蟀,暫時沒有發(fā)現(xiàn)這種問題(讀這個源碼的朋友如果能改進這個錯誤請私信我,萬分感謝Q晾鳌3ひ选!)*/
@property (nonatomic, strong) NSMutableArray *placeTextDataSource; // 替換匹配字段
@property (nonatomic, strong) NSString *judgeStr; // 用來判斷展示的table
@property (nonatomic, strong) SearchModel *model;
// 輸入顯示字段
@property (nonatomic, strong) NSString *textFieldStr;
@end
</pre>
我們要通過textField的代理事件來實現(xiàn)搜索的交互事件
<pre>
pragma mark --- TextFieldDelegate
/**
- 點擊鍵盤搜索按鈕
*/
-
(BOOL)textFieldShouldReturn:(UITextField *)textField
{
// 收起鍵盤
[_searchTextField resignFirstResponder];
// 移除tableView
[_myTable removeFromSuperview];
// 先清空數(shù)據(jù)源昼牛,然后請求數(shù)據(jù)
[self.dataSource removeAllObjects];
[self getDataByText:textField.text];// 存入搜索歷史
_model.historyStr = textField.text;
if (textField.text.length>0) {
if (![[DataBase shareDataBase] isHadSaveModel:_model]) {
[[DataBase shareDataBase] saveModel:_model];
}
}
return YES;
}
/**
- 點擊輸入框開始編輯時走這個方法术瓮。 (我們需要點擊輸入框時,在輸入框下面出現(xiàn)一
- 個tableView來展示搜索的歷史記錄)
*/
-
(void)textFieldDidBeginEditing:(UITextField *)textField
{// 先移除之前添加上的tableView
[self.myTable removeFromSuperview];
// 再次添加
self.judgeStr = History;
[self creatTableViewWithStr:self.judgeStr];// 打開輸入框后匾嘱,展示搜索歷史記錄
self.historyDataSource = [NSMutableArray arrayWithArray:[[DataBase shareDataBase] selectAllModel]];
[self.myTable reloadData];
}
/**
- 當我們開始編輯時斤斧,根據(jù)我們當前輸入的字段進行匹配關鍵字,需要用到這個方法霎烙。 這個方法
- 是當輸入框內(nèi)容開始發(fā)生變化時調(diào)用
*/
-
(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{// 輸入時開始匹配關鍵字,顯示另一個tableView
// 先移除之前添加上的tableView
[self.myTable removeFromSuperview];
// 再次添加
self.judgeStr = keyWord;
[self creatTableViewWithStr:self.judgeStr];self.textFieldStr = string;
// 請求匹配關鍵字
// 先清空保存的數(shù)據(jù)
[self.textFieldDataSource removeAllObjects];
[self getDataByTextfieldText:self.textFieldStr];return YES;
}
</pre>
代碼有點多蕊连,不明白的同學可以到我的git主頁上下載源碼悬垃,里面注釋寫的也比較詳細
git:https://github.com/you12138/SearchLikeWangYiMusic.git