swift-地址选择器

效果图:

地址选择.png

代码:

定义PickerBaseView

import UIKit

let kDatePicHeight:CGFloat = 200
let kTopViewHeight:CGFloat = 44

let SCREEN_BOUNDS = UIScreen.mainBounds
let SCREEN_WIDTH = UIScreen.mainWidth
let SCREEN_HEIGHT = UIScreen.mainHeight

class PickerBaseView: UIView {

    //背景视图
    lazy var backgroundView:UIView = {
        let view = UIView(frame: SCREEN_BOUNDS)
        view.backgroundColor = UIColor.white.withAlphaComponent(0.20)
        view.isUserInteractionEnabled = true
        let tap = UITapGestureRecognizer(target: self, action: #selector(didTapBackgroundView))
        view.addGestureRecognizer(tap)
        return view
    }()

    //弹出视图
    lazy var alertView:UIView = {
        let view = UIView(frame: CGRect(x: 0, y: SCREEN_HEIGHT - kTopViewHeight-kDatePicHeight, width: SCREEN_WIDTH, height: kTopViewHeight+kDatePicHeight))
        view.backgroundColor = UIColor.white

        return view
    }()
    
    //顶部视图
    lazy var topView:UIView = {
        let view = UIView(frame: CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: kTopViewHeight+0.5))
        view.backgroundColor = UIColor.colorWithHexCode(code: "fdfdfd")
        return view
    }()
    
