Swift 地址选择器

import UIKit
import HandyJSON

@objc public protocol KLCityPickerViewDelegate {
     @objc optional func addressPickerViewArea(province: String?, city: String?, area: String?)
//     @objc optional func addressPickerViewCity(province: String?, city: String?)
//     @objc optional func addressPickerViewProvince(province: String?)
}

enum KLAddressPickerType: Int {
    // 只显示省
    case province = 1
    // 显示省份和城市
    case city = 2
    // 显示省份和城市和区域
    case area = 3
}

// 屏幕的宽度
 public var klScreen_width: CGFloat {
    return UIScreen.main.bounds.size.width
 }

// 屏幕的高度
public var klScreen_height: CGFloat {
    return UIScreen.main.bounds.size.height
}

// 设置pickerView的高度
public var klPickerViewHeight: CGFloat {
   return 216
}

// 高度比列
public func kl_scaleHeight(h: CGFloat)->CGFloat {
    return klScreen_height/667*h
}

// 宽度比
public func kl_scaleWidth(w: CGFloat)->CGFloat {
    return klScreen_width/375*w
}

public class KLCityPickerView: UIView {
    
    public weak var dataDelegate: KLCityPickerViewDelegate?
    //MARK: -外部参数
    /// pickerView的字体大小
    public var pickerLabelFont: UIFont?{
        willSet{
            pickerView.reloadAllComponents()
        }
    }
    /// pickerView的字体颜色
    public var pickerLabelTextCoclor: UIColor?{
        willSet{
            pickerView.reloadAllComponents()
        }
    }
    
    // 设置取消、确定按钮的字体大小
    public var titleToolBarFont: UIFont?{
        willSet{
            sureButton.titleLabel?.font = newValue
            cancleButton.titleLabel?.font = newValue
        }
    }
    // 设置取消按钮的颜色
    public var cancleButtonCoclor: UIColor?{
        willSet{
            cancleButton.setTitleColor(newValue, for: .normal)
        }
    }
    // 设置确定按钮的颜色
    public var sureButtonCoclor: UIColor?{
        willSet{
            sureButton.setTitleColor(newValue, for: .normal)
        }
    }
    //设置titleToolBar的背景颜色
    public var titleToolBarBackgroundColor: UIColor?{
        willSet{
            titleToolBar.backgroundColor = newValue
        }
    }
    
    //设置pickView的背景颜色
    public var pickerViewBackgroundColor: UIColor?{
        willSet{
            pickerView.backgroundColor = newValue
        }
    }
    //MARK: -内部参数
    // 接收参数的数据
//     var dataSource = [Dictionary>>]() // Array()
    var dataSource = [ProvinceModel]()
    // 一共显示多少列
     var columnCount: Int?
    // 省
     var provinceArray = [String]()
    // 市
     var cityArray = [String]()
    // 区
     var areaArray = [String]()
    // 默认选中省
     var selectedProvince: String?
    // 默认选中市
     var selectedCity: String?
    // 默认选中区
     var selectedArea: String?
    // 记录省份选中的位置
     var selectedProvinceIndex: Int = 0
    
    //设置选中的类型
     var showType: KLAddressPickerType = .area {
        willSet{
            columnCount = newValue.rawValue
            pickerView.reloadAllComponents()
        }
    }
    // 回调函数
    // 区域block
     var selectedAreaBlock:((_ province:String, _ city:String, _ area:String)->())?
    // 省份block
     var selectedProvinceBlock:((_ province:String)->())?
    // 城市block
     var selectedCityBlock:((_ province:String, _ city:String)->())?
    
    //MARK: -懒加载
    /// 创建城市选择器
     lazy var pickerView: UIPickerView = {
       let pickerView = UIPickerView(frame: CGRect(x: 0, y:
            kl_scaleHeight(h: 55), width:klScreen_width , height: kl_scaleHeight(h: 270) - kl_scaleHeight(h: 55)))
//        let pickerView = UIPickerView()
        pickerView.delegate = self
        pickerView.dataSource = self
        pickerView.backgroundColor = UIColor.white
        return pickerView
    }()
    
    /// 创建容器
     lazy var containView: UIView = {
        let containView = UIView(frame: CGRect(x: 0, y: klScreen_height, width:klScreen_width , height: kl_scaleHeight(h: 270)))
        containView.backgroundColor = UIColor.gray
        return containView
    }()
    
