[技术文档][技术中心][iOS部][114啦]全局搜索

需求说明

1、首页进入显示搜索历史,网页进入对关键词进行联想搜索。
2、搜索需要用web打开都统一新建标签页打开,加在最后面。
3、按照标签、工具、应用、经验、说明书、百度联想排序。
4、显示1条工具,点击更多显示工具列表。
5、显示3条相关的经验,点击更多进入更多经验列表。
6、显示3条相关的说明书,点击更多进入更多相关说明书的列表。
7、关键词联想,由百度提供该关键词的联想,并显示在底部。

需求地址

http://192.168.1.75/114la/220/114la_220/#g=1&p=2_2_%E6%90%9C%E7%B4%A2_%E6%B5%8F%E8%A7%88%E4%BA%A4%E4%BA%92

接口说明

URL:http://114larc.com/q/api/1.0/android/1.0/search
请求方式:GET

  • 请求参数说明:
参数名称 必选 类型 描述
q true string 关键字
  • 返回结果说明:
    列表中的type值:1-经验 2-说明书 3-工具 4-标签 5-应用,
    不同type对应不同的结构模型,经验和说明书结构一样,请参考下面的json数据结构:
    share:分享地址

  • 返回结果:

{
    "state": 1,
    "code": 0,
    "message": "",
    "data": {
        "share": "114larc.com/p/search?q=1",
        "list": [
            {
                "name": "标签",
                "type": 4,
                "list": [
                    "比较"
                ]
            },
            {
                "name": "工具",
                "type": 3,
                "list": [
                    {
                        "name": "比较6",
                        "url": "http://6.com",
                        "logo": "http://img.114larc.com/thumb/P/RC/3D/PRC3D74AC06B2B5772DF7ED285C6C31F5B0_100_100?s=6dt6DCcT4y78R5jmWyrsjQ"
                    }
                ]
            },
            {
                "name": "应用",
                "type": 5,
                "list": [
                    {
                        "pinyin": "bilin-402anzhuoyingyongapk",
                        "size": "31.1M",
                        "name": "比邻",
                        "description": "<p style=\"text-indent: 2em;\">软件简介:</p><p style=\"text-indent: 2em;\">比邻是一款<strong>电话社交</strong>平台APP,是一个刺激年轻人心跳的社交工具。</p><p style=\"text-indent: 2em;\">主要通过<strong>即时通话</strong>,随时畅聊你<strong>感兴趣</strong>的话题,并且可以通过精彩的图片和文字<strong>分享</strong>生活中的美好点滴,</p><p style=\"text-indent: 2em;\">也可以<strong>欣赏</strong>其它用户个性十足的个人资料和生活相册。</p><hr k_oof_k=\"line\" style=\"border-width: 1px 0px 0px; border-right-style: initial; border-bottom-style: initial; border-left-style: initial; border-right-color: initial; border-bottom-color: initial; border-left-color: initial; border-image: initial; border-top-style: dashed; border-top-color: rgb(204, 204, 204); height: 0px; overflow: hidden;\"><p style=\"text-indent: 2em;\">功能简介:</p><p style=\"text-indent: 2em;\">√<strong>随机电话</strong> - 无距离、无时差随时开聊</p><p style=\"text-indent: 2em;\">√<strong>超能力标签</strong> - 找到自己的独特话题</p><p style=\"text-indent: 2em;\">√<strong>最近在线</strong> - 温暖的陌生人都在这里</p><p style=\"text-indent: 2em;\">√<strong>连线好友</strong> - 免费无限时、无限次通话</p><hr k_oof_k=\"line\" style=\"border-width: 1px 0px 0px; border-right-style: initial; border-bottom-style: initial; border-left-style: initial; border-right-color: initial; border-bottom-color: initial; border-left-color: initial; border-image: initial; border-top-style: dashed; border-top-color: rgb(204, 204, 204); height: 0px; overflow: hidden;\"><p style=\"text-indent: 2em;\">使用场景:</p><p style=\"text-indent: 2em;\">√当你<strong>寂寞</strong>的时候,打打比邻,这里有人为你唱歌</p><p style=\"text-indent: 2em;\">√当你<strong>失眠</strong>的时候,打打比邻,这里有人哄你入睡</p><p style=\"text-indent: 2em;\">√当你<strong>难过</strong>的时候,打打比邻,这里有人逗你开心</p><p style=\"text-indent: 2em;\">√当你觉得<strong>冷</strong>的时候,打打比邻,这里有暖男热线</p><hr k_oof_k=\"line\" style=\"border-width: 1px 0px 0px; border-right-style: initial; border-bottom-style: initial; border-left-style: initial; border-right-color: initial; border-bottom-color: initial; border-left-color: initial; border-image: initial; border-top-style: dashed; border-top-color: rgb(204, 204, 204); height: 0px; overflow: hidden;\"><p style=\"text-indent: 2em;\">更新内容:</p><div style=\"text-indent: 2em;\">1、解决部分崩溃问题</div><div style=\"text-indent: 2em;\">2、优化随机群聊匹配</div>",
                        "logo": "http://img.anxia.com/thumb/P/DL/BB/PDLBB6E146E341F7900B35E690F7813E1B3_0?s=Sv8uwHljz5_qEeEM9hq7nA",
                        "sid": "18081",
                        "release_time": "1496073600",
                        "has_history": 0,
                        "url": "/a/bilin-402anzhuoyingyongapk"
                    }
                ]
            },
            {
                "name": "说明书",
                "type": 2,
                "list": [
                    {
                        "t_id": 90,
                        "c_id": 4362,
                        "type": 2,
                        "is_hot": 0,
                        "is_top": 0,
                        "subject": "苯巴比妥片",
                        "summary": "",
                        "state": 1,
                        "post_time": 1500968344,
                        "update_time": 1500982779,
                        "url": "http://114larc.com/s/detail/23D60020000004Y5BJDPASGK.html",
                        "cat_id": 0,
                        "useful_num": 0,
                        "is_useful": 0,
                        "location": "",
                        "icon_url": "http://img.114larc.com/thumb/P/RC/2D/PRC2D0CF8CCC0AAC491D879969C5B4BF3AD_800_800?s=TRfGkLQUmrIzy_5wETifbA",
                        "pics": [],
                        "tags": [
                            "失眠",
                            "心脑血管"
                        ]
                    }
                ]
            }
        ],
        "count": 4
    }
}

