效果图:
代码:
定义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)
})
})