    /// 创建容器中的titleToolBar
     lazy var titleToolBar: UIView = {
        let titleToolBar = UIView(frame: CGRect(x: 0, y: 0, width: klScreen_width, height: kl_scaleHeight(h: 55)))
        titleToolBar.backgroundColor = UIColor(hexString: "#f6f6f6")
        return titleToolBar
    }()
    
    /// 创建确定按钮
     lazy var sureButton: UIButton = {
        let sureButton = UIButton(frame: CGRect(x: klScreen_width - kl_scaleWidth(w: 65), y: 0, width: kl_scaleWidth(w: 65), height: kl_scaleHeight(h: 55)))
//        let sureButton = UIButton()
        sureButton.setTitle("确定", for: .normal)
        sureButton.addTarget(self, action: #selector(addressButtonOnclik), for: .touchUpInside)
        sureButton.setTitleColor(UIColor(hexString: "#ff0000"), for: .normal)
        sureButton.tag = 1
        return sureButton
    }()
    
    /// 创建取消按钮
     lazy var cancleButton: UIButton = {
        let cancleButton = UIButton(frame: CGRect(x: 0, y: 0, width: kl_scaleWidth(w: 65), height: kl_scaleHeight(h: 55)))
//        let cancleButton = UIButton()
        cancleButton.setTitle("取消", for: .normal)
        cancleButton.addTarget(self, action: #selector(addressButtonOnclik), for: .touchUpInside)
        cancleButton.setTitleColor(UIColor(hexString: "#666666"), for: .normal)
        return cancleButton
    }()
    
    //MARK: - 系统方法
    /// 系统初始化
    override init(frame: CGRect) {
        super.init(frame: frame)
        // 设置界面
        kl_setView()
        
        //设置数据
//        kl_layoutSubviws()
    }
    
    required public init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    //MARK: -界面初始化
    /// 初始化界面
     func kl_setView(){
        self.frame = CGRect(x: 0, y: 0, width: klScreen_width, height: klScreen_height)
        // 添加容器
        addSubview(containView)
        // 添加titleToolBar
        containView.addSubview(titleToolBar)
        // 添加pickerView
        containView.addSubview(pickerView)
        // 添加确定按钮
        titleToolBar.addSubview(sureButton)
        // 添加取消按钮
        titleToolBar.addSubview(cancleButton)
    }
    

    //MARK: -获取数据
     func kl_getData(){
        
        let path = Bundle.main.path(forResource: "location", ofType: "json")
        let url = URL(fileURLWithPath: path!)
        do {
            let data = try Data(contentsOf: url)
            let jsonData:Any = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers)
            let jsonDic = jsonData as! Dictionary
            let model = JSONDeserializer.deserializeFrom(dict: jsonDic)
            self.dataSource = model?.children ?? []
            
            //获取省份
            var tempProvinceArray = [String]()
            for tempArray in self.dataSource {
                tempProvinceArray.append(tempArray.value ?? "")
            }
            // 设置省份
            provinceArray = tempProvinceArray
            
            
            // 设置市
            cityArray = getCityNameFromProvinceIndex(provinceIndex: 0)
            
            // 设置区
            self.areaArray = getAreanamesFromProvinceIndex(provinceIndex: 0, cityIndex: 0)
            
            // 如果没有传入默认值默认选中第一个
            if selectedProvince == nil {
                selectedProvince = provinceArray.first
            }
            
            if selectedCity == nil {
                selectedCity = cityArray.first
            }
            
            if selectedArea == nil {
                selectedArea = areaArray.first
            }
            
            
            //根据省市县赋值
            var currentProvinceIndex: Int = 0
            var currentCityIndex: Int = 0
            var currentAreaIndex: Int = 0
            
            for i in (0 ... provinceArray.count - 1) {
                let province = provinceArray[i]
                if province == selectedProvince {
                    selectedProvinceIndex = i
                    currentProvinceIndex = i
                    //获取当前城市
                    cityArray = getCityNameFromProvinceIndex(provinceIndex: currentProvinceIndex)
                    for j in (0 ... cityArray.count - 1){
                        let city = cityArray[j]
                        
                        if city == selectedCity {
                            currentCityIndex = j;
                            areaArray = getAreanamesFromProvinceIndex(provinceIndex: currentProvinceIndex, cityIndex: currentCityIndex)
                            for k in (0 ... areaArray.count - 1){
                                let area = areaArray[k]
                                if area == selectedArea {
                                    currentAreaIndex = k
                                }
                            }
                        }
                    }
                }
            }
            
            //滚动到固定的行
            if showType == .province {
                pickerView.selectRow(currentProvinceIndex, inComponent: 0, animated: true)
            } else if showType == .city {
                pickerView.selectRow(currentProvinceIndex, inComponent: 0, animated: true)
                pickerView.selectRow(currentCityIndex, inComponent: 1, animated: true)
            } else if showType == .area {
                pickerView.selectRow(currentProvinceIndex, inComponent: 0, animated: true)
                pickerView.selectRow(currentCityIndex, inComponent: 1, animated: true)
                pickerView.selectRow(currentAreaIndex, inComponent: 2, animated: true)
            }
            
        } catch let error as Error? {
            print("读取本地数据出现错误!",error.debugDescription)
        }
    
       // self.pickerView.reloadAllComponents()
    }
    //MARK: -自定义方法
    @objc func addressButtonOnclik(currentButton: UIButton){
        //隐藏界面
        hideView()
        if currentButton.tag == 1{
            if (selectedProvinceBlock != nil) {
                selectedProvinceBlock?(selectedProvince!)
            }
            if (selectedCityBlock != nil) {
                selectedCityBlock?(selectedProvince!,selectedCity!)
            }
            if (selectedAreaBlock != nil){
                selectedAreaBlock?(selectedProvince!,selectedCity!,selectedArea!)
            }
            if dataDelegate != nil {

                dataDelegate?.addressPickerViewArea?(province: selectedProvince, city: selectedCity, area: selectedArea)

            }
        }
    }
    /// 获取市
    /// - Parameter provinceIndex: 省份的id
    /// - Returns: 返回某个省份对应的市
     func getCityNameFromProvinceIndex(provinceIndex: Int)->([String]){
        if let tempCityArray = self.dataSource[provinceIndex].children {
            var tempArray = [String]()
            for cityDic in tempCityArray {
                tempArray.append(cityDic.value ?? "")
            }
    
            return tempArray
        }else{
            return []
        }

        
    }
    
    ///  获取区
    /// - Parameters:
    ///   - provinceIndex: 省份的id
    ///   - cityIndex: 市的id
    /// - Returns: 返回某个省份对应的市对应的区
     func getAreanamesFromProvinceIndex(provinceIndex: Int, cityIndex: Int)->[String]{
        if let tempCityArray = self.dataSource[provinceIndex].children,let tempAreaArr = tempCityArray[cityIndex].children  {
            var currentAreaArra = [String]()
            for areaDic in tempAreaArr {
                currentAreaArra.append(areaDic.value ?? "")
            }
            return currentAreaArra
        }else{
            return []
        }
    }
    
    /// 显示view
     func showView() {
        UIApplication.shared.keyWindow?.addSubview(self)
        backgroundColor = UIColor.clear
        UIView.animate(withDuration: 0.3) {
            self.backgroundColor = UIColor(hexString: "#000000",alpha: 0.3)
            self.containView.kl_bottom = klScreen_height
        }
    }

    /// 隐藏View
     func hideView() {
        UIView.animate(withDuration: 0.3, animations: {
            self.backgroundColor = UIColor.clear
            self.containView.kl_y =  klScreen_height
        }) { (finish) in
            self.removeFromSuperview()
        }
    }
    
    //MARK: - 初始化
    /// 显示省份
    /// - Parameter addressBlock: 回调返回省份
    public func provincePickerViewWithProvinceBlock(addressBlock:((String)->())?){
        addressPickerViewWithProvince(province: nil, city: nil, area: nil, provinceBlock: addressBlock, cityBlock: nil, areaBlock: nil, showType: .province)
    }
    
    /// 显示省份
    /// - Parameters:
    ///   - province: 传入选中的省份
    ///   - addressBlock: 回调返回省份
    public func provincePickerViewWithProvince(province: String?, addressBlock:((String)->())?){
        addressPickerViewWithProvince(province: province, city: nil, area: nil, provinceBlock: addressBlock, cityBlock: nil, areaBlock: nil, showType: .province)
    }
    
    /// 显示省份和城市
    ///
    /// - Parameter addressBlock: 返回省份和城市
    public func cityPickerViewWithCityBlock(addressBlock:((String, String)->())?) {
        addressPickerViewWithProvince(province: nil, city: nil, area: nil, provinceBlock: nil, cityBlock: addressBlock, areaBlock: nil, showType: .city)
    }
    
    /// 显示省份城市
    ///
    /// - Parameters:
    ///   - procvince: 传入选中的省份
    ///   - city: 传入选中的城市
    ///   - addressBlock: 返回选中的省份和城市
    public func cityPickerViewWithProvince(procvince: String?, city: String?, addressBlock:((String, String)->())?){
        addressPickerViewWithProvince(province: procvince, city: city, area: nil, provinceBlock: nil, cityBlock: addressBlock, areaBlock: nil, showType: .city)
    }
    
    /// 显示省份市和区域
    /// - Parameter province: 回调省份市和区域
    public func areaPickerViewWithareaBlock(addressBlock:((String, String, String)->())?){
        addressPickerViewWithProvince(province: nil, city: nil, area: nil, provinceBlock: nil, cityBlock: nil, areaBlock: addressBlock, showType: .area)
    }
    
    /// 显示省份城市和区域
    ///
    /// - Parameters:
    ///   - province: 选中的省份
    ///   - city: 选中的城市
    ///   - area: 选中的区域
    ///   - addressBlock: 回调省市区域
    func areaPickerViewWithProvince(province: String?, city: String?, area: String?, addressBlock:((String, String, String)->())?){
        addressPickerViewWithProvince(province: province, city: city, area: area, provinceBlock: nil, cityBlock: nil, areaBlock: addressBlock, showType: .area)
    }
    
    //MARK: - 基本方法
     func addressPickerViewWithProvince(province: String?, city: String?, area: String?, provinceBlock:((String)->())?, cityBlock:((String, String)->())?, areaBlock:((String, String, String)->())?, showType: KLAddressPickerType){
        selectedProvince = province
        selectedCity = city
        selectedArea = area
        selectedProvinceBlock = provinceBlock
        selectedCityBlock = cityBlock
        selectedAreaBlock = areaBlock
        self.showType = showType
        // 设置数据
        kl_getData()
        showView()
    }
}

//MARK: -UIPickerViewDataSource, UIPickerViewDelegate 方法
extension KLCityPickerView: UIPickerViewDataSource, UIPickerViewDelegate {
    
