Swift.地址選擇器
阿新 • • 發佈:2018-11-09
實現效果:
controller彈出時:半透明背景漸變展示.地址選擇器從下方彈出.
地址選擇器:以省份,城市,地區三級進行選擇,資料來自本地plist檔案.有12個熱門城市供快速選擇,選擇錯誤可以回選.
選擇地區時進行將資料回撥到上一控制器,點選頁面空白區域退出controller.
controller消失時:背景漸變消失,地址選擇器向下退出.
#實現思路:
本質上來說這是一個複雜版的日期選擇器,有關彈出動畫完全可以拿過來就用.
所以主要複雜的點就是這個自定製的地址選擇器.
具體實現是寫一個view其中包含tableView.給view三種type.來決定它當前的狀態.然後根據type的改變來修改他的樣式和資料展示,以及cell被點選時執行方法.
實現方式:
1.找到資料來源,宣告model將資料轉成物件.
2.實現地址選擇器的樣式,資料展示.
3.實現我們需要的轉場檢視動畫.
4.將地址選擇器加入一個ViewController,並修改其轉場動畫代理,使其使用自定製轉場動畫.
5.實現地址選擇器的功能,以及互動優化.
1.找到資料來源,宣告model將資料轉成物件.
資料來自網路,一個plist檔案.將其轉換成model進行儲存.
struct EWCountryModel { var countryDictionary: Dictionary<String,EWProvincesModel> = [:] var provincesArray: [String] = [] init(dic:Dictionary<String,Dictionary<String,Array<String>>>){ for (key,value) in dic{ let model = EWProvincesModel(dic: value) countryDictionary[key] = model provincesArray.append(key) } } } struct EWProvincesModel{ var provincesDictionary: Dictionary<String,EWCityModel> = [:] var cityArray: [String] = [] init(dic:Dictionary<String,Array<String>>){ for (key,value) in dic{ let model = EWCityModel(Arr: value) provincesDictionary[key] = model cityArray.append(key) } } } struct EWCityModel{ var areaArray: Array<String> = [] init(Arr:Array<String>){ for str in Arr{ areaArray.append(str) } } } /// 從area.plist獲取全部地區資料 func initLocationData(){ let dic = NSDictionary(contentsOfFile: Bundle.main.path(forResource: "area", ofType: "plist")!) as! Dictionary<String,Any> locationModel = EWCountryModel(dic: dic as! Dictionary<String, Dictionary<String, Array<String>>>) dataArray = locationModel?.provincesArray }
2.實現地址選擇器的樣式,資料展示.
func buildTitleScrollView() { if titleSV != nil { titleSV.removeFromSuperview() } buttonArr = [] titleSV = UIScrollView(frame: CGRect(x: 0, y: 72, width: ScreenInfo.Width, height: 44)) self.underLine = UIView(frame: CGRect(x: 0, y: 40, width: 30, height: 2)) self.underLine.backgroundColor = UIColor.x4FB0FF for i in 0..<3{ let button = UIButton(frame: CGRect(x: 24 + CGFloat(i) * (ScreenInfo.Width - 47) / 3, y: 0, width: ScreenInfo.Width / 3, height: 44)) button.tag = Int(i) if i == 1 { button.isSelected = true underLine.center.x = button.center.x } button.setTitle("請選擇", for: .normal) button.setTitleColor(UIColor.x333333, for: .normal) button.setTitleColor(UIColor.x4FB0FF, for: .selected) button.titleLabel?.font = UIFont.systemFont(ofSize: 12) button.titleLabel?.adjustsFontSizeToFitWidth = true button.addTarget(self, action: #selector(onClickTitlebutton(sender:)), for: .touchUpInside) buttonArr.append(button) titleSV.addSubview(button) } titleSV.showsVerticalScrollIndicator = false titleSV.addSubview(self.underLine) titleSV.contentSize = CGSize(width: ScreenInfo.Width, height: 44) titleSV.isHidden = true self.addSubview(titleSV) } func drawTableView(){ self.addSubview(tableView) tableView.delegate = self tableView.dataSource = self tableView.separatorStyle = .none tableView.tableHeaderView = tableViewHeaderView tableView.showsVerticalScrollIndicator = false tableView.register(EWAddressPickViewTableViewCell.self, forCellReuseIdentifier: EWAddressPickViewTableViewCell.identifier) tableView.register(EWAddressPickViewFirstTableViewCell.self, forCellReuseIdentifier: EWAddressPickViewFirstTableViewCell.identifier) }
3.實現我們需要的轉場檢視動畫.
//EWAddressPickerViewController的推出和取消動畫
class EWAddressPickerPresentAnimated: NSObject,UIViewControllerAnimatedTransitioning {
var type: EWAddressPickerPresentAnimateType = .present
init(type: EWAddressPickerPresentAnimateType) {
self.type = type
}
/// 動畫時間
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.3
}
/// 動畫效果
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
switch type {
case .present:
let toVC : EWAddressViewController = transitionContext.viewController(forKey: .to) as! EWAddressViewController
let toView = toVC.view
let containerView = transitionContext.containerView
containerView.addSubview(toView!)
toVC.containV.transform = CGAffineTransform(translationX: 0, y: (toVC.containV.frame.height))
UIView.animate(withDuration: 0.25, animations: {
/// 背景變色
toVC.backgroundView.alpha = 1.0
/// addresspicker向上推出
toVC.containV.transform = CGAffineTransform(translationX: 0, y: -10)
}) { (finished) in
UIView.animate(withDuration: 0.2, animations: {
/// transform初始化
toVC.containV.transform = CGAffineTransform.identity
}, completion: { (finished) in
transitionContext.completeTransition(true)
})
}
case .dismiss:
let toVC : EWAddressViewController = transitionContext.viewController(forKey: .from) as! EWAddressViewController
UIView.animate(withDuration: 0.25, animations: {
toVC.backgroundView.alpha = 0.0
/// addresspicker向下推回
toVC.containV.transform = CGAffineTransform(translationX: 0, y: (toVC.containV.frame.height))
}) { (finished) in
transitionContext.completeTransition(true)
}
}
}
}
4.將地址選擇器加入一個ViewController,並修改其轉場動畫代理,使其使用自定製轉場動畫.
lazy var containV: EWAddressPickView = {
let view = EWAddressPickView(frame: CGRect(x: 0, y: ScreenInfo.Height-550, width: ScreenInfo.Width, height: 550))
view.backOnClickCancel = {
self.onClickCancel()
}
/// 成功選擇後將資料回撥,並推出檢視
view.backLocationString = { (address,province,city,area) in
if self.backLocationStringController != nil{
self.backLocationStringController!(address,province,city,area)
self.onClickCancel()
}
}
return view
}()
//MARK: - 轉場動畫delegate
extension EWAddressViewController:UIViewControllerTransitioningDelegate{
/// 推入動畫
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
let animated = EWAddressPickerPresentAnimated(type: .present)
return animated
}
/// 推出動畫
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
let animated = EWAddressPickerPresentAnimated(type: .dismiss)
return animated
}
}
5.實現地址選擇器的功能,以及互動優化.
主要複雜的部分,只能展示其中一部分程式碼,具體實現還是要在demo中看.
private var tableViewType: EWLocationPickViewTableViewType = .provinces{
didSet{
switch tableViewType {
case .provinces:
/// 選擇省份時,有上面的熱門城市view.沒有滾動選擇type的titleScrollView.沒有已選擇label.
self.tableView.tableHeaderView = tableViewHeaderView
self.tableView.frame = CGRect(x: 0, y: 42, width: ScreenInfo.Width, height: 458)
self.titleSV.isHidden = true
self.leftLabel.isHidden = true
/// 將所有選中資料清空
self.provincesModel = nil
self.selectedProvince = ""
self.selectedCity = ""
self.selectedArea = ""
self.cityModel = nil
// 將titleSV中所有button的title重置
// 並將第一個button設定為選中狀態,已保證選擇城市後button下的橫線有滾動效果.
for button in buttonArr {
button.setTitle("請選擇", for: .normal)
button.isSelected = false
if button.tag == 0{
button.isSelected = true
}
}
self.underLine.center = CGPoint(x: self.buttonArr[1].center.x, y: self.underLine.center.y)
self.dataArray = locationModel?.provincesArray
self.tableView.reloadData()
case .city:
/// 選擇城市時沒有熱門城市view,並將titleSV顯示出來
self.tableView.tableHeaderView = UIView()
self.tableView.frame = CGRect(x: 0, y: 136, width: ScreenInfo.Width, height: 367)
self.titleSV.isHidden = false
self.leftLabel.isHidden = false
/// 將省份選擇保留,將城市與地區資料清空
self.selectedCity = ""
self.selectedArea = ""
self.cityModel = nil
/// 通過修改titleSV中button的選中狀態來修改它的顏色
for button in buttonArr {
button.isSelected = false
if button.tag != 0{
button.setTitle("請選擇", for: .normal)
}
if button.tag == 1{
button.isSelected = true
}
}
/// 滾動titleSV中button下滾動的Line
UIView.animate(withDuration: 0.3, animations: {() -> Void in
self.underLine.center = CGPoint(x: self.buttonArr[1].center.x, y: self.underLine.center.y)
})
self.dataArray = provincesModel?.cityArray
self.tableView.reloadData()
case .area:
/// 選擇地區時沒有上方熱門城市View,有titleSV
self.tableView.tableHeaderView = UIView()
self.tableView.frame = CGRect(x: 0, y: 136, width: ScreenInfo.Width, height: 367)
self.titleSV.isHidden = false
self.leftLabel.isHidden = false
/// 通過修改titleSV中button的選中狀態來修改它的顏色
for button in buttonArr {
button.isSelected = false
if button.tag == 2{
button.isSelected = true
}
}
/// 滾動titleSV中button下滾動的Line
UIView.animate(withDuration: 0.3, animations: {() -> Void in
self.underLine.center = CGPoint(x: self.buttonArr[2].center.x, y: self.underLine.center.y)
})
self.dataArray = cityModel?.areaArray
self.tableView.reloadData()
}
}
}
使用方法:
將EWAddressPicker資料夾拖入專案,呼叫時:
let addressPicker = EWAddressViewController()
/*** 可使用這種init方法自定製選中顏色,不填寫selectColor預設顏色為UIColor(red: 79/255, green: 176/255, blue: 255/255, alpha: 1),藍色
let addressPicker = EWAddressViewController(selectColor: UIColor.yellow)
*/
// 返回選擇資料,地址,省,市,區
addressPicker.backLocationStringController = { (address,province,city,area) in
self.label.text = address
}
self.present(addressPicker, animated: true, completion: nil)
demo地址:AddressPicker
OC版本:OC.地址選擇器.
有問題歡迎探討.