見出し画像

【徒然iOS】気ままにUIKit48〜Picker Viewを使って、秒も設定できるカウントダウンタイマーを作る。〜

概要

このマガジンは四十を過ぎたおっさんが、

を参考にStoryboardでiOSアプリを完全に趣味で楽しんでいるだけな記事を気ままに上げてます。

今回

をハイ、レッツゴ🕺

前準備

今回は、前回のビューの続きにはめ込もうかなと考えたけど、よく考えたらPickerViewがコードで管理されて、データが分割できないので、新しいビューをいつもどおり作ることにした💦
念の為、

  1. バックアップ

  2. 新しいクラス

  3. ビューコントローラの追加

  4. イニシャルビューの変更

をいつも通りやってから本題へ💃

こんな感じかな

本題

まあ、解説がつらつらと書かれてるけど、
要は、

前々回のカウントダウンタイマーだと、
秒まで表示できないから〜〜〜

ってことが言いたいことは理解した!

⒈前回の機能を別ビューで用意

コードまで組み込んで〜〜〜〜
はい、問題なし🕺

では、今回の操作をやっていこうっと〜〜〜

⒉ボタンを配置する

アトリビュートインスペクタボタンを押して設定画面を表示。

  • Titleにカウントダウン開始

  • Text Colorを白

  • Backgroundに青

を設定。
てことなんで、言われたとおり。

完了🕺

⒊ボタンを以下の設定でアクション接続

  • ConnectionにAction

  • NameにstartContDown

  • TypeにUIButton

  • EventにTouch Up Inside

名前だけ任意のものにして〜〜〜
ハイ、完了🕺

⒋ピッカービューをアウトレット接続

  • ConnectionにOutlet

  • NameにtestPickerView

こんな感じかな💦
ハイここも完了!

⒌Pickerの色を変更

ハイ、変更できた

⒍準備完了なので、以下のコードを組み込む

//サイズを返すメソッド
func pickerView(pickerView: UIPickerView, widthForComponent component:Int) -> CGFloat {
    
    //サンプル
    switch component {
        case 0:
            return 100
        case 1:
            return 50
        default:
            return 30
    }
}
//
//  ViewController.swift
//
import UIKit
class ViewController: UIViewController,UIPickerViewDelegate,UIPickerViewDataSource {
    @IBOutlet weak var testPickerView: UIPickerView!
    @IBOutlet weak var testLabel: UILabel!
    var timer:NSTimer = NSTimer()
    var count:Int = 0
    //時分秒のデータ
    let dataList = [[Int](0...24), [Int](0...60), [Int](0...60)]
    //最初からあるメソッド
    override func viewDidLoad() {
        super.viewDidLoad()
        //「時間」のラベルを追加
        let hStr = UILabel()
        hStr.text = "時間"
        hStr.sizeToFit()
        hStr.frame = CGRectMake(testPickerView.bounds.width/4 - hStr.bounds.width/2,
            testPickerView.bounds.height/2 - (hStr.bounds.height/2),
            hStr.bounds.width, hStr.bounds.height)
        testPickerView.addSubview(hStr)
        //「分」のラベルを追加
        let mStr = UILabel()
        mStr.text = "分"
        mStr.sizeToFit()
        mStr.frame = CGRectMake(testPickerView.bounds.width/2 - mStr.bounds.width/2,
            testPickerView.bounds.height/2 - (mStr.bounds.height/2),
            mStr.bounds.width, mStr.bounds.height)
        testPickerView.addSubview(mStr)
        //「秒」のラベルを追加
        let sStr = UILabel()
        sStr.text = "秒"
        sStr.sizeToFit()
        sStr.frame = CGRectMake(testPickerView.bounds.width*3/4 - sStr.bounds.width/2,
            testPickerView.bounds.height/2 - (sStr.bounds.height/2),
            sStr.bounds.width, sStr.bounds.height)
        testPickerView.addSubview(sStr)
    }
    //コンポーネントの個数を返すメソッド
    func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
        return dataList.count
    }
    //コンポーネントに含まれるデータの個数を返すメソッド
    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return dataList[component].count
    }
    //サイズを返すメソッド
    func pickerView(pickerView: UIPickerView, widthForComponent component:Int) -> CGFloat {
        return testPickerView.bounds.width * 1/4
    }
    //データを返すメソッド
    func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView
    {
        let pickerLabel = UILabel()
        pickerLabel.textAlignment = NSTextAlignment.Left
        pickerLabel.text = String(dataList[component][row])
        pickerLabel.backgroundColor = UIColor.redColor()
        return pickerLabel
    }
    //ボタン押下時の呼び出しメソッド
    @IBAction func startCountDown(sender: UIButton) {
        //すでに動いているタイマーは停止する
        timer.invalidate()
        //カウントダウンする秒数を取得する。
        count = dataList[0][testPickerView.selectedRowInComponent(0)] * 60 * 60
            +  dataList[0][testPickerView.selectedRowInComponent(1)] * 60
            +  dataList[0][testPickerView.selectedRowInComponent(2)]
        //1秒周期でcountDownメソッドを呼び出すタイマーを開始する。
        timer = NSTimer.scheduledTimerWithTimeInterval(1, target:self, selector:"countDown", userInfo:nil, repeats:true)        
    }
    //タイマーから呼び出されるメソッド
    func countDown(){
        //カウントを減らす。
        count--
        //カウントダウン状況をラベルに表示
        if(count > 0) {
            testLabel.text = "残り\(count)秒です。"
        } else {
            testLabel.text = "カウントダウン終了"
            timer.invalidate()
        }
    }    
}