    public func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return self.columnCount ?? 1
    }
    
    public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        if component == 0 {
            return self.provinceArray.count
        } else if component == 1 {
            return self.cityArray.count
        }else if component == 2 {
            return self.areaArray.count
        }
        return 0
    }
    
    public func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
        var label = view as? UILabel
        if label == nil {
            label = UILabel(frame: CGRect(x: 0, y: 0, width: kl_width/3, height: 30))
            label?.adjustsFontSizeToFitWidth = true
            label?.textAlignment = .center
            label?.textColor = pickerLabelTextCoclor == nil ? UIColor(hexString: "#666666"): pickerLabelTextCoclor
            label?.font = pickerLabelFont == nil ? UIFont.systemFont(ofSize: 17) : pickerLabelFont
        }
        
        if component == 0 {
            label?.text =  self.provinceArray[row]
        } else if component == 1 {
            label?.text =  self.cityArray[row]
        } else if component == 2 {
            label?.text =  self.areaArray[row]
        }
        return label!
    }
    
    public func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        if component == 0 { // 选择省份
            selectedProvinceIndex = row
            switch showType {
            case .province:
                selectedProvince = provinceArray[row]
                selectedCity = ""
                selectedArea = ""
            case .city:
                cityArray = getCityNameFromProvinceIndex(provinceIndex: row)
                pickerView.selectRow(0, inComponent: 1, animated: true)
                pickerView.reloadComponent(1)
                selectedProvince = provinceArray[row]
                selectedCity = cityArray[0]
                selectedArea = ""
            case .area:
                cityArray = getCityNameFromProvinceIndex(provinceIndex: row)
                areaArray = getAreanamesFromProvinceIndex(provinceIndex: row, cityIndex: 0)
                pickerView.reloadComponent(1)
                selectedProvince = provinceArray[row]
                pickerView.selectRow(0, inComponent: 1, animated: true)
                pickerView.reloadComponent(2)
                pickerView.selectRow(0, inComponent: 2, animated: true)
                selectedCity = cityArray.count > 0 ? cityArray[0] : ""
                selectedArea = areaArray.count > 0 ? areaArray[0] : ""
            }
           
        } else if component == 1 {
            switch showType {
            case .city:
                selectedCity = cityArray[row]
                selectedArea = ""
            case .area:
                areaArray = getAreanamesFromProvinceIndex(provinceIndex: selectedProvinceIndex, cityIndex: row)
                pickerView.reloadComponent(2)
                pickerView.selectRow(0, inComponent: 2, animated: true)
                
                selectedCity = cityArray[row]
                selectedArea = areaArray.count > 0 ? areaArray[0] : ""
            case .province:
                break
            }
            
        }else if component == 2 {
            switch showType {
            case .province,.city:
                break
            case .area:
                 selectedArea = areaArray[row]
            }
           
        }
    }
    
    public func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
        return 40
    }
}

