iOS开发 - 国内城市选择控制器②

1.初始化或者搜索条为空时,表格显示所有数据

2.支持屏幕右边缘拼音首字母快速检索

2.搜索条不为空时,实时过滤显示

3.支持大小写拼音及中文搜索

支持闭包回传,所有东西都塞到一坨了,可以直接当个选择控制器使用..
代码有点混乱,看来也没时间继续优化节奏了,哥困了...

Simulator Screen Shot 2016年6月24日 上午2.44.05

CityViewController.swift

import UIKit

class CityViewController: UIViewController {
    
    //闭包回传
    var selectCityBack: ((cityName: String) -> Void)?
    
    //MARK: - Property 属性
    var tableView:UITableView!
    let screen_W = UIScreen.mainScreen().bounds.size.width
    let screen_H = UIScreen.mainScreen().bounds.size.height
    
    let cityModel = CityDataModel()
    var cityModel_Key = [String]()
    
    //搜索状态
    enum SearchT {
        case on
        case off
    }
    var searchBar: UISearchBar?
    var searchRetrunData = [String]()
    var searchMode: SearchT = .off {
        didSet {
            self.changeTableViewData(searchMode)
        }
    }
    
    //MARK: - LifeCycle 生命周期
    override func viewDidLoad() {
        super.viewDidLoad()

        setupNavigationBar()
        setupCustomSearchView()
        setupTableView()
        
        searchMode = .off
    }
    
    //MARK: - ViewSetup 视图设置
    func setupNavigationBar()  {
        let navBarView = UIView(frame: CGRect(x: 0, y: 0, width: screen_W, height: 64))
        navBarView.backgroundColor = UIColor.whiteColor()
        self.view.addSubview(navBarView)
        
        let closeBtn = UIButton(type: .Custom)
        closeBtn.frame = CGRect(x: 20, y: 30, width: 40, height: 20)
        closeBtn.setTitle("关闭", forState: .Normal)
        closeBtn.setTitleColor(UIColor.orangeColor(), forState: .Normal)
        closeBtn.addTarget(self, action: #selector(CityViewController.closeButton), forControlEvents: .TouchUpInside)
        navBarView.addSubview(closeBtn)
        
        let titleLabel = UILabel(frame: CGRect(x: screen_W/2 - 50, y: 30, width: 100, height: 25))
        titleLabel.textColor = UIColor.blackColor()
        titleLabel.textAlignment = .Center
        titleLabel.font = UIFont.systemFontOfSize(15)
        titleLabel.text = "选择城市"
        navBarView.addSubview(titleLabel)
    }
    
    func setupCustomSearchView()  {
        searchBar = UISearchBar(frame: CGRect(x: 0, y: 64, width: screen_W, height: 40))
        searchBar?.placeholder = "请输入要搜索的城市"
        searchBar?.delegate = self
        self.view.addSubview(searchBar!)
    }
    
    func setupTableView() {
        tableView = UITableView(frame: CGRect(x: 0, y: 64 + 40 , width: screen_W, height: screen_H - 64), style: .Plain)
        self.view.addSubview(tableView)
        tableView.delegate = self
        tableView.dataSource = self
        tableView.sectionIndexColor = UIColor.orangeColor()
        //创建一个重用的单元格
        tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
    }

    //MARK: - private 内部方法
    func changeTableViewData(searchMode: SearchT) {
        switch searchMode {
        case .off:
            cityModel_Key = self.cityModel.newdictK
        case .on:
            cityModel_Key = self.searchRetrunData
        }
        tableView.reloadData()
    }
    
   func closeButton()  {
        self.dismissViewControllerAnimated(true, completion: nil)
    }
}
//MARK: - UISearchBar 代理
extension CityViewController: UISearchBarDelegate {
    func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
        
        //搜索栏为空时候,显示原来数据
        guard !searchText.isEmpty else { return self.searchMode = .off }
        
