iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 30
0
Mobile Development

《菜鳥のSwift》持續30天開發挑戰系列 第 30

《DAY 30》天氣 App 實作(完)

  • 分享至 

  • xImage
  •  

最後一天來把天氣 App 的剩餘部分給完成,衝啊!

  • 當一開始進入 App 會直接顯示宜蘭縣在第一個時間區間的天氣資訊。
    https://ithelp.ithome.com.tw/upload/images/20201013/20129680sgUY2eur5m.png

  • 點擊一下畫面可以選擇地點,因此要把選取器放入提示框裡。
    https://ithelp.ithome.com.tw/upload/images/20201013/20129680TUadaBrs1z.png

  • 選完地點後接著就讓使用者選擇時間。
    https://ithelp.ithome.com.tw/upload/images/20201013/20129680JVqLlYX5t0.png

  • 完整的程式碼如下,看起來有點恐怖,但如果清楚流程其實還好。

import UIKit

class ViewController: UIViewController {
    
    let location = ["宜蘭縣","花蓮縣","臺東縣","澎湖縣","金門縣","連江縣","臺北市","新北市","桃園市","臺中市","臺南市","高雄市","基隆市","新竹縣","新竹市","苗栗縣","彰化縣","南投縣","雲林縣","嘉義縣","嘉義市","屏東縣"]
    var selectLocation = "宜蘭縣" // 選取器選擇的地點
    var selectTime = 0 // 選取器選擇的時間區間,範圍 0~2
    var timeData = ["","",""] // 讀取 JSON 後,存放三個時間的 startTime
    let locationPickerView = UIPickerView(frame: CGRect(x: 0, y: 50, width: 270, height: 150)) // 把地點選取器放入提示框裡,大小要自己嘗試調整
    let timePickerView = UIPickerView(frame: CGRect(x: 0, y: 50, width: 270, height: 150)) // 把時間選取器放入提示框裡,大小要自己嘗試調整
    
    @IBOutlet weak var locationName: UILabel!
    @IBOutlet weak var Wx: UILabel!
    @IBOutlet weak var PoP: UILabel!
    @IBOutlet weak var MinT: UILabel!
    @IBOutlet weak var CI: UILabel!
    @IBOutlet weak var MaxT: UILabel!
    @IBOutlet weak var startTime: UILabel!
    @IBOutlet weak var endTime: UILabel!
    
    @IBOutlet weak var weatherIcon: UIImageView!
    
        
    override func viewDidLoad() {
        super.viewDidLoad()
        
        locationPickerView.dataSource = self
        locationPickerView.delegate = self
        timePickerView.dataSource = self
        timePickerView.delegate = self
        
        loadJSON(locationName: selectLocation, time: selectTime) // 進入畫面前先讀一次 JSON,以便得到 timeData
        
    }
    
    // MARK:- 讀 JSON 資料,必須要傳入地點和時間
    func loadJSON(locationName: String ,time: Int){
        
        let url =  "https://opendata.cwb.gov.tw/api/v1/rest/datastore/F-C0032-001?Authorization=CWB-6F803E34-66E5-4135-AC7D-25811AD53D5C&format=JSON&locationName=\(locationName)"
        let newUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)! // 網址有中文,需要先編碼
        