// MARK: - 代理方式传值
extension KLCityPickerView {
    
    //初始化方法
    public func areaPickerViewProvince(delegate:KLCityPickerViewDelegate){
        dataDelegate = delegate
        addressPickerViewWithProvince(province: nil, city: nil, area: nil, provinceBlock: nil, cityBlock: nil, areaBlock: nil, showType: .province)
    }
    
    public func areaPickerViewProvince(provine:String?, delegate:KLCityPickerViewDelegate){
        dataDelegate = delegate
        addressPickerViewWithProvince(province: provine, city: nil, area: nil, provinceBlock: nil, cityBlock: nil, areaBlock: nil, showType: .province)
    }
    
    
    public func areaPickerViewCity(delegate:KLCityPickerViewDelegate){
        dataDelegate = delegate
        addressPickerViewWithProvince(province: nil, city: nil, area: nil, provinceBlock: nil, cityBlock: nil, areaBlock: nil, showType: .city)
    }
    
    public func areaPickerViewCity(provine: String?, city: String?, delegate: KLCityPickerViewDelegate){
        dataDelegate = delegate
        addressPickerViewWithProvince(province: provine, city: city, area: nil, provinceBlock: nil, cityBlock: nil, areaBlock: nil, showType: .city)
    }
    
    public func areaPickerViewArea(delegate:KLCityPickerViewDelegate){
        dataDelegate = delegate
        addressPickerViewWithProvince(province: nil, city: nil, area: nil, provinceBlock: nil, cityBlock: nil, areaBlock: nil, showType: .area)
    }
    
