iOS 搜索功能,粗仿网易云音乐

/**
最近做的项目中需要到一个仿照网易云音乐的搜索功能,我把它抽离出来供大家分享,有一些写的不好的地方,欢迎大家指正
我在这里用朋友的测试接口展示数据,仅供测试使用,请勿进行商业用途
/
/

这里会讲一下基本的搜索功能的搭建,首先是当点击搜索框的时候,调起键盘并显示搜索历史记录,然后在点击记录时返回搜索数据
当点击键盘时候,显示匹配到的关键字,点击字段返回数据并将该字段存入到历史记录中
虽然搜索功能很小很简单,但是不细心的话也会出现很多bug,我会把我想到的一些注意事项写在项目中,欢迎大家指正补充
**/

效果图如下:


搜索Gif.gif

我们先来分析一下:首先点击搜索框的时候,弹出键盘,显示历史记录;点击键盘开始输入时,需要匹配关键字;点击键盘上的搜索,点击历史记录,点击匹配到的关键字的时候都要返回值,然后界面刷新UI。
我们需要搭建一个本地数据库来存储搜索的历史记录
DataBase.h
<pre>

import <Foundation/Foundation.h>

import "SearchModel.h"

@interface DataBase : NSObject

/**

  • 创建单例接口
    */
  • (DataBase *)shareDataBase;

pragma mark -

/**

  • 收藏接口
    */
  • (void)saveModel:(SearchModel )model;
    /
    *
  • 判断是否已经收藏
    */
  • (BOOL)isHadSaveModel:(SearchModel )model;
    /
    *
  • 获取收藏的所有数据
    */
  • (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
// 创建单例

  • (DataBase *)shareDataBase
    {
    static DataBase *single = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    single = [[DataBase alloc] init];
    [single creatDataBase];
    });
    return single;
    }

// 创建数据库

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

    // 初始化
    self.db = [FMDatabase databaseWithPath:dbPath];
    // 打开数据库
    [self.db open];
    // 创建表格
    [self creatTable];

}

  • (void)creatTable
    {
    BOOL isSuccess = [self.db executeUpdate:@"create table if not exists MV(id integer primary key autoincrement, historyStr text)"];
    NSLog(@"%@", isSuccess ? @"表格创建成功":@"表格创建失败");
    }

  • (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写的. 实现代理方法
<pre>
/**

  • 创建一个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
  • 分别展示,根据传入的一个标识分别创建(因为两个cell只有一个button的区别,也可以创建一
  • 个cell再来控制button的显隐性。不过我特么就是想创建两个)
    */
  • (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数据源
@property (nonatomic, strong) NSMutableArray textFieldDataSource; // 匹配字段数据源
@property (nonatomic, strong) NSMutableArray historyDataSource; // 搜索历史数据源
/
我在这里用一个替换字段接收请求下来的匹配字段的数据。。不这样做的话,在匹配字段返回的cell时,如果是在汉语模式下编辑,在没有确定输入字段时,此时已经匹配到了字段,但是如果点击的时候,在点击事件中,原来的数据源是空的,可能是我在哪里清空了原来的数据源,我没有找到,只能用一个新的数据源来替代。英文模式下输入,暂时没有发现这种问题(读这个源码的朋友如果能改进这个错误请私信我,万分感谢!!!)
*/
@property (nonatomic, strong) NSMutableArray *placeTextDataSource; // 替换匹配字段

@property (nonatomic, strong) NSString *judgeStr; // 用来判断展示的table

@property (nonatomic, strong) SearchModel *model;

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

@end
</pre>
我们要通过textField的代理事件来实现搜索的交互事件
<pre>

pragma mark --- TextFieldDelegate

/**

  • 点击键盘搜索按钮
    */
  • (BOOL)textFieldShouldReturn:(UITextField *)textField
    {
    // 收起键盘
    [_searchTextField resignFirstResponder];
    // 移除tableView
    [_myTable removeFromSuperview];
    // 先清空数据源,然后请求数据
    [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;

}
/**

  • 点击输入框开始编辑时走这个方法。 (我们需要点击输入框时,在输入框下面出现一
  • 个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];
    }

/**

  • 当我们开始编辑时,根据我们当前输入的字段进行匹配关键字,需要用到这个方法。 这个方法
  • 是当输入框内容开始发生变化时调用
    */
  • (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;

    // 请求匹配关键字
    // 先清空保存的数据
    [self.textFieldDataSource removeAllObjects];
    [self getDataByTextfieldText:self.textFieldStr];

    return YES;
    }

</pre>

代码有点多,不明白的同学可以到我的git主页上下载源码,里面注释写的也比较详细
git:https://github.com/you12138/SearchLikeWangYiMusic.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,398评论 25 707
  • Swift版本点击这里欢迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh阅读 25,266评论 7 249
  • 我在这里, 你也在这里, 我们熟识,却又像路人, 我们不曾伴着咖啡长谈, 只有匆匆的遇见。 美丽过后,你还是那个你...
    流枫鮰雪阅读 53评论 0 0
  • 睡不着的时候,最美好的事便是静听夜的语言。 最近天气燥热地非常,每晚不能正常入睡,今晚算是彻底的一回。我在床上辗转...
    曾彧阅读 510评论 9 2
  • 这几天心里很烦,人生的诸多不顺总是在不经意的袭来,社会繁忙凝成了心中沉重的困惑,我自己仿佛成了一只孤独而又疲...
    玫瑰心阅读 198评论 0 1