核心代码

进入搜索界面都先调用该方法,进行初始化操作

func urlBarViewDidClick(_ urlBarView: URLBarView) {
        if let keyworkSearch = MainViewFacade.sharedInstance.cache?.object(forKey: "keywork_search") as? [NSCoding] {
            let temp = NSMutableArray(array: keyworkSearch)
            //覆盖安装时,缓存的内容为【string】,需转化为模型
            if temp as AnyObject is [String] {
                for i in 0..<temp.count {
                    temp.replaceObject(at: i, with: SearchCellModel(keyword: temp[i] as? String ?? ""))
                }
            }
            if !isEqualContains(self.keyworkSearch, other: temp as AnyObject as? [SearchCellModel] ?? []) {
                self.keyworkSearch = temp as AnyObject as? [SearchCellModel] ?? []
            }
        }

        //文字修改
        changeUrlBarViewText()

        if self.contenView.superview == nil {
            self.addContenView()
            if urlBarView.addressTextField.text?.isEmpty == false {
                self.datas = []
            }
            shouldUpdateDatas = true
        } else {
            ////已经在搜索界面点击。成为焦点
            shouldUpdateDatas = false
        }
        
        textFieldText = urlBarView.addressTextField.text
        self.tableView.reloadData()
    }

修改该属性则会延迟0.6s执行搜索操作,还带有cancel上一次未完成的请求。