        var request = URLRequest(url: URL(string: newUrl)!,timeoutInterval: Double.infinity)
        request.httpMethod = "GET"
        let task = URLSession.shared.dataTask(with: request){(data, respond, error) in
            
            let decoder = JSONDecoder()
            if let data = data, let weather = try? decoder.decode(Weather.self, from: data){
                
                print(weather)
                
                DispatchQueue.main.sync {
                    
                    self.locationName.text = weather.records.location[0].locationName
                    self.Wx.text = weather.records.location[0].weatherElement[0].time[time].parameter.parameterName
                    self.PoP.text = weather.records.location[0].weatherElement[1].time[time].parameter.parameterName + "%"
                    self.MinT.text = weather.records.location[0].weatherElement[2].time[time].parameter.parameterName + "°" + weather.records.location[0].weatherElement[2].time[time].parameter.parameterUnit!
                    self.CI.text = weather.records.location[0].weatherElement[3].time[time].parameter.parameterName
                    self.MaxT.text = weather.records.location[0].weatherElement[4].time[time].parameter.parameterName + "°" + weather.records.location[0].weatherElement[4].time[time].parameter.parameterUnit!
                    self.startTime.text = weather.records.location[0].weatherElement[0].time[time].startTime
                    self.endTime.text = weather.records.location[0].weatherElement[0].time[time].endTime
                    
                    for i in 0...2 {
                        self.timeData[i] = weather.records.location[0].weatherElement[0].time[i].startTime
                    } // 把三個 startTime 放入陣列
                    
                    self.changeWeatherIcon() // 根據天氣現象改變圖示

                }
                
            }
            else {
                print("error")
            }
            
        }
        task.resume()
    }
    
    // MARK:- 改變 weatherIcon
    func changeWeatherIcon() {
        if Wx.text!.contains("積冰") {
            weatherIcon.image = UIImage.init(systemName: "snow")
        }
        else if Wx.text!.contains("暴風雪"){
            weatherIcon.image = UIImage.init(systemName: "wind.snow")
        }
        else if Wx.text!.contains("雪") {
            if Wx.text!.contains("雨") {
                weatherIcon.image = UIImage.init(systemName: "cloud.sleet")
            }
            else {
                weatherIcon.image = UIImage.init(systemName: "cloud.snow")
            }
        }
        else if Wx.text!.contains("雨") {
            if Wx.text!.contains("雷") {
                weatherIcon.image = UIImage.init(systemName: "cloud.bolt.rain")
            }
            else if Wx.text!.contains("晴"){
                weatherIcon.image = UIImage.init(systemName: "cloud.sun.rain")
            }
                
            else {
                weatherIcon.image = UIImage.init(systemName: "cloud.rain")
            }
        }
        else if Wx.text!.contains("晴") {
            if Wx.text!.contains("雲") {
                weatherIcon.image = UIImage.init(systemName: "cloud.sun")
            }
            else {
                weatherIcon.image = UIImage.init(systemName: "sun.max")
            }
        }
        else if Wx.text!.contains("陰") {
            weatherIcon.image = UIImage.init(systemName: "smoke.fill")
        }
        else if Wx.text!.contains("雲") {
            weatherIcon.image = UIImage.init(systemName: "smoke")
        }
        
    }
    
    
    // MARK:- 點擊一下畫面依序跳出選取器
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        locationView() // 點擊一下畫面可以選擇地點
    }
    
    func locationView() {
        let alertView = UIAlertController(
            title: "選擇地點",
            message: "\n\n\n\n\n\n\n\n\n", // 因為要放入選取器,使提示框高度增高
            preferredStyle: .alert
        )
        let cancelAction = UIAlertAction(
            title: "取消",
            style: .default,
            handler: nil
        )
        
        let okAction = UIAlertAction(
            title: "確認",
            style: .destructive,
            handler: {_ in
                self.loadJSON(locationName: self.selectLocation, time: self.selectTime)
                self.timeView()} // 選完地點接著選時間
        )
        
        alertView.view.addSubview(locationPickerView)
        alertView.addAction(cancelAction)
        alertView.addAction(okAction)
        
        present(alertView, animated: true, completion: nil)
    }
    func timeView() {
        let alertView = UIAlertController(
            title: "選擇時間",
            message: "\n\n\n\n\n\n\n\n\n", // 因為要放入選取器,使提示框高度增高
            preferredStyle: .alert
        )
        let cancelAction = UIAlertAction(
            title: "取消",
            style: .default,
            handler: nil
        )
        
        let okAction = UIAlertAction(
            title: "確認",
            style: .destructive,
            handler: {_ in self.loadJSON(locationName: self.selectLocation, time: self.selectTime)}
        )
        
        alertView.view.addSubview(timePickerView)
        alertView.addAction(cancelAction)
        alertView.addAction(okAction)
        
        present(alertView, animated: true, completion: nil)
    }
    
}

    // MARK:- 選取器

extension ViewController: UIPickerViewDataSource, UIPickerViewDelegate {
    
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        
        if pickerView == locationPickerView {
            return location.count
        }
        if pickerView == timePickerView {
            return timeData.count // 三個時間區間
        }

        return 0
        
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        if pickerView == locationPickerView {
            return location[row]
        }
        if pickerView == timePickerView {
            return timeData[row]
        }

        return nil
    }


    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        
        if pickerView == locationPickerView {
            selectLocation = location[row] // 改變地點
        }
        if pickerView == timePickerView {
            selectTime = row // 改變時間
        }
        
    }
    
}
  • 執行起來的樣子。

心得:終於完賽了,這些天介紹了幾個元件,也做了 1A2B 小遊戲和這個天氣 App,其實開賽前我本來預計還要做其它 App 出來的,但是那時候硬碟壞軌,導致許多寫好的程式都不見,所以這 30 天來幾乎是一天寫一篇,寫好程式再來寫文章,即使是寫過的還必須再寫一次,實在是頗累人的,但是往好的方面想,這樣可以讓自己寫過的東西記憶更深,即使忘掉了只要過來這裡複製就好,也在這裡看到了團隊隊友做過,而我卻沒做過的作品。


上一篇
《DAY 29》天氣 App 實作(二)
系列文
《菜鳥のSwift》持續30天開發挑戰30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言