と、ここのコードは長すぎるので、、、、
改修後だけをまとめて〜〜〜〜

コード

class PickerSecondsCountDownTimerViewController: UIViewController,UIPickerViewDelegate,UIPickerViewDataSource {
    @IBOutlet weak var myCountDownPicker: UIPickerView!
    @IBOutlet weak var myCountDownLabel: UILabel!
    var timer:Timer = Timer()
    var count:Int = 0
    //時分秒のデータ
    let dataList = [[Int](0...24), [Int](0...60), [Int](0...60)]
    override func viewDidLoad() {
        super.viewDidLoad()
        //「時間」のラベルを追加
        let hStr = UILabel()
        hStr.text = "時間"
        hStr.sizeToFit()
        hStr.frame = CGRectMake(
            myCountDownPicker.bounds.width/4 - hStr.bounds.width/2,
            myCountDownPicker.bounds.height/2 - (hStr.bounds.height/2),
            hStr.bounds.width, hStr.bounds.height)
        myCountDownPicker.addSubview(hStr)
        //「分」のラベルを追加
        let mStr = UILabel()
        mStr.text = "分"
        mStr.sizeToFit()
        mStr.frame = CGRectMake(
            myCountDownPicker.bounds.width/2 - mStr.bounds.width/2,
            myCountDownPicker.bounds.height/2 - (mStr.bounds.height/2),
            mStr.bounds.width, mStr.bounds.height)
        myCountDownPicker.addSubview(mStr)
        //「秒」のラベルを追加
        let sStr = UILabel()
        sStr.text = "秒"
        sStr.sizeToFit()
        sStr.frame = CGRectMake(
            myCountDownPicker.bounds.width*3/4 - sStr.bounds.width/2,
            myCountDownPicker.bounds.height/2 - (sStr.bounds.height/2),
            sStr.bounds.width, sStr.bounds.height)
        myCountDownPicker.addSubview(sStr)
    }
    //サイズを返すメソッド
    func pickerView(_ pickerView: UIPickerView, rowHeightForComponent component:Int) -> CGFloat {
        //サンプル
        switch component {
        case 0:
            return 100
        case 1:
            return 50
        default:
            return 30
        }
    }
    //コンポーネントの個数を返すメソッド
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return dataList.count
    }
    //コンポーネントに含まれるデータの個数を返すメソッド
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return dataList[component].count
    }
    //サイズを返すメソッド
    func pickerView(_ pickerView: UIPickerView, widthForComponent component:Int) -> CGFloat {
        return myCountDownPicker.bounds.width * 1/4
    }
    //データを返すメソッド
    func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
        let pickerLabel = UILabel()
        pickerLabel.textAlignment = NSTextAlignment.left
        pickerLabel.text = String(dataList[component][row])
        pickerLabel.backgroundColor = UIColor.red
        return pickerLabel
    }
    //ボタン押下時の呼び出しメソッド
    @IBAction func myStartContDown(_ sender: UIButton) {
        //すでに動いているタイマーは停止する
        timer.invalidate()
        //カウントダウンする秒数を取得する。
        count = dataList[0][myCountDownPicker.selectedRow(inComponent: 0)] * 60 * 60
        +  dataList[0][myCountDownPicker.selectedRow(inComponent: 1)] * 60
        +  dataList[0][myCountDownPicker.selectedRow(inComponent: 2)]
        //1秒周期でcountDownメソッドを呼び出すタイマーを開始する。
        timer = Timer.scheduledTimer(timeInterval: 1, target:self, selector:#selector(DateTimeViewController.countDown), userInfo:nil, repeats:true)
    }
    //タイマーから呼び出されるメソッド
    @objc func countDown(){
        //カウントを減らす。
        count -= 1
        //カウントダウン状況をラベルに表示
        if(count > 0) {
            myCountDownLabel.text = "残り\(count)秒です。"
        } else {
            myCountDownLabel.text = "カウントダウン終了"
            timer.invalidate()
        }
    }
}

⒎シミュレータを実行する

てな感じでちゃんと動く

サイト記事の内容は以上。。。

なんだけど、色々、気に入らないので〜〜〜〜
恒例の、、、

ブラッシュアップ

まず、

オイラはオレンジ背景に赤を重ねるのは、ミートソースを見てるみたいで
醜くて嫌い
(ボロネーゼ好きなイタリア人の血が流れていないせいか?)

なので、

緑に変更

次に、

個人的には、ここまでピッカーの項目が広くなくていいので、

こうでいい👀

さらに、

前回のラベルの初期設定が邪魔なので、、、

大分、らしくなってきた👀

さてとあとは、AutoLayoutだね。
前回同様、VerticalStackViewを使って一気に直す

