iOS 搜索功能,粗仿網(wǎng)易云音樂

/**
最近做的項(xiàng)目中需要到一個(gè)仿照網(wǎng)易云音樂的搜索功能,我把它抽離出來(lái)供大家分享,有一些寫的不好的地方,歡迎大家指正
我在這里用朋友的測(cè)試接口展示數(shù)據(jù),僅供測(cè)試使用,請(qǐng)勿進(jìn)行商業(yè)用途
/
/

這里會(huì)講一下基本的搜索功能的搭建,首先是當(dāng)點(diǎn)擊搜索框的時(shí)候,調(diào)起鍵盤并顯示搜索歷史記錄,然后在點(diǎn)擊記錄時(shí)返回搜索數(shù)據(jù)
當(dāng)點(diǎn)擊鍵盤時(shí)候,顯示匹配到的關(guān)鍵字,點(diǎn)擊字段返回?cái)?shù)據(jù)并將該字段存入到歷史記錄中
雖然搜索功能很小很簡(jiǎn)單,但是不細(xì)心的話也會(huì)出現(xiàn)很多bug,我會(huì)把我想到的一些注意事項(xiàng)寫在項(xiàng)目中,歡迎大家指正補(bǔ)充
**/

效果圖如下:


搜索Gif.gif

我們先來(lái)分析一下:首先點(diǎn)擊搜索框的時(shí)候,彈出鍵盤,顯示歷史記錄;點(diǎn)擊鍵盤開始輸入時(shí),需要匹配關(guān)鍵字;點(diǎn)擊鍵盤上的搜索,點(diǎn)擊歷史記錄,點(diǎn)擊匹配到的關(guān)鍵字的時(shí)候都要返回值,然后界面刷新UI。
我們需要搭建一個(gè)本地?cái)?shù)據(jù)庫(kù)來(lái)存儲(chǔ)搜索的歷史記錄
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;
    /
    *
  • 刪除一個(gè)收藏
    */
  • (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ù)庫(kù)

  • (void)creatDataBase
    {
    // 在Documents文件夾下創(chuàng)建db.sqlite
    NSString *dbPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"db.splite"];

    // 初始化
    self.db = [FMDatabase databaseWithPath:dbPath];
    // 打開數(shù)據(jù)庫(kù)
    [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>

搭建一下主界面,這里我是用一個(gè)collectionView寫的. 實(shí)現(xiàn)代理方法
<pre>
/**

  • 創(chuàng)建一個(gè)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上添加一個(gè)搜索框
    self.searchTextField = [[UITextField alloc] initWithFrame:CGRectMake(50, 20, ScreenWidth-100, 40)];
    _searchTextField.placeholder = @"??輸入關(guān)鍵字查詢";
    _searchTextField.textColor = [UIColor redColor];
    _searchTextField.borderStyle = UITextBorderStyleRoundedRect;
    [self.view addSubview:_searchTextField];
    // 設(shè)置textfield的return鍵為搜索鍵
    _searchTextField.returnKeyType = UIReturnKeySearch;
    // 設(shè)置textfield的代理
    _searchTextField.delegate = self;

}

</pre>

然后我們需要再寫一個(gè)tableView,用來(lái)展示歷史記錄和匹配到的關(guān)鍵字
<pre>
**

  • table的cell有兩種,一種是歷史的cell,一種是匹配關(guān)鍵字的cell,這里我建了兩個(gè)cell
  • 分別展示,根據(jù)傳入的一個(gè)標(biāo)識(shí)分別創(chuàng)建(因?yàn)閮蓚€(gè)cell只有一個(gè)button的區(qū)別,也可以創(chuàng)建一
  • 個(gè)cell再來(lái)控制button的顯隱性。不過我特么就是想創(chuàng)建兩個(gè))
    */
  • (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;

    // 當(dāng)tableView滑動(dòng)時(shí)收起鍵盤
    _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ù)源
/
我在這里用一個(gè)替換字段接收請(qǐng)求下來(lái)的匹配字段的數(shù)據(jù)。。不這樣做的話,在匹配字段返回的cell時(shí),如果是在漢語(yǔ)模式下編輯,在沒有確定輸入字段時(shí),此時(shí)已經(jīng)匹配到了字段,但是如果點(diǎn)擊的時(shí)候,在點(diǎn)擊事件中,原來(lái)的數(shù)據(jù)源是空的,可能是我在哪里清空了原來(lái)的數(shù)據(jù)源,我沒有找到,只能用一個(gè)新的數(shù)據(jù)源來(lái)替代。英文模式下輸入,暫時(shí)沒有發(fā)現(xiàn)這種問題(讀這個(gè)源碼的朋友如果能改進(jìn)這個(gè)錯(cuò)誤請(qǐng)私信我,萬(wàn)分感謝?。。。?/em>*/
@property (nonatomic, strong) NSMutableArray *placeTextDataSource; // 替換匹配字段

@property (nonatomic, strong) NSString *judgeStr; // 用來(lái)判斷展示的table

@property (nonatomic, strong) SearchModel *model;

// 輸入顯示字段
@property (nonatomic, strong) NSString *textFieldStr;

@end
</pre>
我們要通過textField的代理事件來(lái)實(shí)現(xiàn)搜索的交互事件
<pre>

pragma mark --- TextFieldDelegate

/**

  • 點(diǎn)擊鍵盤搜索按鈕
    */
  • (BOOL)textFieldShouldReturn:(UITextField *)textField
    {
    // 收起鍵盤
    [_searchTextField resignFirstResponder];
    // 移除tableView
    [_myTable removeFromSuperview];
    // 先清空數(shù)據(jù)源,然后請(qǐng)求數(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;

}
/**

  • 點(diǎn)擊輸入框開始編輯時(shí)走這個(gè)方法。 (我們需要點(diǎn)擊輸入框時(shí),在輸入框下面出現(xiàn)一
  • 個(gè)tableView來(lái)展示搜索的歷史記錄)
    */
  • (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];
    }

/**

  • 當(dāng)我們開始編輯時(shí),根據(jù)我們當(dāng)前輸入的字段進(jìn)行匹配關(guān)鍵字,需要用到這個(gè)方法。 這個(gè)方法
  • 是當(dāng)輸入框內(nèi)容開始發(fā)生變化時(shí)調(diào)用
    */
  • (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {

    // 輸入時(shí)開始匹配關(guān)鍵字,顯示另一個(gè)tableView
    // 先移除之前添加上的tableView
    [self.myTable removeFromSuperview];
    // 再次添加
    self.judgeStr = keyWord;
    [self creatTableViewWithStr:self.judgeStr];

    self.textFieldStr = string;

    // 請(qǐng)求匹配關(guān)鍵字
    // 先清空保存的數(shù)據(jù)
    [self.textFieldDataSource removeAllObjects];
    [self getDataByTextfieldText:self.textFieldStr];

    return YES;
    }

</pre>

代碼有點(diǎn)多,不明白的同學(xué)可以到我的git主頁(yè)上下載源碼,里面注釋寫的也比較詳細(xì)
git:https://github.com/you12138/SearchLikeWangYiMusic.git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,138評(píng)論 25 708
  • Swift版本點(diǎn)擊這里歡迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh閱讀 26,159評(píng)論 7 249
  • 我在這里, 你也在這里, 我們熟識(shí),卻又像路人, 我們不曾伴著咖啡長(zhǎng)談, 只有匆匆的遇見。 美麗過后,你還是那個(gè)你...
    流楓鮰雪閱讀 60評(píng)論 0 0
  • 睡不著的時(shí)候,最美好的事便是靜聽夜的語(yǔ)言。 最近天氣燥熱地非常,每晚不能正常入睡,今晚算是徹底的一回。我在床上輾轉(zhuǎn)...
    曾彧閱讀 602評(píng)論 9 2
  • 這幾天心里很煩,人生的諸多不順總是在不經(jīng)意的襲來(lái),社會(huì)繁忙凝成了心中沉重的困惑,我自己仿佛成了一只孤獨(dú)而又疲...
    玫瑰心閱讀 224評(píng)論 0 1

友情鏈接更多精彩內(nèi)容