![見出し画像](https://assets.st-note.com/production/uploads/images/100562251/rectangle_large_type_2_e443d42343db1196e63c23a5f67a42c8.png?width=1200)
【徒然iOS】気ままにUIKit48〜Picker Viewを使って、秒も設定できるカウントダウンタイマーを作る。〜
概要
このマガジンは四十を過ぎたおっさんが、
を参考にStoryboardでiOSアプリを完全に趣味で楽しんでいるだけな記事を気ままに上げてます。
今回
をハイ、レッツゴ🕺
前準備
今回は、前回のビューの続きにはめ込もうかなと考えたけど、よく考えたらPickerViewがコードで管理されて、データが分割できないので、新しいビューをいつもどおり作ることにした💦
念の為、
バックアップ
新しいクラス
ビューコントローラの追加
イニシャルビューの変更
をいつも通りやってから本題へ💃
![](https://assets.st-note.com/img/1679120598719-shwWtR2Zra.png?width=1200)
本題
まあ、解説がつらつらと書かれてるけど、
要は、
前々回のカウントダウンタイマーだと、
秒まで表示できないから〜〜〜
ってことが言いたいことは理解した!
⒈前回の機能を別ビューで用意
![](https://assets.st-note.com/img/1679120834825-Y5p1UEXINJ.png?width=1200)
![](https://assets.st-note.com/img/1679120883586-K9h9aIsmi8.png?width=1200)
では、今回の操作をやっていこうっと〜〜〜
⒉ボタンを配置する
アトリビュートインスペクタボタンを押して設定画面を表示。
Titleにカウントダウン開始
Text Colorを白
Backgroundに青
を設定。
てことなんで、言われたとおり。
![](https://assets.st-note.com/img/1679121070018-HYjHgoEXTg.png?width=1200)
⒊ボタンを以下の設定でアクション接続
ConnectionにAction
NameにstartContDown
TypeにUIButton
EventにTouch Up Inside
![](https://assets.st-note.com/img/1679121198030-4rPdYMzRh2.png?width=1200)
![](https://assets.st-note.com/img/1679121222243-4wNUrWRbgM.png?width=1200)
⒋ピッカービューをアウトレット接続
ConnectionにOutlet
NameにtestPickerView
![](https://assets.st-note.com/img/1679121351668-GgeBVWT6mA.png?width=1200)
![](https://assets.st-note.com/img/1679121373410-dPmCTl5TYv.png?width=1200)
⒌Pickerの色を変更
![](https://assets.st-note.com/img/1679121443444-Z7F8M4igY4.png?width=1200)
⒍準備完了なので、以下のコードを組み込む
//サイズを返すメソッド
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()
}
}
}
⒎シミュレータを実行する
![](https://assets.st-note.com/img/1679122792135-O4Io81dpbW.png?width=1200)
サイト記事の内容は以上。。。
なんだけど、色々、気に入らないので〜〜〜〜
恒例の、、、
ブラッシュアップ
まず、
オイラはオレンジ背景に赤を重ねるのは、ミートソースを見てるみたいで
醜くて嫌い
(ボロネーゼ好きなイタリア人の血が流れていないせいか?)
なので、
![](https://assets.st-note.com/img/1679123053274-kAidjHCH8g.png?width=1200)
次に、
個人的には、ここまでピッカーの項目が広くなくていいので、
![](https://assets.st-note.com/img/1679123169851-vdhaxFUZR0.png?width=1200)
さらに、
前回のラベルの初期設定が邪魔なので、、、
![](https://assets.st-note.com/img/1679123251724-l5TUcfI8jm.png?width=1200)
さてとあとは、AutoLayoutだね。
前回同様、VerticalStackViewを使って一気に直す
![](https://assets.st-note.com/img/1679123398108-FEVTMr7SND.png?width=1200)
てか、
区別しやすいようにPickerの背景をオレンジにしろってしただけだから、
![](https://assets.st-note.com/img/1679123473479-P49c2HbvMU.png?width=1200)
そうすると、
正直、グリーンに変えたところも、別に設定なしの方が見やすくなるので、
![](https://assets.st-note.com/img/1679123565531-MVTNtcxRU5.png?width=1200)
![](https://assets.st-note.com/img/1679123676329-MPhmjfFtgt.png?width=1200)
今回のコード(まとめ)
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周りが終わった
けど、流石に
疲れた
ので。あとは、
犬の散歩
新聞
嫁に晩飯の焼きそば作る
など、週末を満喫しまくる〜〜〜!!!
💃みなさんも良い週末を🕺
犬の散歩後〜
![](https://assets.st-note.com/production/uploads/images/100580772/picture_pc_c876ccebed8299ee36b8067212df2c90.jpg?width=1200)
目玉焼きハート型にしたら
焼きそば隠れ過ぎー! 藁🤣