    //左边取消按钮
    lazy var leftBtn:UIButton = {
        let btn = UIButton(type: .custom)
        btn.frame = CGRectMake(5, 8, 60, 28)
        btn.backgroundColor = UIColor.clear
        btn.layer.borderColor = Color.topNav.cgColor
        btn.layer.cornerRadius = 6.0
        btn.layer.masksToBounds = true
        btn.layer.borderWidth = 1.0
        btn.titleLabel?.font = Font.large
        btn.setTitleColor(Color.topNav, for: .normal)
        btn.setTitle("取消", for: .normal)
        btn.addTarget(self, action: #selector(clickLeftBtn), for: .touchUpInside)
        return btn
    }()
    
    //右边确定按钮
    lazy var rightBtn:UIButton = {
        let btn = UIButton(type: .custom)
        btn.frame = CGRectMake(SCREEN_WIDTH - 65, 8, 60, 28)
        btn.backgroundColor = UIColor.clear
        btn.layer.borderColor = Color.topNav.cgColor
        btn.layer.cornerRadius = 6.0
        btn.layer.masksToBounds = true
        btn.layer.borderWidth = 1.0
        btn.titleLabel?.font = Font.large
        btn.setTitleColor(Color.topNav, for: .normal)
        btn.setTitle("确定", for: .normal)
        btn.addTarget(self, action: #selector(clickRightBtn), for: .touchUpInside)
        return btn

    }()
    
    //中间标题
    lazy var titleLabel:UILabel = {
        let label = UILabel(frame: CGRectMake(65, 0, SCREEN_WIDTH-130, kTopViewHeight))
        label.backgroundColor = UIColor.clear
        label.font = Font.middleP
        label.textAlignment = .center
        label.textColor = Color.topNav
        return label
    }()
    
    //分割线视图
    lazy var lineView:UIView = {
        let view = UIView(frame: CGRectMake(0, kTopViewHeight, SCREEN_WIDTH, 0.5))
        view.backgroundColor = Color.line2
        return view
    }()
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    func initUI(){
        self.frame = SCREEN_BOUNDS
        
        self.addSubview(self.backgroundView)
        self.addSubview(self.alertView)
        self.alertView.addSubview(self.lineView)
        self.alertView.addSubview(self.topView)
        self.topView.addSubview(self.leftBtn)
        self.topView.addSubview(self.rightBtn)
        self.topView.addSubview(self.titleLabel)
        self.topView.addSubview(self.lineView)
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
}
//响应事件
extension PickerBaseView{
    func didTapBackgroundView(){
        
    }
    func clickLeftBtn(){
        
    }
    func clickRightBtn(){
        
    }

}

定义PickerView选择器

import UIKit
import HandyJSON

typealias AaddressResultBlock = (_ selectedAddress:AddressSelected) -> Void

class AddressPickerView: PickerBaseView{
    
    //初始值
    var rowOfProvince:Int = 0
    var rowOfCity:Int = 0
    var rowOfTown:Int = 0
    
    var textField: UITextField!
    lazy var pickerView:UIPickerView = {
        let pickerV = UIPickerView(frame: CGRectMake(0, kTopViewHeight+0.5, SCREEN_WIDTH, kDatePicHeight))
        pickerV.backgroundColor = UIColor.white
        pickerV.dataSource = self
        pickerV.delegate = self
        return pickerV
    }()
    
    lazy var address:AddressSelected = {
        let are = AddressSelected()
        are.province = "北京市"
        are.city = "北京市辖区"
        are.town = "东城区"
        return are
    }()
    
    var addressModelArr = [AddressProvinceModel]()
    
    var defaultSelectedArr:[Int] = [Int]()
    lazy var isAutoSelect:Bool = true
    
    var resultBlock:AaddressResultBlock?
    
    /// 显示地址选择器
    ///
    /// - Parameters:
    ///   - defaultSelected: 默认选中的值(传数组,元素为对应的索引值)
    ///   - isAutoSelect: 是否自动选择,即选择完执行结果回调,
    ///   - resultBlock: 选择后的回调
    static func showAddressPicker(defaultSelected:[Int], isAutoSelect:Bool, resultBlock:@escaping AaddressResultBlock){
        let addressPickerView = AddressPickerView.pickerView(withDefaultSelectedArr: defaultSelected, isAutoSelect: isAutoSelect, resultBlock: resultBlock)
        addressPickerView.showWithAnimation(animation: true)
    }
    private override init(frame: CGRect) {
        super.init(frame: frame)
    }
    static func pickerView(withDefaultSelectedArr selectedArr:[Int], isAutoSelect autoSelect:Bool, resultBlock:@escaping AaddressResultBlock) -> AddressPickerView {
        let addressPickerView = AddressPickerView()
        if selectedArr.count == 3 {
            addressPickerView.defaultSelectedArr = selectedArr
        }else{
            addressPickerView.defaultSelectedArr = [0,0,0]
        }
        addressPickerView.isAutoSelect = autoSelect
        addressPickerView.resultBlock = resultBlock
        addressPickerView.loadCities()
        addressPickerView.initUI()
        return addressPickerView
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    deinit {
        print("地址选择器被销毁")
    }
    
    //加载城市数据
    func loadCities(){
        let pt = Bundle.main.path(forResource: "Cities.json", ofType: nil)
        let dicp = try?JSONSerialization.jsonObject(with: NSData(contentsOfFile: pt!) as Data, options: .mutableLeaves) as! [String:AnyObject]
        let dicArr = dicp!["data"] as! [AnyObject]
        for dic in dicArr{
            let dicF = dic as! NSDictionary
            let provinceModel = AddressProvinceModel.deserialize(from: dicF)
            addressModelArr.append(provinceModel!)
        }
    }
    
    override func initUI() {
        super.initUI()
        self.titleLabel.text = "请选择城市"
        self.alertView.addSubview(self.pickerView)
    }
}

extension AddressPickerView{
    //弹出视图方法
    func showWithAnimation(animation:Bool){
        let window = UIApplication.shared.keyWindow
        window?.addSubview(self)
        if animation {
            //动画初始位置
            var rect = self.alertView.frame
            rect.origin.y = SCREEN_HEIGHT
            self.alertView.frame = rect
            //浮现动画
            UIView.animate(withDuration: 0.3, animations: {
                var rect = self.alertView.frame
                rect.origin.y -= kDatePicHeight + kTopViewHeight
                self.alertView.frame = rect
            })
        }
        
        //滚动到默认行
        scrollTo(row: 0, component: 0, animated: true)
    }
    
    //关闭动画
    func dismissWithAnimation(animation:Bool){
        UIView.animate(withDuration: 0.2, animations: {
            var rect = self.alertView.frame
            rect.origin.y += kDatePicHeight+kTopViewHeight
            self.alertView.frame = rect
            self.backgroundView.alpha = 0
        }) { (finished) in
            self.leftBtn.removeFromSuperview()
            self.rightBtn.removeFromSuperview()
            self.titleLabel.removeFromSuperview()
            self.lineView.removeFromSuperview()
            self.topView.removeFromSuperview()
            self.pickerView.removeFromSuperview()
            self.alertView.removeFromSuperview()
            self.backgroundView.removeFromSuperview()
            self.removeFromSuperview()
        }
    }
    override func clickLeftBtn() {
        self.dismissWithAnimation(animation: true)
    }
    override func clickRightBtn() {
        self.dismissWithAnimation(animation: true)
        if (self.resultBlock != nil) {
            self.resultBlock!(address)
        }
    }
    override func didTapBackgroundView() {
        self.dismissWithAnimation(animation: false)
    }
}

extension AddressPickerView: UIPickerViewDelegate, UIPickerViewDataSource {
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 3
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        let provinceModel = self.addressModelArr[rowOfProvince];
        let cityModel = provinceModel.city?[rowOfCity];
        if (component == 0) {
            //返回省个数
            return self.addressModelArr.count;
        }
        if (component == 1) {
            //返回市个数
            return provinceModel.city?.count ?? 1;
        }
        if (component == 2) {
            //返回区个数
            return cityModel?.town?.count ?? 1;
        }
        return 0;
    }
    
    //row
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        var showTitleValue:String = ""
        switch component {
        case 0:
            let provinceModel = addressModelArr[row]
            showTitleValue = provinceModel.name!
            break
        case 1:
            let provinceModel = addressModelArr[rowOfProvince]
            let cityModel = provinceModel.city?[row]
            showTitleValue = cityModel?.name ?? ""
            break
        case 2:
            let provinceModel = addressModelArr[rowOfProvince]
            let cityModel = provinceModel.city?[rowOfCity]
            let towModel = cityModel?.town?[row]
            showTitleValue = towModel?.name ?? ""
            break
        default:
            break
        }
        return showTitleValue
    }
    
    //自定义cell
    func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
        let label = UILabel(frame: CGRect(x: 0, y: 0, width: (UIScreen.mainWidth-30)/3, height: 40))
        label.textAlignment = .center
        label.font = Font.largeP
        label.text = self.pickerView(pickerView, titleForRow: row, forComponent: component)
        return label
    }
    
    //选中
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        if (component == 0) {
            rowOfProvince = row;
            rowOfCity = 0;
            rowOfTown = 0;
            address.province = addressModelArr[rowOfProvince].name!
        } else if (component == 1) {
            rowOfCity = row;
            rowOfTown = 0;
            address.city = addressModelArr[rowOfProvince].city![rowOfCity].name!
            
        } else if (component == 2) {
            rowOfTown = row;
            address.town = addressModelArr[rowOfProvince].city![rowOfCity].town![rowOfTown].name!
        }
        scrollTo(row: row, component: component)
        
        if self.isAutoSelect {
            self.resultBlock!(address)
        }
        
    }
    //MARK: - 手动滚动刷新
    func scrollTo(row:Int, component:Int, animated:Bool = true){
        self.pickerView.selectRow(row, inComponent: component, animated: animated)
        switch component {
        case 0:
            rowOfProvince = row
            rowOfCity = 0
            rowOfTown = 0
            let provinceModel = addressModelArr[row]
            address.province = provinceModel.name!
            let cityModel = provinceModel.city?[rowOfCity]
            address.city = cityModel?.name ?? ""
            address.town = cityModel?.town?[rowOfTown].name ?? ""
            pickerView.reloadComponent(1)
            pickerView.reloadComponent(2)
            break
        case 1:
            rowOfCity = row
            rowOfTown = 0
            self.pickerView.reloadComponent(2)
            let cityModel = addressModelArr[rowOfProvince].city?[row]
            address.city = cityModel?.name ?? ""
            address.town = cityModel?.town?[rowOfTown].name ?? ""
            break
        case 2:
            rowOfTown = row
            address.town = addressModelArr[rowOfProvince].city?[rowOfCity].town?[row].name ?? ""
            break
        default:
            break
        }
        pickerView.selectRow(rowOfProvince, inComponent: 0, animated: true)
        pickerView.selectRow(rowOfCity, inComponent: 1, animated: true)
        pickerView.selectRow(rowOfTown, inComponent: 2, animated: true)
        /*
        if self.isAutoSelect {
            self.resultBlock!(address)
        }
        */
    }
    
}


