美文网首页
Swift--三级联动地址选择器

Swift--三级联动地址选择器

作者: 熊本丸 | 来源:发表于2020-04-24 14:20 被阅读0次

    最近有空都在学习Swift并且尝试在项目中应用,今天在重写老项目的时候,写到收货地址模块,需要一个三级联动地址选择器,于是就有了今天的内容,谨以此来记录我学习Swift的点点滴滴

    知道你们在找啥 先来个demo试试鲜---BWAddressPickerView

    遇到的问题:

    1. 获取地址数据的路径时拿到的path一直为nil,这个找了我老半天😂😂,很低级也很致命的错误,将plist文件导入工程时,没有勾选加入到工程内,小伙伴们一定要切记切记,将资源文件导入项目中的时候,一定要记得勾选加入到工程!!!
    2. 获取到资源文件的路由后,我使用JSONSerialization将其序列化转成字典,无奈一直报3840错误,将资源文件换成.json后缀也不行,到现在我也没找出原因,而且Swift的Dictionary也不支持从path获取,最后的最后,我将接收地址数据的变量类型换成了NSDictionary,使用NSDictionary的NSDictionary(contentsOfFile: filePath)方法,在这里说一句,OC大哥就是大哥,真香,如果有大佬们知道这个原因的,可以帮小弟解个惑,小弟静候各位大佬(ps:看到这篇文章的都是大佬!!!)
    3. 初始化器中的不会执行属性的didSet和willSet方法,所以我在初始化器中手动的调用了设置默认选中地址的操作

    特点

    说起这个有些害臊,哈哈哈 其实没啥特点 拿出来凑个数吧 哈哈哈
    支持三级省市区联动 二级省市联动 一级省联动 支持默认选中
    默默的上个图 大佬们应该没啥意见 哈哈哈

    一级联动
    二级联动
    三级联动

    代码部分

    • 初始化
    /// 便利初始化器
        /// - Parameter block: 回调闭包
        convenience init(selectedBlock block: BWAddressPickerResultBlock?) {
            self.init(autoSeleceted: false, selectedBlock: block)
        }
        
        /// 便利初始化器
        /// - Parameters:
        ///   - isAutoSelected: 是否支持默认回调
        ///   - selectedBlock: 回调闭包
        convenience init(autoSeleceted isAutoSelected: Bool = false,
                         selectedBlock: BWAddressPickerResultBlock?) {
            self.init(autoSeleceted: isAutoSelected,mode: .area, regions: nil, selectedBlock: selectedBlock)
        }
        
        /// 便利初始化器
        /// - Parameters:
        ///   - isAutoSelected: 是否支持默认回调
        ///   - mode: 地址选择器mode
        ///   - defaultRegions: 默认选中的地址
        convenience init(autoSeleceted isAutoSelected: Bool = false,
                         mode: BWAddressPickerMode = .area,
                         defaultRegions: (String, String, String)?) {
            self.init(autoSeleceted: isAutoSelected,mode: mode, regions: defaultRegions, selectedBlock: nil)
        }
        
        /// 便利初始化器
        /// - Parameters:
        ///   - isAutoSelected: 是否支持默认回调
        ///   - mode: 地址选择器mode
        ///   - regions: 默认选中的地址
        ///   - selectedBlock: 回调闭包
        convenience init(autoSeleceted isAutoSelected: Bool = false,
                         mode: BWAddressPickerMode = .area,
                         regions: (String, String, String)?,
                         selectedBlock: BWAddressPickerResultBlock?) {
            self.init()
            shouldAutoSelect = isAutoSelected
            pickerMode = mode
            self.defaultRegions = regions
            addressSelectBlock = selectedBlock
            //由于在初始化的时候不会执行didSet和willSet方法 此处手动调用设置默认选中值的方法
            if self.defaultRegions != nil {
                configDefaultData()
            }
        }
    
    • 初始数据以及默认选中数据的配置
    //配置数据
        func configData() {
            selectedProvinceModel = provinceDataSource[selectedProvinceIndex]
            switch pickerMode {
            case .area:
                selectedCityModel = selectedProvinceModel?.child[selectedCityIndex]
                
                selectedAreaModel = selectedCityModel?.child[selectedAreaIndex]
            case .city:
                selectedCityModel = selectedProvinceModel?.child[selectedCityIndex]
            case .province:
                selectedProvinceModel = provinceDataSource[selectedProvinceIndex]
            }
        }
        
        //配置默认数据
        func configDefaultData() {
            //元组解包
            let (province, city, area) = defaultRegions!
            //默认选中的省数据以及下标
            for (index, provinceModel) in provinceDataSource.enumerated() {
                if provinceModel.title == province {
                    selectedProvinceIndex = index
                    break
                } else {
                    if index == provinceDataSource.count - 1 {
                        selectedProvinceIndex = 0
                    }
                }
            }
            selectedProvinceModel = provinceDataSource[selectedProvinceIndex]
            pickerView.selectRow(selectedProvinceIndex, inComponent: 0, animated: true)
    
            if pickerMode == .city || pickerMode == .area {
                if selectedProvinceModel?.child.count ?? 0 > 0 {
                    for (index, cityModel) in (selectedProvinceModel?.child.enumerated())! {
                        if cityModel.title == city {
                            selectedCityIndex = index
                            break
                        } else {
                            if index == (selectedProvinceModel?.child.count)! - 1 {
                                selectedCityIndex = 0
                            }
                        }
                    }
                    selectedCityModel = selectedProvinceModel?.child[selectedCityIndex]
                    pickerView.selectRow(selectedCityIndex, inComponent: 1, animated: true)
                }
            }
            if pickerMode == .area {
                if selectedCityModel?.child.count ?? 0 > 0 {
                    for (index, areaModel) in (selectedCityModel?.child.enumerated())! {
                        if areaModel.title == area {
                            selectedAreaIndex = index
                            break
                        } else {
                            if index == selectedCityModel?.child.count ?? 0 - 1 {
                                selectedAreaIndex = 0
                            }
                        }
                    }
                    selectedAreaModel = selectedCityModel?.child[selectedAreaIndex]
                    pickerView.selectRow(selectedAreaIndex, inComponent: 2, animated: true)
                }
            }
            pickerView.reloadAllComponents()
        }
    
    • UIPickerViewDataSource部分
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
            switch pickerMode {
            case .area:
                return 3
            case .city:
                return 2
            case .province:
                return 1
            }
        }
        
        func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
            switch component {
            case 0:
                return provinceDataSource.count
            case 1:
                return selectedProvinceModel?.child.count ?? 0
            case 2:
                return selectedCityModel?.child.count ?? 0
            default:
                return 0
            }
        }
        
        func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
            return BWScreenScaleWidth(width: 35)
        }
    
    • UIPickerViewDelegate部分
      这里是地址选择联动的核心代码
     func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
            //设置分割线颜色
            for subView in pickerView.subviews {
                if subView.isKind(of: UIView.self) && subView.height <= 1 {
                    subView.backgroundColor = BWHexColor("#EAEAEA")
                }
            }
            var label = view as? UILabel
            if label == nil {
                label = UILabel.init()
                label?.font = BWSystemRegularFont(fontSize: 14)
                label?.textColor = color333333
                label?.textAlignment = .center
                label?.minimumScaleFactor = 0.5
                label?.adjustsFontSizeToFitWidth = true
            }
            switch component {
            case 0:
                //省标题
                let provinceModel = provinceDataSource[row]
                label?.text = provinceModel.title
            case 1:
                let cityModel = selectedProvinceModel?.child[row]
                label?.text = cityModel?.title
            case 2:
                let areaModel = selectedCityModel?.child[row]
                label?.text = areaModel?.title
            default:
                break
            }
            return label!
        }
        
        func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
            switch component {
            case 0:
                selectedProvinceIndex = row
                selectedProvinceModel = provinceDataSource[row]
                switch pickerMode {
                case .province:
                    selectedCityModel = nil
                    selectedAreaModel = nil
                case .city:
                    selectedCityIndex = 0
                    //避免港澳台地区没有下级市的情况
                    if selectedProvinceModel?.child.count ?? 0 > 0 {
                        selectedCityModel = selectedProvinceModel?.child[selectedCityIndex]
                        pickerView.selectRow(selectedCityIndex, inComponent: 1, animated: true) 
                    } else {
                        selectedCityModel = nil
                    }
                    selectedAreaModel = nil
                    //刷新下级市数据
                    pickerView.reloadComponent(1)
                case .area:
                    //刷新下级市以及下级县数据
                    selectedCityIndex = 0
                    if selectedProvinceModel?.child.count ?? 0 > 0 {
                        selectedCityModel = selectedProvinceModel?.child[selectedCityIndex]
                        selectedAreaIndex = 0
                        pickerView.selectRow(selectedCityIndex, inComponent: 1, animated: true)
                        if selectedCityModel?.child.count ?? 0 > 0 {
                            selectedAreaModel = selectedCityModel?.child[selectedAreaIndex]
                            pickerView.selectRow(selectedAreaIndex, inComponent: 2, animated: true)
                        } else {
                            selectedAreaModel = nil;
                        }
                    } else {
                        selectedCityModel = nil
                        selectedAreaModel = nil;
                    }
                    pickerView.reloadComponent(1)
                    pickerView.reloadComponent(2)
                }
            case 1:
                selectedCityIndex = row
                selectedCityModel = selectedProvinceModel?.child[row]
                switch pickerMode {
                case .city:
                    selectedAreaModel = nil
                case .area:
                    selectedAreaIndex = 0
                    //避免某些下级市没有更下级的县区造成的数组越界问题
                    if selectedCityModel?.child.count ?? 0 > 0 {
                        selectedAreaModel = selectedCityModel?.child[selectedAreaIndex]
                        pickerView.selectRow(selectedAreaIndex, inComponent: 2, animated: true)
                    } else {
                        selectedAreaModel = nil
                    }
                    pickerView.reloadComponent(2)
                default:
                    break
                }
            case 2:
                selectedAreaIndex = row
                selectedAreaModel = selectedCityModel?.child[selectedAreaIndex]
            default:
                break
            }
            if shouldAutoSelect == true {
                selectedAddress()
            }
        }
    

    使用

     let addressPickerView = BWAddressPickerView.init(autoSeleceted: true, mode: pickerMode, regions: ("浙江省", "湖州市", "长兴县")) { (provinceModel, cityModel, areaModel) in
                print("block回调-----省:\(provinceModel.title)----市:\(cityModel?.title)----区县:\(areaModel?.title)")
            }
    //        addressPickerView.defaultRegions = ("浙江省", "湖州市", "长兴县")
            addressPickerView.delegate = self
            addressPickerView.animationShow()
    

    不积跬步无以至千里,不积小流无以成江海,每天都进步一点,那我们离顶端的差距又近了一点

    相关文章

      网友评论

          本文标题:Swift--三级联动地址选择器

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