てな感じで〜〜〜〜

てか、

区別しやすいようにPickerの背景をオレンジにしろってしただけだから、

元に戻して〜〜〜

そうすると、

正直、グリーンに変えたところも、別に設定なしの方が見やすくなるので、

こうした方がいい感じ👀
ハイ、動きました🕺

今回のコード(まとめ)

class PickerSecondsCountDownTimerViewController: UIViewController,UIPickerViewDelegate,UIPickerViewDataSource {
    @IBOutlet weak var myCountDownPicker: UIPickerView!
    @IBOutlet weak var myCountDownLabel: UILabel!
    var timer:Timer = Timer()
    var count:Int = 0
    //時分秒のデータ
    let dataList = [[Int](0...24), [Int](0...60), [Int](0...60)]
    override func viewDidLoad() {
        super.viewDidLoad()
        //「時間」のラベルを追加
        let hStr = UILabel()
        hStr.text = "時間"
        hStr.sizeToFit()
        hStr.frame = CGRectMake(
            myCountDownPicker.bounds.width/4 - hStr.bounds.width/2,
            myCountDownPicker.bounds.height/2 - (hStr.bounds.height/2),
            hStr.bounds.width, hStr.bounds.height)
        myCountDownPicker.addSubview(hStr)
        //「分」のラベルを追加
        let mStr = UILabel()
        mStr.text = "分"
        mStr.sizeToFit()
        mStr.frame = CGRectMake(
            myCountDownPicker.bounds.width/2 - mStr.bounds.width/2,
            myCountDownPicker.bounds.height/2 - (mStr.bounds.height/2),
            mStr.bounds.width, mStr.bounds.height)
        myCountDownPicker.addSubview(mStr)
        //「秒」のラベルを追加
        let sStr = UILabel()
        sStr.text = "秒"
        sStr.sizeToFit()
        sStr.frame = CGRectMake(
            myCountDownPicker.bounds.width*3/4 - sStr.bounds.width/2,
            myCountDownPicker.bounds.height/2 - (sStr.bounds.height/2),
            sStr.bounds.width, sStr.bounds.height)
        myCountDownPicker.addSubview(sStr)
    }
    //コンポーネントの個数を返すメソッド
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return dataList.count
    }
    //コンポーネントに含まれるデータの個数を返すメソッド
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return dataList[component].count
    }
    //サイズを返すメソッド
    func pickerView(_ pickerView: UIPickerView, widthForComponent component:Int) -> CGFloat {
        return myCountDownPicker.bounds.width * 1/4
    }
    //データを返すメソッド
    func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
        let pickerLabel = UILabel()
        pickerLabel.textAlignment = NSTextAlignment.left
        pickerLabel.text = String(dataList[component][row])
        return pickerLabel
    }
    //ボタン押下時の呼び出しメソッド
    @IBAction func myStartContDown(_ sender: UIButton) {
        //すでに動いているタイマーは停止する
        timer.invalidate()
        //カウントダウンする秒数を取得する。
        count = dataList[0][myCountDownPicker.selectedRow(inComponent: 0)] * 60 * 60
        +  dataList[0][myCountDownPicker.selectedRow(inComponent: 1)] * 60
        +  dataList[0][myCountDownPicker.selectedRow(inComponent: 2)]
        //1秒周期でcountDownメソッドを呼び出すタイマーを開始する。
        timer = Timer.scheduledTimer(timeInterval: 1, target:self, selector:#selector(DateTimeViewController.countDown), userInfo:nil, repeats:true)
    }
    //タイマーから呼び出されるメソッド
    @objc func countDown(){
        //カウントを減らす。
        count -= 1
        //カウントダウン状況をラベルに表示
        if(count > 0) {
            myCountDownLabel.text = "残り\(count)秒です。"
        } else {
            myCountDownLabel.text = "カウントダウン終了"
            timer.invalidate()
        }
    }
}

全部検証してないけど、これって元々のコードがなんか

ピッカーが動作を止めないうちに、カウントダウンボタンを押すと
out of indexとかにならないかな?

と怪しい気がするんだよね👀
てか元々カウントダウンタイマーで1時間以上って逆に要らなくないか?
って気がしなくもないけど。

まあそこまではいいかな💦
あって困るものではないし。

今回のポイント

開発中に、区別しやすいために便宜的にやってるデザイン変更なんかは、
機能が組み込み終わったら、柔軟にブラッシュアップで最後に直そう!
デザインとは、、、

引き算 = 余計なものは削ぎ落とす

の美学

さて、次回は

をレッツゴする〜〜〜〜!

今日は、

立て続けに4本の記事をランチ挟みながら作って、

一気にPickerView周りが終わった

けど、流石に

疲れた

ので。あとは、

  • 犬の散歩

  • 新聞

  • 嫁に晩飯の焼きそば作る

など、週末を満喫しまくる〜〜〜!!!

💃みなさんも良い週末を🕺

犬の散歩後〜

出来た〜
目玉焼きハート型にしたら
焼きそば隠れ過ぎー! 藁🤣


この記事が気に入ったらサポートをしてみませんか?