美文网首页
swift-城市搜索选择器

swift-城市搜索选择器

作者: 一蓑丨烟雨 | 来源:发表于2017-09-19 10:42 被阅读366次

    代码:

    import UIKit
    
    typealias MyCityBlock = (_ str:String)->Void
    
    class CitySelectorViewController: UIViewController {
        //城市列表
        lazy var cityTBView:UITableView = UITableView(frame: UIScreen.mainBounds, style: .plain)
        //搜索结果控制器
        lazy var searchResultVC:ResultSearchView = {
            let resultVC = ResultSearchView(frame: CGRect.init(x: 0, y: -UIScreen.mainHeight, width: UIScreen.mainWidth, height: UIScreen.mainHeight), style: .plain)
            resultVC.backgroundColor = UIColor.white
            return resultVC
        }()
        //返回按钮
        lazy var backBtn:UIButton = {
            let btn = UIButton(frame: CGRect(x: 10, y: 10, width: 24, height: 24))
            btn.setBackgroundImage(UIImage(named:"关闭"), for: .normal)
            btn.addTarget(self, action: #selector(backToHomeView), for: .touchUpInside)
            return btn
        }()
        //搜索控制器
        lazy var searchView:UIView = {
            let searchV = UIView(frame:CGRect(x: UIScreen.mainWidth*0.2, y: 7, width: UIScreen.mainWidth*0.6, height: 30))
            searchV.addSubview(self.searchBar)
            searchV.layer.masksToBounds = true
            searchV.layer.cornerRadius = 15
            searchV.backgroundColor = UIColor.white
            return searchV
        }()
        //搜索图标
        lazy var searchImgView:UIImageView = {
            let imgV = UIImageView(image: UIImage(named: "搜索"))
            imgV.contentMode = .scaleAspectFit
            return imgV
        }()
        //搜索框
        lazy var searchBar:UITextField = {
            let textF = UITextField(frame: CGRect(x: 30, y: 0, width: UIScreen.mainWidth*0.6-60, height: 30))
            textF.leftView = self.searchImgView
            textF.font = Font.large
            textF.placeholder = "输入城市名称或拼音"
            textF.textColor = Color.textH
            textF.clearButtonMode = UITextFieldViewMode.always
            textF.tintColor = Color.topNav
            textF.leftViewMode = UITextFieldViewMode.always
            textF.delegate = self
            textF.returnKeyType = UIReturnKeyType.done
            return textF
        }()
        //取消按钮
        lazy var cancleBtn:UIButton = {
            let btn = UIButton(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
            btn.setTitle("取消", for: .normal)
            btn.titleLabel?.font = Font.large
            btn.isHidden = true
            btn.addTarget(self, action: #selector(endSearching), for: .touchUpInside)
            return btn
        }()
    
        //获取城市数据
        lazy var cityDic:[String:[String]] = {
            let path = Bundle.main.path(forResource: "cities", ofType: "plist")
            let dic = NSDictionary(contentsOfFile: path!)
            return dic as! [String : [String]]
        }()
        //热门城市
        lazy var hotCities:[String] = {
            let path = Bundle.main.path(forResource: "hotCities", ofType: "plist")
            let array = NSArray(contentsOfFile: path!)
            return array as! [String]
        }()
        
        //标题数组
        lazy var titleArray:[String] = {
            var array = [String]()
            for str in self.cityDic.keys {
                array.append(str)
            }
            array.sort()
            array.insert("热门", at: 0)
            array.insert("定位", at: 0)
            return array
        }()
        
        //更新位置闭包
        var updateCityName:MyCityBlock?
        
        override func viewDidLoad() {
            super.viewDidLoad()
            self.navigationController?.navigationBar.tintColor = UIColor.white
            UIApplication.shared.statusBarStyle = .lightContent
            setupUI()
        }
        func setupUI(){
            //设置searchBar
            self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backBtn)
            self.navigationController?.navigationBar.addSubview(self.searchView)
            self.navigationController?.navigationBar.addSubview(cancleBtn)
            
            //设置导航条
            self.navigationController?.navbackgrouondImage = UIImage.createNVImage(by: Color.topNav)
            
            cityTBView.delegate = self
            cityTBView.dataSource = self
            cityTBView.register(UITableViewCell.self, forCellReuseIdentifier: normalCell)
            cityTBView.register(LocationCitiesCell.self, forCellReuseIdentifier: locaCityCell)
            cityTBView.register(HotCitiesCell.self, forCellReuseIdentifier: hotCityCell)
            
            //索引
            cityTBView.sectionIndexColor = Color.topNav
            cityTBView.sectionIndexBackgroundColor = Color.mainBg
            
            //Header View
            cityTBView.tableHeaderView = CurrentCityView(frame: CGRect(x: 0, y: 0, width: UIScreen.mainWidth, height: 44))
            self.view.addSubview(cityTBView)
            self.view.addSubview(self.searchResultVC)
        }
        
        //MARK: 返回
        func backToHomeView(){
            self.dismiss(animated: true, completion: nil)
        }
        
        deinit {
            print("返回到首页")
        }
        override func viewWillLayoutSubviews() {
            self.cancleBtn.snp.makeConstraints { (make) in
                make.left.equalTo(self.searchView.snp.right).offset(5)
                make.top.bottom.equalToSuperview()
                make.width.equalTo(44)
            }
        }
        func endSearching(){
    
            SPAnimation.animate(0.5, animations: {
                self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: self.backBtn)
                self.searchView.frame = CGRect(x: UIScreen.mainWidth*0.2, y: 7, width: UIScreen.mainWidth*0.6, height: 30)
                self.searchBar.frame = CGRect(x: 30, y: 0, width: UIScreen.mainWidth*0.6-60, height: 30)
                self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: self.backBtn)
                self.searchBar.text = nil
                self.cancleBtn.isHidden = true
                self.searchResultVC.frame = CGRect(x: 0, y: -UIScreen.mainHeight, width: UIScreen.mainWidth, height: UIScreen.mainHeight)
            })
        }
        func beginSearching(){
    
            SPAnimation.animate(0.5, animations: {
                self.navigationItem.leftBarButtonItem = nil
                self.searchView.frame = CGRect(x: 15, y: 7, width: UIScreen.mainWidth*0.8-15, height: 30)
                self.searchBar.frame = CGRect(x: 5, y: 0, width: UIScreen.mainWidth*0.8-20, height: 30)
                self.cancleBtn.isHidden = false
                self.searchResultVC.frame = CGRect(x: 0, y: 0, width: UIScreen.mainWidth, height: UIScreen.mainHeight)
            })
        }
       
    }
    
    //MARK: - 搜索代理方法
    extension CitySelectorViewController:UITextFieldDelegate{
        //开始输入时开始搜索
        func textFieldDidBeginEditing(_ textField: UITextField) {
           self.beginSearching()
        }
        //结束编辑
        func textFieldDidEndEditing(_ textField: UITextField) {
            self.getSearchResultArray(searchBarText: "")
        }
        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            let str = textField.text! as NSString
            
            let searhStr = str.replacingCharacters(in: range, with: string)
            self.getSearchResultArray(searchBarText: searhStr)
            return true
        }
        func textFieldShouldReturn(_ textField: UITextField) -> Bool {
            self.view.endAllEditing()
            return true
        }
    }
    
    //MARK:- 城市列表的 代理方法  tableView
    extension CitySelectorViewController:UITableViewDelegate,UITableViewDataSource{
        func numberOfSections(in tableView: UITableView) -> Int {
            return titleArray.count
        }
        
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            if section > 1 {
                let key = titleArray[section]
                return cityDic[key]!.count - 3
            }
            return 1
        }
        
        // MARK: 创建cell
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
            if indexPath.section == 0 {
                
                let cell = tableView.dequeueReusableCell(withIdentifier: locaCityCell, for: indexPath) as! LocationCitiesCell
                return cell
            }else if indexPath.section == 1 {
                
                let cell = tableView.dequeueReusableCell(withIdentifier: hotCityCell, for: indexPath) as! HotCitiesCell
                cell.cityClicked = {(cityName:String) in
                    self.updateCityName!(cityName)
                    self.backToHomeView()
                }
                return cell
            }else {
                let cell = tableView.dequeueReusableCell(withIdentifier: normalCell, for: indexPath)
                // cell.backgroundColor = cellColor
                let key = titleArray[indexPath.section]
                cell.textLabel?.text = cityDic[key]![indexPath.row]
                return cell
            }
        }
        // MARK: 点击cell
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            tableView.deselectRow(at: indexPath, animated: true)
            if indexPath.section > 1 {
                tableView.deselectRow(at: indexPath, animated: false)
                let key = titleArray[indexPath.section]
                CurrentCity.shar.name = self.cityDic[key]![indexPath.row]
                updateCityName!(CurrentCity.shar.name)
                backToHomeView()
            }
        }
        
        // MARK: 右边索引
        func sectionIndexTitles(for tableView: UITableView) -> [String]? {
            return titleArray
        }
        
        // MARK: section头视图
        func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
            let view = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.mainWidth+20, height: sectionMargin))
            view.backgroundColor = Color.mainBg
            let title = UILabel(frame: CGRect(x: 20, y: 5, width: UIScreen.mainWidth, height: 28))
            var titleArr = titleArray
            titleArr[0] = "定位城市"
            titleArr[1] = "热门城市"
            title.text = titleArr[section]
            title.textColor = Color.textM
            title.font = Font.largeP
            view.addSubview(title)
            
            if section > 1 {
                view.backgroundColor = Color.bgColor
                title.textColor = UIColor.darkGray
            }
            
            return view
        }
        
        func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
          
            return sectionMargin
        }
        
        // MARK: row高度
        func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
           if indexPath.section == 0 {
                return btnHeight + 2 * btnMargin
            }else if indexPath.section == 1 {
                let row = (hotCities.count - 1) / 3
                return (btnHeight + 2 * btnMargin) + (btnMargin + btnHeight) * CGFloat(row)
            }else{
                return 42
            }
        }
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            self.view.endEditing(true)
        }
    
    }
    
    //MARK: - 搜索逻辑
    extension CitySelectorViewController{
        fileprivate func getSearchResultArray(searchBarText: String){
            var resultArray:[String] = []
            if searchBarText == "" {
                searchResultVC.resultArray = resultArray
                return
            }
            // 传递闭包 当点击’搜索结果‘的cell调用
            searchResultVC.updateCityName = {(cityName:String) in
                CurrentCity.shar.name = cityName
                self.updateCityName!(cityName)
                self.backToHomeView()
            }
            // 中文搜索
    
            if searchBarText.isIncludeChineseIn() {
                // 转拼音
                let pinyin = searchBarText.chineseToPinyin()
                // 获取大写首字母
                let first = String(pinyin[pinyin.startIndex]).uppercased()
                guard let dic = cityDic[first] else {
                    return
                }
                for str in dic {
                    if str.hasPrefix(searchBarText) {
                        resultArray.append(str)
                    }
                }
                searchResultVC.resultArray = resultArray
            }else {
                // 拼音搜索
                // 若字符个数为1
                if searchBarText.characters.count == 1 {
                    guard let dic = cityDic[searchBarText.uppercased()] else {
                        return
                    }
                    resultArray = dic
                    searchResultVC.resultArray = resultArray
                }else {
                    guard let dic = cityDic[searchBarText.first().uppercased()] else {
                        return
                    }
                    for str in dic {
                        // 去空格
                        let py = String(str.chineseToPinyin().characters.filter({ $0 != " "}))
                        let range = py.range(of: searchBarText)
                        if range != nil {
                            resultArray.append(str)
                        }
                    }
                    // 加入首字母判断 如 cq => 重庆 bj => 北京
                    if resultArray.count == 0 {
                        for str in dic {
                            // 北京 => bei jing
                            let pinyin = str.chineseToPinyin()
                            // 获取空格的index
                            let a = pinyin.characters.index(of: " ")
                            let index = pinyin.index(a!, offsetBy: 2)
                            // offsetBy: 2 截取 bei j
                            // offsetBy: 1 截取 bei+空格
                            // substring(to: index) 不包含 index最后那个下标
                            let py = pinyin.substring(to: index)
                            /// 获取第二个首字母
                            ///
                            ///     py = "bei j"
                            ///     last = "j"
                            ///
                            let last = py.substring(from: py.index(py.endIndex, offsetBy: -1))
                            /// 两个首字母
                            let pyIndex = String(pinyin[pinyin.startIndex]) + last
                            
                            if searchBarText.lowercased() == pyIndex {
                                resultArray.append(str)
                            }
                        }
                    }
                    searchResultVC.resultArray = resultArray
                }
            }
    
        }
    }
    
    
    class CurrentCity:NSObject {
        static let shar = CurrentCity()
        
        fileprivate let path = ""
        var name:String{
            set{
                UserDefaults.standard.set(newValue, forKey: "city")
            }
            get{
                return UserDefaults.standard.string(forKey: "city") ?? "上海"
            }
        }
        override init() {
            super.init()
        }
    }
    
    

    搜索结果界面

    fileprivate let resultCell = "resultCell"
    
    import UIKit
    
    //MARK: - 搜索结果页面
    class ResultSearchView: BaseTableView{
        var resultArray:[String] = []{
            didSet{
                self.reloadData()
            }
        }
        
        var updateCityName:MyCityBlock?
        override init(frame: CGRect, style: UITableViewStyle) {
            super.init(frame: frame, style: style)
            self.alertStr = "暂无搜索结果"
            self.setupUI()
        }
        
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        func setupUI() {
            self.delegate = self
            self.dataSource = self
            self.backgroundColor = Color.mainBg
            self.register(UITableViewCell.self, forCellReuseIdentifier: resultCell)
        }
        
    }
    extension ResultSearchView:UITableViewDataSource,UITableViewDelegate{
        func numberOfSections(in tableView: UITableView) -> Int {
            
            return 1
        }
        
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            
            return resultArray.count
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell =  tableView.dequeueReusableCell(withIdentifier: resultCell, for: indexPath)
            cell.textLabel?.text = resultArray[indexPath.row]
            return cell
        }
        
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            let cell = tableView.cellForRow(at: indexPath)
            print(cell?.textLabel?.text ?? "")
            CurrentCity.shar.name = resultArray[indexPath.row]
            updateCityName!(CurrentCity.shar.name)
        }
    
    }
    
    

    自定义cell

    let normalCell = "normalCell"
    let hotCityCell = "hotCityCell"
    let locaCityCell = "locaCityCell"
    /// section间距
    let sectionMargin: CGFloat = 38
    
    /// 热门城市btn
    let btnMargin: CGFloat = 15
    let btnWidth: CGFloat = (UIScreen.mainWidth - 90) / 3
    let btnHeight: CGFloat = 36
    
    let cellColor = Color.mainBg
    let btnHighlightImage = UIImage.createNVImage(by: UIColor.colorWithHexCode(code: "EAEAEA"))
    
    
    
    import UIKit
    
    //MARK: - 自定义cell
    class LocationCitiesCell: UITableViewCell {
        lazy var locaView:UIView = {
            let locaV = UIView(frame: CGRect(x: btnMargin, y: 15, width: btnWidth, height: btnHeight))
            locaV.layer.masksToBounds = true
            locaV.layer.cornerRadius = 3
            locaV.backgroundColor = UIColor.white
            return locaV
        }()
        lazy var iconView:UIImageView = {
            let iconV = UIImageView(frame: CGRect(x: 5, y: 5, width: 20, height: 20))
            iconV.contentMode = .scaleAspectFit
            iconV.image = UIImage(named:"位置_H")
            return iconV
        }()
        lazy var titleLabel:UILabel = {
            let label = UILabel(frame: CGRect(x: 28, y: 5, width: btnWidth-28, height: btnHeight-10))
            label.textColor = Color.textM
            label.textAlignment = .center
            label.text = "定位城市"
            label.font = Font.large
            return label
        }()
        override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            self.setupUI()
            self.selectionStyle = UITableViewCellSelectionStyle.none
        }
        
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        private func setupUI() {
            
            self.backgroundColor = cellColor
            locaView.addSubview(iconView)
            locaView.addSubview(titleLabel)
            self.addSubview(locaView)
            
        }
        
    }
    //当前:
    class CurrentCityView: UIView {
        
        lazy var currentCityLabel:UILabel = {
            var label = UILabel(frame: CGRect(x: 15, y: 0, width: self.frame.width-15, height: self.frame.height))
            label.textColor = Color.textH
            label.font = Font.largePP
            label.backgroundColor = UIColor.white
            label.text = String(format: "当前:  %@", CurrentCity.shar.name)
            return label
        }()
        override init(frame: CGRect) {
            super.init(frame: frame)
            self.backgroundColor = UIColor.white
            self.setupUI()
        }
        func setupUI(){
            self.addSubview(currentCityLabel)
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }
    
    class HotCitiesCell: UITableViewCell {
        /// 懒加载 热门城市
        var cityClicked:MyCityBlock?
        lazy var hotCities: [String] = {
            let path = Bundle.main.path(forResource: "hotCities.plist", ofType: nil)
            let array = NSArray(contentsOfFile: path!) as? [String]
            return array ?? []
        }()
        
        /// 使用tableView.dequeueReusableCell会自动调用这个方法
        override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            self.setupUI()
            self.selectionStyle = UITableViewCellSelectionStyle.none
        }
        
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        private func setupUI() {
            
            self.backgroundColor = cellColor
            // 动态创建城市btn
            for i in 0..<hotCities.count {
                // 列
                let column = i % 3
                // 行
                let row = i / 3
                
                let btn = UIButton(frame: CGRect(x: btnMargin + CGFloat(column) * (btnWidth + btnMargin), y: 15 + CGFloat(row) * (btnHeight + btnMargin), width: btnWidth, height: btnHeight))
                btn.setTitle(hotCities[i], for: .normal)
                btn.setTitleColor(Color.textH, for: .normal)
                btn.titleLabel?.font = Font.large
                btn.backgroundColor = UIColor.white
                btn.layer.masksToBounds = true
                btn.layer.cornerRadius = 3
                btn.setBackgroundImage(btnHighlightImage, for: .highlighted)
                btn .addTarget(self, action: #selector(btnClick(btn:)), for: .touchUpInside)
                self.addSubview(btn)
                
            }
        }
        
        @objc private func btnClick(btn: UIButton) {
            //        print(btn.titleLabel!.text!)
            CurrentCity.shar.name = btn.titleLabel!.text!
            cityClicked!(CurrentCity.shar.name)
        }
        
    }
    
    

    调用方法:

     //FIXME: 选择地点
        func didLocationBtn(){
            self.locaBtn.setImage(#imageLiteral(resourceName: "位置_H"), for: .normal)
    
            let cityVC = CitySelectorViewController()
            cityVC.updateCityName = {(cityName:String) in
                self.locaCity.text = cityName
            }
            let locationNV = UINavigationController(rootViewController: cityVC)
            present(locationNV, animated: true) { 
                self.locaBtn.setImage(#imageLiteral(resourceName: "location"), for: .normal)
            }
        }
    
    

    城市列表:

    城市列表.png

    效果图


    button.png 搜索1.png 搜索2.png

    相关文章

      网友评论

          本文标题:swift-城市搜索选择器

          本文链接:https://www.haomeiwen.com/subject/vlhwsxtx.html