         //这里哥懒得做判断了,字母优先了
         let currsearchText = searchText.lowercaseString //转成小写字母
         var filterCity = cityModel.dictKey.filter{ $0.hasPrefix(currsearchText) }
            .flatMap{ CityDataModel.cityDic[$0] } //filter过滤  flatMap转换并去除nil
        
         if filterCity.isEmpty { //字母搜索结果为空时,使用文字搜索
            filterCity = cityModel.dictVaule.filter{ $0.hasPrefix(currsearchText) }
            }
         self.searchRetrunData = filterCity
         self.searchMode = .on
         print(searchRetrunData)
    }
    
    //按下右下角键
    func searchBarSearchButtonClicked(searchBar: UISearchBar) {
        searchBar.resignFirstResponder()
    }
    //滑动收起键盘
    func scrollViewDidScroll(scrollView: UIScrollView) {
        searchBar?.resignFirstResponder()
    }
}

//MARK: - UITableView 代理
extension CityViewController: UITableViewDelegate, UITableViewDataSource {
    
    // UITableViewDataSource
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        guard case .off = searchMode else { return 1 }
        return cityModel_Key.count
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        guard case .off = searchMode else { return cityModel_Key.count }
        
        let cityhead = cityModel_Key[section]
        return (cityModel.newdictKY[cityhead]?.count)!
    }
    
    func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        guard case .off = searchMode else { return nil }
        return cityModel_Key[section]
    }
    
    func sectionIndexTitlesForTableView(tableView: UITableView) -> [String]? {
        guard case .off = searchMode else { return nil }
        return cityModel_Key
    }
    
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return 49
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell
        
        if searchMode == .on { //搜索状态 - 开
            cell.textLabel?.text = cityModel_Key[indexPath.row]
        } else {
            let cityhead = cityModel_Key[indexPath.section]
            let cityPinyin = cityModel.newdictKY[cityhead]![indexPath.row]
            cell.textLabel?.text = "\(CityDataModel.cityDic[cityPinyin]!)"
        }
        
        return cell
    }
    
    // UITableViewDelegate
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        switch searchMode {
        case .off:
            let cityhead = cityModel_Key[indexPath.section]
            let cityPinyin = cityModel.newdictKY[cityhead]![indexPath.row]
            let currCtiy = CityDataModel.cityDic[cityPinyin]
            self.selectCityBack?(cityName: currCtiy!)
        case .on:
            let currCtiy = cityModel_Key[indexPath.row]
            self.selectCityBack?(cityName: currCtiy) //回传数据
        }
        self.dismissViewControllerAnimated(true, completion: nil)
    }
}

 // MARK: - 城市数据
 struct CityDataModel {
   static let cityDic = ["wuhai": "乌海", "chaoyang": "朝阳", "lanzhou": "兰州", "nanjing": "南京", "wuhan": "武汉", "hegang": "鹤岗", "yongzhou": "永州", "loudi": "娄底", "lianyungang": "连云港", "zhangzhou": "漳州", "zhumadian": "驻马店", "wuxi": "无锡", "chizhou": "池州", "shanghai": "上海", "shaoyang": "邵阳", "qiannan": "黔南", "zhongwei": "中卫", "tacheng": "塔城", "tonghua": "通化", "benxi": "本溪", "jingmen": "荆门", "cixi": "慈溪", "changsha": "长沙", "wanzhou": "万州", "jiyuan": "济源", "yanji": "延吉", "deyang": "德阳", "tangshan": "唐山", "changzhou": "常州", "meizhou": "梅州", "shijiazhuang": "石家庄", "yiwu": "义乌", "changchun": "长春", "linyi": "临沂", "shangyu": "上虞", "heihe": "黑河", "shannan": "山南", "fuxin": "阜新", "puyang": "濮阳", "changde": "常德", "changdu": "昌都", "ruian": "瑞安", "lijiang": "丽江", "wuzhou": "梧州", "tongliao": "通辽", "huaihua": "怀化", "ningbo": "宁波", "puer": "普洱", "kelamayi": "克拉玛依", "hanzhong": "汉中", "wuwei": "武威", "binzhou": "滨州", "guilin": "桂林", "nantong": "南通", "yongkang": "永康", "xiantao": "仙桃", "kezhou": "克州", "maoming": "茂名", "shuangyashan": "双鸭山", "changle": "长乐", "liyang": "溧阳", "suining": "遂宁", "huanggang": "黄冈", "huidong": "惠东", "honghe": "红河", "wulumuqi": "乌鲁木齐", "yangjiang": "阳江", "hainanzhou": "海南州", "hangzhou": "杭州", "jiangning": "江宁", "xuchang": "许昌", "tanggu": "塘沽", "zhanjiang": "湛江", "xuancheng": "宣城", "danyang": "丹阳", "chengde": "承德", "longyan": "龙岩", "sanxia": "三峡", "qiqihaer": "齐齐哈尔", "beijing": "北京", "huaian": "淮安", "jixi": "鸡西", "guiyang": "贵阳", "zhenjiang": "镇江", "nanchang": "南昌", "yaan": "雅安", "panzhihua": "攀枝花", "changxing": "长兴", "langfang": "廊坊", "guyuan": "固原", "mudanjiang": "牡丹江", "fuyang": "阜阳", "nanning": "南宁", "yili": "伊犁", "baotou": "包头", "dongying": "东营", "cangzhou": "沧州", "shantou": "汕头", "zhangjiajie": "张家界", "taiyuan": "太原", "jincheng": "晋城", "ali": "阿里", "qiandongnan": "黔东南", "yushu": "玉树", "dongguan": "东莞", "sanya": "三亚", "kunming": "昆明", "zhaoqing": "肇庆", "guangan": "广安", "daxinganling": "大兴安岭", "dali": "大理", "wuzhong": "吴忠", "xiaoshan": "萧山", "huizhou": "惠州", "jieyang": "揭阳", "luoyang": "洛阳", "baishan": "白山", "handan": "邯郸", "xingtai": "邢台", "jinan": "济南", "dandong": "丹东", "songyuan": "松原", "fuzhoufz": "抚州", "heze": "菏泽", "sanmenxia": "三门峡", "panjin": "盘锦", "yanan": "延安", "qingyuan": "清远", "aletai": "阿勒泰", "liaoyang": "辽阳", "shuozhou": "朔州", "qianxinan": "黔西南", "huadu": "花都", "yingkou": "营口", "haidong": "海东", "jiujiang": "九江", "suihua": "绥化", "kaifeng": "开封", "liuzhou": "柳州", "chuzhou": "滁州", "ankang": "安康", "shenzhen": "深圳", "yanbian": "延边", "zhangjiakou": "张家口", "bazhong": "巴中", "yixing": "宜兴", "mianyang": "绵阳", "hechi": "河池", "aba": "阿坝", "jian": "吉安", "yancheng": "盐城", "quanzhou": "泉州", "bengbu": "蚌埠", "chongzuo": "崇左", "dazhou": "达州", "baise": "百色", "panyu": "番禺", "luzhou": "泸州", "weinan": "渭南", "zigong": "自贡", "wulanchabu": "乌兰察布", "yantai": "烟台", "fushun": "抚顺", "haixi": "海西", "xianggang": "香港", "huaibei": "淮北", "huiyang": "惠阳", "guangzhou": "广州", "foshan": "佛山", "alashanmeng": "阿拉善", "qianan": "迁安", "shanwei": "汕尾", "yueyang": "岳阳", "zhongshan": "中山", "shizuishan": "石嘴山", "xiamen": "厦门", "boertala": "博尔塔拉", "xinzhou": "忻州", "hebi": "鹤壁", "tongchuan": "铜川", "zhoushan": "舟山", "emeishan": "峨眉山", "zhuozhou": "涿州", "lvliang": "吕梁", "qujing": "曲靖", "liaocheng": "聊城", "bijiediqu": "毕节", "huangshan": "黄山", "fuqing": "福清", "yangshuo": "阳朔", "suzhousz": "宿州", "tongling": "铜陵", "dehong": "德宏", "chifeng": "赤峰", "xiangtan": "湘潭", "weihai": "威海", "zhaotong": "昭通", "jinjiang": "晋江", "ningde": "宁德", "changzhi": "长治", "qinhuangdao": "秦皇岛", "luohe": "漯河", "haibei": "海北", "jiangmen": "江门", "bayannaoer": "巴彦淖尔", "qionghai": "琼海", "pingxiang": "萍乡", "jinhua": "金华", "lishui": "丽水", "chengdu": "成都", "anqing": "安庆", "xining": "西宁", "putian": "莆田", "linfen": "临汾", "huludao": "葫芦岛", "shenyang": "沈阳", "tongrendiqu": "铜仁", "linxia": "临夏", "zaozhuang": "枣庄", "qingdao": "青岛", "ezhou": "鄂州", "baoshan": "保山", "fuling": "涪陵", "xinyang": "信阳", "qitaihe": "七台河", "shihezi": "石河子", "dunhunag": "敦煌", "liuan": "六安", "linhai": "临海", "shaoxing": "绍兴", "daqing": "大庆", "changji": "昌吉", "anyang": "安阳", "deqing": "德清", "haerbin": "哈尔滨", "nanping": "南平", "shangqiu": "商丘", "jinchang": "金昌", "haining": "海宁", "zhangye": "张掖", "chenzhou": "郴州", "dongyang": "东阳", "chaozhou": "潮州", "zhangjiagang": "张家港", "xinyu": "新余", "huangnan": "黄南", "linzhi": "林芝", "longnan": "陇南", "hulunbeier": "呼伦贝尔", "naqu": "那曲", "jingzhou": "荆州", "yuyao": "余姚", "hezhou": "贺州", "shunde": "顺德", "laibin": "来宾", "meishan": "眉山", "baoji": "宝鸡", "leshan": "乐山", "suizhou": "随州", "tianjin": "天津", "yinchuan": "银川", "tieling": "铁岭", "laiwu": "莱芜", "chuxiong": "楚雄", "diqing": "迪庆", "haikou": "海口", "pingliang": "平凉", "siping": "四平", "ganzi": "甘孜", "hengyang": "衡阳", "xinganmeng": "兴安", "qinzhou": "钦州", "dingxi": "定西", "dezhou": "德州", "jiamusi": "佳木斯", "yulin": "玉林", "wenshan": "文山", "gannan": "甘南", "jiayuguan": "嘉峪关", "xiaogan": "孝感", "zhoukou": "周口", "yangzhou": "扬州", "wenzhou": "温州", "heyuan": "河源", "fangchenggang": "防城港", "hengshui": "衡水", "taizhoutz": "台州", "jiaozuo": "焦作", "beihai": "北海", "fuzhou": "福州", "lincang": "临沧", "aomen": "澳门", "shaoguan": "韶关", "yibin": "宜宾", "jinzhong": "晋中", "yingtan": "鹰潭", "nanyang": "南阳", "liupanshui": "六盘水", "qingyang": "庆阳", "jinzhou": "锦州", "liangshan": "凉山", "zhuzhou": "株洲", "datong": "大同", "leqing": "乐清", "anshan": "鞍山", "wenling": "温岭", "chaohu": "巢湖", "zunyi": "遵义", "shishi": "石狮", "xiangyang": "襄阳", "nujiang": "怒江", "baicheng": "白城", "wuan": "武安", "fuyangfy": "富阳", "wuhu": "芜湖", "hetian": "和田", "kunshan": "昆山", "yiyang": "益阳", "zhangqiu": "章丘", "guoluo": "果洛", "huangdao": "黄岛", "shiyan": "十堰", "hami": "哈密", "yichunyc": "伊春", "zhuhai": "珠海", "tulufan": "吐鲁番", "zibo": "淄博", "jiaxing": "嘉兴", "nanchong": "南充", "yichang": "宜昌", "yanzhou": "兖州", "taizhou": "泰州", "yichun": "宜春", "dalian": "大连", "xilinguolemeng": "锡林郭勒", "weifang": "潍坊", "guangyuan": "广元", "lasa": "拉萨", "chongqing": "重庆", "neijiang": "内江", "changshu": "常熟", "suzhou": "苏州", "eerduosi": "鄂尔多斯", "jining": "济宁", "yulinyl": "榆林", "maanshan": "马鞍山", "bozhou": "亳州", "rizhao": "日照", "yunfu": "云浮", "huainan": "淮南", "jilin": "吉林", "tongxiang": "桐乡", "shangrao": "上饶", "huangshi": "黄石", "ganzhou": "赣州", "quzhou": "衢州", "shangluo": "商洛", "kashi": "喀什", "wuyishan": "武夷山", "pingdingshan": "平顶山", "jingdezhen": "景德镇", "anshun": "安顺", "xian": "西安", "ziyang": "资阳", "sanming": "三明", "guigang": "贵港", "taicang": "太仓", "xianning": "咸宁", "huhehaote": "呼和浩特", "xishuangbanna": "西双版纳", "taian": "泰安", "rikaze": "日喀则", "xiangxi": "湘西", "baiyin": "白银", "jintan": "金坛", "baoding": "保定", "hefei": "合肥", "bazhou": "巴州", "jiangyin": "江阴", "xianyang": "咸阳", "jiuquan": "酒泉", "enshi": "恩施", "yuxi": "玉溪", "taibei": "台北", "xinxiang": "新乡", "xuzhou": "徐州", "conghua": "从化", "akesu": "阿克苏", "yangquan": "阳泉", "suqian": "宿迁", "zhengzhou": "郑州", "liaoyuan": "辽源", "huzhou": "湖州", "zhuji": "诸暨", "tianshui": "天水", "yuncheng": "运城"]
    
    //建立合适的数据模型 [section - [key: vaule]]
    var newdictKY = [String:[String]]()
    var newdictK:[String] { //排序后的 - 键
        return Array(newdictKY.keys).sort(<)
    }
    
    // 字典的键
    var dictKey:[String] {
        return Array(CityDataModel.cityDic.keys)
    }
    
    // 字典的值
    var dictVaule:[String] {
        return Array(CityDataModel.cityDic.values)
    }
    
    private var currStrHead = "a"
    private var currStrArr = [String]()
    init() {
        //建立排序规则
        let sortdeDictKey = dictKey.sort(<) //字典的键 - 升序
        for i in 0..<sortdeDictKey.count {
            let currStr = sortdeDictKey[i]
            let start = currStr.startIndex
            let currStartStr = String(currStr[start])
            if currStrHead == currStartStr  {
                currStrArr.append(currStr)
            } else {
                let k = currStrHead
                let v = currStrArr
                newdictKY[k] = v
                currStrArr.removeAll()
                currStrHead = currStartStr
            }
        }
    }
}

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

推荐阅读更多精彩内容

  • 九月黎明 我落在梦中的海岛 鞋上还落着家乡的尘土 穿过大海和天空 我背着彩虹的颜色 流浪到远方城市 我没有忘记带伞...
    卿珞阅读 363评论 0 0
  • Inmon 《构建数据仓库》《DW 2.0》Kimball 《数据仓库生命周期工具箱》Inmon偏向于从底层的数据...
    重剑无锋_Augustine阅读 203评论 0 0
  • 每天尽量按照自己的节奏油盐酱醋,工作赚钱,捧着热茶观落日。 这不是所谓的平淡,至少对于我,这是此生追求的幸福,以及...
    嗷大喵爱石榴阅读 558评论 0 0
  • 1.学会提问第七章看完 2.一个小时的培训认识到自己思路的问题以及梳理情绪的方法,搞笑段子,相声,吃东西。 3.拆...
    kidII阅读 120评论 0 0