//MARK: - 地址数据模型
class AddressProvinceModel:HandyJSON{
    var name:String?
    var city:[AddressCityModel]?
    required init() {
    }
    func mapping(mapper: HelpingMapper) {
        
        mapper <<<
            self.city <-- "children"
        
    }
    
}

class AddressCityModel:HandyJSON{
    var name:String?
    var town:[AddressTownModel]?
    required init() {}
    func mapping(mapper: HelpingMapper) {
        
        mapper <<<
            self.town <-- "children"
    }
}
class AddressTownModel:HandyJSON{
    var name:String?
    required init() {}
    
}
//记录选中的区域
class AddressSelected {
    var province = ""
    var city = ""
    var town = ""
    
    func description(){
        
    }
}

//MARK:- 自定义TextField
typealias SelectTapActionBlock = ()->Void

class TapTextField: UITextField {
    
    var tapActionBlock:SelectTapActionBlock?
    
 @IBInspectable
    var leftStr: String!
    var leftMoreW: CGFloat = 0
    
    lazy var tapView = { () -> UIView in 
        let tapV = UIView()
        tapV.backgroundColor = UIColor.clear
        let tap = UITapGestureRecognizer(target: self, action: #selector(didTapAction))
        tapV.addGestureRecognizer(tap)
        tapV.isUserInteractionEnabled = true
        return tapV
    }()
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        if self.leftStr != nil{
            let leftLabel = UILabel()
            leftLabel.frame = CGRect(x: 15, y: 0, width: 100, height: rect.height)
            leftLabel.text = self.leftStr
            leftLabel.textColor = Color.textH
            leftLabel.font = Font.large
            
            let leftView = UIView()
            leftView.frame = CGRect(x: 0, y: 0, width: leftLabel.sizeWidth+25+self.leftMoreW, height: rect.height)
            self.leftView = leftView
            self.leftViewMode = UITextFieldViewMode.always
            leftView.addSubview(leftLabel)
        }else{
            self.addLeftBlank(w: 15)
        }
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.addSubview(tapView)
    }
    convenience init() {
        self.init(frame: CGRect.zero)
        self.backgroundColor = UIColor.white
        self.textColor = Color.textM
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        self.tapView.snp.makeConstraints { (make) in
            make.edges.equalToSuperview()
        }
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    func setTapActionBlock(actionBlock:@escaping SelectTapActionBlock){
        self.tapActionBlock = actionBlock
        self.tapView.isHidden = false
    }
    func didTapAction(){
        //响应点击事件,隐藏键盘
//        UIApplication.shared.keyWindow?.endEditing(true)
        self.tapActionBlock!()
    }
}


使用说明:

     //显示地址
    lazy var addressTextField:TapTextField = {
        let label = TapTextField()
        label.leftStr = "所在地区"
        label.placeholder = "请选择"
        label.delegate = self
        label.textAlignment = .right

        return label
    }()

    
        addressTextField.setTapActionBlock(actionBlock: {
        AddressPickerView.showAddressPicker(defaultSelected: [0,0,0], isAutoSelect: true, resultBlock: { [unowned self](selectedAddress) in
            self.setAreaText(address: selectedAddress)
            })
        })

转载于:https://my.oschina.net/u/3552209/blog/1536909

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值