【はじめてのKotlinプログラミング(24)】CountDownTimer(前編)

kotlinで、簡単なカウントダウンタイマーアプリをつくってみたいと思います。

後編はこちら

おまけ編はこちら

 

動画

【目次】

01:40 xml
06:55~
1)viewの取得
2)ボタンの有効・無効

12:20~
3)スタートボタン
4)カウントダウンタイマー

16:05~
4-1)途中経過・残り時間
4-2)終了設定

18:10~ 5)スタートボタン
19:55~ 6)ストップボタン

アラーム音:効果音ラボ「目覚まし時計のアラーム」

コード

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="00:00"
        android:textSize="50sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btnStart"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="START"
        app:layout_constraintEnd_toStartOf="@+id/btnStop"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv" />

    <Button
        android:id="@+id/btnStop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="STOP"
        app:layout_constraintEnd_toStartOf="@+id/btnRestart"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btnStart"
        app:layout_constraintTop_toBottomOf="@+id/tv" />

    <Button
        android:id="@+id/btnRestart"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="RESTART"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btnStop"
        app:layout_constraintTop_toBottomOf="@+id/tv" />

    <Button
        android:id="@+id/btnReset"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="RESET"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.kt

package com.example.simplecountdown

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.CountDownTimer
import android.widget.Button
import android.widget.TextView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //1)開始時間を設定
        val startTime:Long = 10000 //10秒

        //1)viewを取得+tvに開始時間を表示
        val tv:TextView =findViewById(R.id.tv)
        val btnStart:Button =findViewById(R.id.btnStart)
        val btnStop:Button =findViewById(R.id.btnStop)
        val btnRestart:Button =findViewById(R.id.btnRestart)
        val btnReset:Button =findViewById(R.id.btnReset)
        tv.text ="${startTime/1000}" //開始時間を秒で表示

        //2)ボタンの有効・無効(リセットボタンはずっと有効なので触らず)
        btnStart.isEnabled = true
        btnStop.isEnabled = false
        btnRestart.isEnabled = false

        //4)カウントダウンタイマーのオブジェクトを用意
        val timer = object :CountDownTimer(startTime,100){
            //[4-1]途中経過・残り時間
            override fun onTick(p0: Long) {
                //TODO("Not yet implemented")
                //残り時間を表示
                tv.text ="${p0/1000}" //秒単位
            }
            //[4-2]終了設定
            override fun onFinish() {
                //TODO("Not yet implemented")
                tv.text ="タイムアップ"

                //スタートボタンだけ有効
                btnStart.isEnabled = true
                btnStop.isEnabled = false
                btnRestart.isEnabled = false
            }

        }

        //3)スタートボタンを押したらカウントダウン
        btnStart.setOnClickListener {
            //5)「4」のtimerをスタート
            timer.start()

            btnStart.isEnabled = false
            btnStop.isEnabled = true
            btnRestart.isEnabled = false
        }

        //6)ストップボタンを押した時の処理
        btnStop.setOnClickListener {
            timer.cancel()

            //ストップボタンを無効化
            btnStart.isEnabled = true
            btnStop.isEnabled = false
            btnRestart.isEnabled = true
        }

    }
}

テキスト

kotlinで、簡単なカウントダウンタイマーアプリをつくってみたいと思います。完成見本としては

——————————————–
今、開始時間が10秒と設定されています。
スタートボタンを押すと、カウントダウンが開始され・・・

ストップで止まる・・・。

で、リスタートボタンを押すと、続きから開始。

カウントが0になると、タイムアップと表示されて
アラーム音が鳴る、
——————————————–

というものです。

今回の主な学習のテーマはもちろんCountDownTimer()なんですけども
ちょっと今回は
前編、後編、そしておまけと、3部作でいきたいと思います。

今回の前編で、スタートとストップを実装します。

(XMLは割愛)

01-02)viewとボタンの有効化

それではプログラミングをやっていきましょう。
ktを開いてください。
まずはいつものようにviewを取得していきます。
取得するのはテキストビューが1つと、ボタンが4つ、合計5つですね。

まずは名前をtvとかにしてあげて、こちらの方はテキストビュー