    public func areaPickerViewArea(provine: String?, city: String?, area: String?, delegate:KLCityPickerViewDelegate){
        dataDelegate = delegate
        addressPickerViewWithProvince(province: provine, city: city, area: area, provinceBlock: nil, cityBlock: nil, areaBlock: nil, showType: .area)
    }
}


extension UIView {
    
    public var kl_x: CGFloat {
        get {
            return frame.origin.x
        }
        set {
            var f = frame
            f.origin.x = newValue
            frame = f
        }
    }
    
    public var kl_y: CGFloat {
        get {
            return frame.origin.y
        }
        set {
            var f = frame
            f.origin.y = newValue
            frame = f
        }
    }
    
    public var kl_width: CGFloat {
        get {
            return frame.size.width
        }
        set {
            var f = frame
            f.size.width = newValue
            frame = f
        }
    }
    
    public var kl_height: CGFloat {
        get {
            return frame.size.height
        }
        set {
            var f = frame
            f.size.height = newValue
            frame = f
        }
    }
    
    public var kl_origin: CGPoint {
        get {
            return frame.origin
        }
        set {
            var f = frame
            f.origin = newValue
            frame = f
        }
    }
    
    public var kl_size: CGSize {
        get {
            return frame.size
        }
        set {
            var f = frame
            f.size = newValue
            frame = f
        }
    }
    
    public var kl_centerX: CGFloat {
        get {
            return center.x
        }
        set {
            var c = center
            c.x = newValue
            center = c
        }
    }
    
    public var kl_centerY: CGFloat {
        get {
            return center.y
        }
        set {
            var c = center
            c.y = newValue
            center = c
        }
    }
    
    public var kl_bottom: CGFloat {
        get {
            return frame.maxY
        }
        set {
           kl_y = newValue - kl_height
        }
    }
    
}

你可能感兴趣的:(Swift 地址选择器)