SwiftUI 城市选择器 --多级联动

SwiftUI 城市选择器

效果图
在这里插入图片描述

//
/*!
 -------------------------------------------------------------------------------
   File name:       CityPicker.swift
   Author:            lanyuejing

   Description:    城市选择器

   History:
              2023/4/15: File created. at version v版本号

 -------------------------------------------------------------------------------
 */

import Foundation
import SwiftUI
import SwiftyJSON

struct CityPicker: View {
    // MARK: Internal

    var body: some View {
        let provinceName = addressItems[safe: selectProvinceIndex]?.name
        let city = addressItems[safe: selectProvinceIndex]?.childs[safe: selectCityIndex]?.name
        let area = addressItems[safe: selectProvinceIndex]?.childs[safe: selectCityIndex]?.childs[safe: selectAreaIndex]?.name
        VStack(spacing: 20) {
            HStack {
                Text("\(provinceName ?? "未选择")")
                Text("\(city ?? "")")
                Text("\(area ?? "")")
            }.foregroundColor(Color.black)
            GeometryReader { geometry in
                HStack(spacing: 0) {
                    Picker("省", selection: $selectProvinceIndex) {
                        ForEach(0..<addressItems.count, id: \.self) { index in
                            let name = addressItems[index].name
                            Text(name)
                        }
                    }
                    .onChange(of: selectProvinceIndex, perform: { _ in
                        changeSelectCity(selectCityIndex: 0)
                    })
                    .frame(width: geometry.size.width/3, alignment: .center)
                    .clipped()

                    Picker("市", selection: $selectCityIndex) {
                        let cities = addressItems[safe: selectProvinceIndex]?.childs
                        if let cities = cities {
                            ForEach(0..<cities.count, id: \.self) { index in
                                let name = cities[safe: index]?.name ?? ""
                                Text(name)
                            }
                        } else {
                            EmptyView()
                        }
                    }
                    .onChange(of: selectCityIndex, perform: { newValue in
                        changeSelectAreas(selectCityIndex: newValue)
                    })
                    .frame(width: geometry.size.width/3, alignment: .center)
                    .clipped()
                    Picker("区", selection: $selectAreaIndex) {
                        let selectedArea = self.addressItems[safe: selectProvinceIndex]?.childs[safe: selectCityIndex]?.childs
                        if let areas = selectedArea {
                            ForEach(0..<areas.count, id: \.self) { index in
                                let name = areas[safe: index]?.name ?? ""
                                Text(name)
                            }
                        } else {
                            EmptyView()
                        }
                    }
                    .frame(width: geometry.size.width/3, alignment: .center)
                    .clipped()
                }
            }
        }.onAppear(perform: { loadAddress() })
    }

    // MARK: Private

    @State private var addressItems: [Province] = []
    @State private var selectProvinceIndex = 0
    @State private var selectCityIndex = 0
    @State private var selectAreaIndex = 0

    private func loadAddress() {
        let bundle = Bundle.main
        let plistPath = bundle.path(forResource: "newaddress", ofType: "plist")
        let addressDic = NSDictionary(contentsOfFile: plistPath ?? "") ?? ["": ""]
        let jsonData = JSON(addressDic)
        let provincesItems = Address(json: jsonData).provinces
        addressItems = provincesItems
    }

    private func changeSelectAreas(selectCityIndex: Int) {
        selectAreaIndex = selectCityIndex
    }

    private func changeSelectCity(selectCityIndex: Int) {
        self.selectCityIndex = selectCityIndex
        selectAreaIndex = 0
    }
}

public extension Collection {
    subscript(safe index: Index) -> Element? {
        indices.contains(index) ? self[index] : nil
    }
}

struct CityPicker_Previews: PreviewProvider {
    static var previews: some View {
        CityPicker()
    }
}

折叠效果之城市选择器
在这里插入图片描述

//
/*!
 -------------------------------------------------------------------------------
   File name:       AddressView.swift
   Author:            langyuejing

   Description:    城市选择器
   History:
              2023/4/15: File created. at version v版本号

 -------------------------------------------------------------------------------
 */

import Foundation
import SwiftUI
import SwiftyJSON

struct AddressView: View {
    // MARK: Internal

    var body: some View {
        VStack {
            GeometryReader { geometry in
                List(addressItems, children: \.childs, selection: $selectionItem, rowContent: { item in
                    if item.provincecode.count > 0, item.citycode.count > 0 {
                        Text(item.name).foregroundColor(Color.black).onTapGesture {
                            selectionItem = item
                        }.frame(width: geometry.size.width - 40, alignment: .leading).padding(.leading, 80)
                    } else {
                        Text(item.name).foregroundColor(Color.black).onTapGesture {
                            selectionItem = item
                        }
                    }
                }).onAppear(perform: { loadAddress() })
            }
        }
    }

    // MARK: Private

    @State private var showAlert = false
    @State private var tapValue = "123"

    @State private var selectionItem: AreaModel?
    @State private var selectProvinceIndex = 0
    @State private var selectCityIndex = 0
    @State private var selectAreaIndex = 0
    @State private var addressItems: [AreaModel] = []
    @State private var flags: [Bool] = [false, false, false]
    @State private var items: [Any] = []

    private func loadAddress() {
        let bundle = Bundle.main
        let plistPath = bundle.path(forResource: "newaddress", ofType: "plist")
        let addressDic = NSDictionary(contentsOfFile: plistPath ?? "") ?? ["": ""]
        let jsonData = JSON(addressDic)
        let provincesItems = AreaList(json: jsonData).areaList
        addressItems = provincesItems
    }
}

struct AddressView_Previews: PreviewProvider {
    static var previews: some View {
        AddressView()
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值