//1)viewを取得
       val tv: TextView =findViewById(R.id.tv)
        val btnStart:Button = findViewById(R.id.btnStart)
        val btnStop:Button=findViewById(R.id.btnStop)
        val btnRestart:Button =findViewById(R.id.btnRestart)
        val btnReset:Button=findViewById(R.id.btnReset)

それからボタンの有効・無効もしてあげましょう。
起動直後はスタートボタンだけ有効で、残りの2つは無効にしたいので

        //2)ボタンの有効・無効(リセットボタンはずっと有効なので触らず)
        btnStart.isEnabled = true
        btnStop.isEnabled = false
        btnRestart.isEnabled= false

これでいったんエミュレータを起動して、
ボタンの有効・無効だけ確認してみましょう。

はい、起動直後はスタートボタンだけが押せるようになっています。

**************************************
それから、この流れで、開始時間を設定して、テキストビューに表示もしてみましょう。
ひとまず1番のところに並べて。
開始時間を設定しましょう。一応今回は10秒でいきたいと思います。

まずはvalとしてあげて、名前を用意してあげましょう。
開始時間なのでstartTimeとしてあげて、ここは数字なのでIntとしたいところなんですが
桁数を多く扱うことのできるLongにします。

何故かというと、プログラミングの世界では、時間を表す単位はミリ秒なので
1000とかいて、これで1秒になります。
10秒としたいばやい、10000このようになります。

なのでintではなくてLongを使います。

val startTime:Long =10000 //10秒

これ、0が多くなって、何秒かわからなくなったらですね、
千単位のところで、10.000このように区切ってあげると、点より前の数字をみたら
お、10秒だなとわかるのでおすすめです。
自分で確認したら、直しておきましょう10000。

それではこれを開始時間ということでテキストビューに表示したいわけですが
tv.text = “”
このまま表示すると startTime 当然1万って表示されてしまうので
1000で割ってあげましょう。あとは、波カッコでくくってあげて、
変数の前にダラーマークを忘れないようにしてあげてください。

tv.text = “${startTime/1000}” //開始時間を秒で表示

これで、1万÷1000で、10秒と表示されるはずなので見てみましょう。

はい、ちゃんと開始時間と表示されているのがわかります。

それではいよいよ、スタートボタンをおしたら、
カウントダウンされるように、今回の本丸、CountDownTimer()を動かしていきましょう。

03)スタートボタンとカウントダウン

それではスタートボタンを押した時の処理を書いていきましょう。
2番の下に書いていきます。スタートボタンを押した時、ということなので

//3)スタートボタンを押したらカウントダウン
btnStart.setOnClickListener {
}

で、この中にカウントダウンタイマーのスタート処理をしていきたいんですが。
このあと、この下にストップボタンを押した時には、タイマーをキャンセルさせるので
ひとまず上に、変数を用意して、その中にカウントダウンタイマーを作っておきます。

てことで、3番の上に

//4)カウントダウンタイマーのオブジェクトを用意

valとしてあげて、名前はとりあえず timer とかにしてあげましょう。

val timer = object :CountDownTimer(){
}

そうしたらobjectのところにエラーが出てくるので・・・

・・・objectってのは厳密にいうと、無名クラスを作るときの構文なんですが
まあCountDownTimerの決まり文句だと思っておいてください。

で、objectにエラーが出てるのでマウスをあてて、左のワーニングから
implement members、
implementってのは埋め込むって意味なんですけど
メンバーを埋め込みましょうということなのでクリック。

で2つ用意されています。

onTickっていのは途中経過。残り時間。
onFinishってのは文字とおり終了。

てことで、どちらも使うので、両方を選択してOK。

これでもろもろ揃いました。
onTickっていうのは
//[4-1]途中経過・残り時間
チックタック、チックタック、のことですね。

onFinishの方はもちろん
//[4-2]終了設定
ということです。

あとはCountDownTimer()の中に、これらの開始時間と、
インターバル、更新の区切り時間を設定してあげます。