var textFieldText: String? {
        didSet {
            
            if textFieldText?.characters.count == 0 && shouldUpdateDatas {
                NSObject.cancelPreviousPerformRequests(withTarget: self)
                updateDatas("")
                return
            }
            guard textFieldText != oldValue else {
                if shouldUpdateDatas {
                    NSObject.cancelPreviousPerformRequests(withTarget: self)
                    self.perform(#selector(NewSearchViewManager.updateDatas(_:)), with:textFieldText, afterDelay: 0.1)
                    shouldUpdateDatas = false
                }
                return
            }

            NSObject.cancelPreviousPerformRequests(withTarget: self)
            self.perform(#selector(NewSearchViewManager.updateDatas(_:)), with:textFieldText, afterDelay: 0.6)
        }
    }

该方法则是真正发出请求。
该处分为两个接口,同时发出请求,先回来数据则先显示,后回来的则进行处理拼接起来后再刷新数据。
返回的结果是有固定的排序方式的。

func updateDatas(_ text: String?) {
        if text?.trimmingCharacters(in: CharacterSet.whitespaces).isEmpty == false {
            
            let enginModel = SearchGroupModel(SearchGroupType.engine)
            enginModel.searchDatas = [SearchCellModel(keyword: text!)]
            self.datas = [enginModel]
            self.tableView.reloadData()
            //114啦  热词联想搜索接口
            self.api.associateSearch(withKeywork: text!) { [weak self](keyworks, searchEngineURL) -> Void in
                guard let strongSelf = self else {
                    return
                }
                guard let keyworks = keyworks as? [String], strongSelf.textFieldText! == text else {
                    return
                }
                
                var levdatas = [SearchCellModel]()
                
                for kword in keyworks {
                    let model = SearchCellModel(keyword: kword)
                    levdatas.append(model)
                }
                
                if levdatas.count > 0 || text == "114la.com" || text == "115.com" {
                    if text == "w" || text == "ww" || text == "www" || text == "www."
                     || text == "114la.com" || text == "115.com" {
                        levdatas.insert(SearchCellModel(keyword: "www.115.com"), at: 0)
                        levdatas.insert(SearchCellModel(keyword: "www.114la.com"), at: 0)
                    }
                    let lenovoModel = SearchGroupModel(SearchGroupType.lenovo)
                    lenovoModel.searchDatas = levdatas
                    
                    
                    if let datas = strongSelf.datas, datas.last?.type == .share {
                        strongSelf.datas?.insert(lenovoModel, at: datas.count - 1)
                    } else {
                        strongSelf.datas?.append(lenovoModel)
                    }
                }
                strongSelf.tableView.isHidden = false
                strongSelf.tableView.dk_backgroundColorPicker = DKColor.picker(withNormalColor: UIConstants.NormalBackgroundColor, nightColor: UIConstants.NightDarkBackgroundColor)
                strongSelf.tableView.reloadData()
            }
            
            // 综合搜索
            YYW114LaService.comprehensiveSearch(keyword: text!, { (json, error) -> AnyObject? in
                if error != nil {
                    self.urlBarView?.addressTextField.resignFirstResponder()
                    return nil
                }
                if let json = json {
                    guard self.textFieldText! == text, json["state"].intValue == 1 else {
                        return nil
                    }
                    
                    let listDatas = json["data"]["list"].arrayValue
                    
                    var tempDatas = [SearchGroupModel]()
                
                    for type in showOrder {
                        if let dict = listDatas.filter({ (dict) -> Bool in
                            return dict["type"].intValue == type
                        }).first {
                            switch type {
                            case 1:
                                if dict["list"].arrayValue.count > 0 {
                                    tempDatas.append(SearchGroupModel(SearchGroupType.experience,dict["list"].arrayValue))
                                }
                            case 2:
                                if dict["list"].arrayValue.count > 0 {
                                    tempDatas.append(SearchGroupModel(SearchGroupType.instructions,dict["list"].arrayValue))
                                }
                            case 3:
                                if dict["list"].arrayValue.count > 0 {
                                    tempDatas.append(SearchGroupModel(SearchGroupType.tool,dict["list"].arrayValue))
                                }
                            case 4:
                                if dict["list"].arrayValue.count > 0 {
                                    let model = SearchGroupModel(.label)
                                    model.searchDatas = SearchGroupModel.getLabelModels(dict["list"].arrayValue)
                                    tempDatas.append(model)
                                }
                            case 5:
                                if dict["list"].arrayValue.count > 0 {
                                    tempDatas.append(SearchGroupModel(SearchGroupType.application,dict["list"].arrayValue))
                                }
                            case 999:
                                tempDatas.append(SearchGroupModel(SearchGroupType.ads,[dict["list"]]))
                            default:
                                break
                            }
                        }
                    }
                    
                    self.datas?.insert(contentsOf: tempDatas, at: 1)
                    if !json["data"]["share"].stringValue.isEmpty && tempDatas.count > 0
                    && self.datas?.last?.type != .share {
                        let shareModel = SearchGroupModel(SearchGroupType.share)
                        shareModel.searchDatas = [SearchCellModel(keyword: json["data"]["share"].stringValue)]
                        self.datas?.append(shareModel)
                    }
                    
                    self.tableView.dk_backgroundColorPicker = DKColor.picker(withNormalColor: UIConstants.NormalBackgroundColor, nightColor: UIConstants.NightDarkBackgroundColor)
                    self.tableView.isHidden = false
                    self.tableView.reloadData()
                }
                return nil
            })
        }
        else
        {
            shouldShowKeyWordSearch()
        }
    }

当点击搜索记录发生页面跳转,并且会记录搜索历史。

//处理url后进行加载
fileprivate func loadAndAddToHistoryWithURLString(_ URLString: String) {
        
        guard !isSearchUrlToChangeSearchKey(URLString) else { return }
        
        var text = self.searchEngineURL + URLString
        if let _ = MainViewFacade.sharedInstance.mainViewModel.verificationURL(URLString)
        {
            text = URLString
        }
        
        if UserDefaults.standard.bool(forKey: "isOpenSearch")
        {
            self.addKeyworkToSearchHistory(URLString)
        }
        
        if let request = MainViewFacade.sharedInstance.mainViewModel.verificationURL(text) {
            urlBarView?.clearText(UITapGestureRecognizer())
            urlBarView?.cancel()
//            MainViewFacade.sharedInstance.currentPageView().loadRequest(request)
            mainViewController()?.pageViewManager.newTabLoadRequest(request)
            if let absoluteString = request.url?.absoluteString {
                urlBarView?.addressTextString = absoluteString
            }
            cancelFocus()
        }
        
    }
//添加搜索历史记录 隐身模式不添加
    func addKeyworkToSearchHistory(_ keywork: String) {
        guard !self.isPrivate else {
            return
        }
        let index = isContainsKeyWord(keywork)
        if index >= 0 {
            self.keyworkSearch.remove(at: index)
        }
        let searchModel:SearchCellModel
        
        if let _ = MainViewFacade.sharedInstance.mainViewModel.verificationURL(keywork) {
            searchModel = SearchCellModel(dict: ["keyWord": keywork as AnyObject], type: .url)
        } else {
            searchModel = SearchCellModel(keyword: keywork)
        }
        
        self.keyworkSearch.insert(searchModel, at: 0)
        if self.keyworkSearch.count > 10 {
            self.keyworkSearch.removeSubrange(Range(10 ..< self.keyworkSearch.count))
        }
        MainViewFacade.sharedInstance.cache?.setObject(self.keyworkSearch as NSCoding, forKey: "keywork_search")
    }

添加分享搜索结果以后需要判断是不是打开分享出去的搜索结果url。
是的话则用原生UI打开搜索页面,不进行打开网页。

fileprivate func isSearchUrlToChangeSearchKey(_ text: String) -> Bool {//http://114larc.com/p/search?q=keyword
        if text.contains("114larc.com/p/search?q=") || text.contains("114la.com/p/search?q=") {
            let range = text.range(of: ".com/p/search?q=")
            var changeText = text.substring(from: range!.upperBound)
            changeText = changeText.removingPercentEncoding ?? changeText
            urlBarView?.addressTextField.text = changeText
            textFieldText = changeText
            return true
        }
        return false
    }

该搜索界面是将view添加在首页的view中的,显示时添加,取消搜索时将view移除。
使用的是同一个tableview。不会重新创建,因此每次需要初始化。

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,790评论 25 707
  • 1、万物遵循自然的规律;这个世界本来是一个圆,就像是太阳的升降,形成了四季。春天到秋天不能马上进入,需要夏天来过度...
    娜么好玩阅读 193评论 0 2
  • “宠辱不惊,看庭前花开花落;去留无意,望天边云卷云舒。”第一次看到这句话是在同学的QQ签名改上,当时只觉得这句话有...
    当下的航子阅读 386评论 2 6
  • 发现我的打卡时间越来越晚,这样不好,得调整。 今天上午把重要事项完成的差不多了,下午,晚上就分别约了朋友。一场憧憬...
    HR老白张小编阅读 149评论 1 2