開始時間は10秒なので10に03つ。10,000。コンマは消してください10000。
インターバルは、何秒ごとに更新しますかってことなので0.1秒ごと、ということで
CountDownTimer(10000,100)
このように書いてあげればいいんですが
今回は先ほど変数を用意したので、変数で使っていきます。

CountDownTimer(startTime,100)

これで開始の時間は10秒、インターバルは0.1秒なので
0.1秒ごとにチックタック、チックタック、されて、、
時間が終了するとonFinish()が呼び出されると
いう設定になりました。

あとは、途中経過と終了設定をしていきましょう。

04)onTickとonFinish

ひとまずこのTODOってのは要らないので両方とも決しておいてください

で、1つ説明しておくと、onTickの方に、何やらLong型で1つ入っています。
p0

これは残り時間のことです。

これが(startTime)開始時間。
これが(p0)残り時間。

ていうのがわかったら、onTickが動いたら,テキストビューに残り時間を表示させてあげましょう。
上のtv.text ~ を丸丸コピーして
貼り付け。

開始時間ではなくってp0。
残り時間を秒単位で表示

tv.text = “${p0/1000}” //秒単位

***********************************

最後に onFinish を書いたら完成です。

まず、終了したらテキストビューに タイムアップ と表示させましょう。

tv.text = “タイムアップ”

それから有効無効ですが。
時間が終了したら、スタートもストップも関係ないので、本来はリセットボタン以外は全て無効でいいと思うんですが、今回はリセットボタンは実装しないので、いったんスタートボタンだけ有効化にしておきましょう。

2番を使いましょうか。これらをコピーして、スタートボタンだけtrueにしてあげます。

               btnStart.isEnabled = true
                btnStop.isEnabled = false
                btnRestart.isEnabled= false

これでカウントダウンタイマー、途中経過、終了時、もろもろの設定が完了です。

あとはスタートボタンを押したらスタート、
ストップボタンをおしたらキャンセルにすれば完成です。

05)スタートボタン

それでは今作った timer を使って
スタートボタンを押した時、
ストップボタンを押した時、を書いていきましょう。

まずスタートボタンを押したら
//5)「4」のtimerをスタート

タイマーをスタート。

timer.start()

スタートしたら、(xml)あとはストップボタンだけ有効化したいので
両サイドは無効化ですね。
てことで、false true false と。

            btnStart.isEnabled = false
            btnStop.isEnabled=true
            btnRestart.isEnabled = false

ひとまずこれでエミュレータを起動して、
スタートを押したらカウントダウンが開始されるかどうか確認してみましょう。

今はスタートボタンだけ押せるようになっています。
スタートを押したらカウントダウンが開始されて、
ストップボタンが押せるようになっているはずなので押してみましょう。

はい、こうですね。カウントが開始されました。
終了したらタイムアップも表示されているようです。

今はリセットボタンは作ってないので何も起きませんが、
その代わり、スタートボタンを押すと、また最初からカウントダウンが開始されるようになっています。
ただし今はストップを押しても止まらないので、最後にストップボタンを書いたら終了です。

06)ストップボタン

それでは最後、ストップボタンを書いてあげましょう。
スタートボタン波カッコの下に書いていきます。

//6)ストップボタンを押した時の処理
btnStop.setOnClickListener { 

}

まずはタイマーをキャンセルなので

timer.cancel()

それからストップボタンを無効化させたいので

//ストップボタンを無効化
btnStart.isEnabled = true
btnStop.isEnabled=false
btnRestart.isEnabled = true

 

以上ですね。
ではエミュレータを起動して、確認してみましょう。

スタートを押して、ストップ。
はい、こんな感じで、ストップボタンを押したら、
タイマーがキャンセルされて、ストップボタンが無効化されているのがわかります。

今はリスタートボタンもリセットも押せないわけですが、
スタートボタンは押せるのでひとまず毎回、最初からではありますがスタートさせることはできます。

で、タイムアップと。

**************************************************
これでひとまず、これら2つリスタートとリセットのボタンはともかく
スタートとストップは出来るようになりました。

カウントダウンタイマーの使い方自体は、これで終了なので、
後半は、これの応用で、
「途中からスタート」
そしてリセットボタンを押したら元に戻る、というのを解説したいと思います。

    コメントを残す