どうも!LSSです!
ちょっと久々に「カウントダウンタイマー&ストップウォッチ」の続きになります。
(カウントダウンする分・秒を設定できるようにします)
今回は↓この本で見かけた「NumberPicker」というものを試してみます。
なお、「カウントダウンタイマー&ストップウォッチ」について過去に書いた記事はこちら! little-strange.hatenablog.com
目次
- 今回のキモ!
- NumberPickerって?
- xmlへの組み込み方
- NumberPicker、設定は?
- Kotlinで初期設定!
- NumberPickerで設定した数値をタイマーの待ち時間として使用
- 以上で、あっさり完成です!
- 一応、コード全文のせときますね
今回のキモ!
以下、「n0」は任意の名前、好きに変えちゃってOK!な部分です。
xml内、NumberPickerを配置したい場所に記述
<NumberPicker
android:id="@+id/n0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
onCreate内で、最小値・最大値・初期値を設定
n0.minValue=0 // 分の最小値
n0.maxValue=99 // 分の最大値
n0.value=3 // 分の初期値
NumberPickerの値を取り出す
n0.value
NumberPickerって?
AndroidStudioのPaletteの中に…
…いないんですよね。なぜか。
まず、どういうものかというと、
こういう、縦スワイプで数字を選ぶやつです。
…なぜか、これを見ると金庫の暗証番号を連想してしまいますwww
xmlへの組み込み方
xmlのデザイン編集ではPalleteにいないので、テキスト編集のほうで書きます。
配置したい部分に
<NumberPicker
android:id="@+id/n0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
のように書くだけでOKです!
上記画面写真の例だと、NumberPickerを2つ、その間にTextViewで:を挟んでいるので…
<NumberPicker
android:id="@+id/n0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text=":" />
<NumberPicker
android:id="@+id/n1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
このように書きました^^
左のNumberPickerに「n0」、右のNumberPickerに「n1」ってidを振ってます。
この「n0」「n1」は任意の名前、好きに変えちゃってOK!な部分です。
NumberPicker、設定は?
さて、このNumberPicker、少なくとも「最大値」「最小値」「既定値」の設定がありそうなものですが、Attributesの中に …
…これまた、いないんですよね。
なお、この 「最大値」「最小値」「既定値」については、Palleteの中にいなかったように
AndoidStudioが陰険な継子イジメをしているわけではなくて、
元々、xml上では設定できないようです。
なので、Kotlinから「最大値」「最小値」「既定値」を設定してあげます。
Kotlinで初期設定!
設定はとても簡単です。
…最近、lateinitしたり、最後にreleaseしたりばっかりだったのでなんかことさら簡単に感じてしまいましたw
onCreateの中に、以下のコードを書きます。
n0.minValue=0
n0.maxValue=99
n0.value=3
n1.minValue=0
n1.maxValue=59
n1.value=0
minValueが最小値、maxValueが最大値、valueが既定値(最初に入ってる値)
って事になります。
この例だと99:59まで設定できるようにした、って事になります。
NumberPickerで設定した数値をタイマーの待ち時間として使用
…極力、手間のかからない方法を選択しましたw
以下、赤文字で示す行が、今回追加した処理になります。(わずか1行!)
// START・STOPボタンを押した時の処理
fun btSclk(v:View){
if (tflag) { // tflagはタイマー作動中はtrue、停止中はfalse
// 作動中にSTOPが押された場合の処理
tflag=false
btS.text="START"
rt0.stop() // Ringtone(音)を止める
vb0.cancel() // Vibratorを止める
hnd0.removeCallbacks(rnb0) // handlerタイマー処理をキャンセル
}else{
// 停止中にSTARTが押された時の処理
tflag=true
btS.text="STOP"
cntF=true
CntT=n0.value * 60+n1.value
cld0.timeInMillis=System.currentTimeMillis() //STARTが押された時の時刻値をcld0にセット
hnd0.post(rnb0) // handlerタイマー処理を開始
}
}
拙作のカウントダウンタイマー&ストップウォッチは
「CntTという変数にカウントダウン秒数を代入して使用する仕様(ダジャレじゃないよ!)」
だったので、そのCntTに各NumberPickerの値(.value)を取り出し、秒に換算してタイマー処理を開始する、というだけの話です。
以上で、あっさり完成です!
っと、NumberPickerにも、変更された時に発動するイベントリスナーとかありますが、今回はそれを使わずに簡単に利用する方法を試してみました!
これで、熱湯5分の
が、自作タイマーアプリで作れます!!(まだ言うかwww)
一応、コード全文のせときますね
package jp.littlestrangesoftware.mytech
import android.content.Context
import android.content.pm.ActivityInfo
import android.media.Ringtone
import android.media.RingtoneManager
import android.net.Uri
import android.os.*
import androidx.appcompat.app.AppCompatActivity
import android.view.View
import kotlinx.android.synthetic.main.activity_timer.*
import java.util.*
class timerActivity : AppCompatActivity() {
var cld0=Calendar.getInstance() // 計測開始時の時刻値 保管用
var cld1=Calendar.getInstance() // 現在の時刻値 保管用
var tflag=false // タイマー動作中はtrueになるフラグ
var cntF=true // カウントダウン未終了フラグ
var CntT=180 // カウントダウン用の時間を秒で指定
lateinit var ur0:Uri // Uriを宣言
lateinit var rt0:Ringtone // Ringtoneを宣言
lateinit var vb0:Vibrator // Vibratorを宣言
val vbpt0= longArrayOf(0,150,50,150,50,150,50,350,50,350,50,350,50) // Vivratorのパターンを作成
val hnd0=Handler() // Handlerを作成
val rnb0=object:Runnable{
override fun run() {
cld1.timeInMillis=System.currentTimeMillis() // 現在の時刻値をミリ秒で取得
var i=CntT+((cld0.timeInMillis-cld1.timeInMillis)/1000).toInt() // 残り秒数
// カウントダウンが完了している場合
if (i<0) {
i = 0
// カウントダウン終了後に1回だけ行う
if (cntF){
cntover() // 処理内容を書いた別のfunを呼び出す
cntF=false // フラグをfalseにする事で連続動作を防止
}
}
// カウントダウンタイマーの表示
tvCntD.text="%02d:%02d".format(i/60,i%60)
// ストップウォッチの表示
tv0.text="%.2f".format((cld1.timeInMillis-cld0.timeInMillis).toFloat()/1000)
hnd0.postDelayed(this,10) // 0.01秒後にこの処理を再度呼び出し
}
}
// カウントダウン終了後に行う処理
fun cntover(){
rt0.play() // Ringtone(音)を鳴らす
// 端末にVibrator機能がある場合
if(vb0.hasVibrator()){
vb0run()
}
}
// Vibratorを振動させる
fun vb0run(){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ // Android8.0以降の場合
vb0.vibrate(VibrationEffect.createWaveform(vbpt0,0))
}else{ // Android8.0未満の場合
vb0.vibrate(vbpt0,0)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_timer)
requestedOrientation =ActivityInfo.SCREEN_ORIENTATION_PORTRAIT // 縦画面に固定
ur0=RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM) // uriを設定
rt0=RingtoneManager.getRingtone(this,ur0) // Ringtoneを設定
vb0= getSystemService(Context.VIBRATOR_SERVICE) as Vibrator // Vibratorを設定
n0.minValue=0 // 分の最小値
n0.maxValue=99 // 分の最大値
n0.value=3 // 分の初期値
n1.minValue=0 // 秒の最小値
n1.maxValue=59 // 秒の最大値
n1.value=0 // 秒の初期値
}
// START・STOPボタンを押した時の処理
fun btSclk(v:View){
if (tflag) { // tflagはタイマー作動中はtrue、停止中はfalse
// 作動中にSTOPが押された場合の処理
tflag=false
btS.text="START"
rt0.stop() // Ringtone(音)を止める
vb0.cancel() // Vibratorを止める
hnd0.removeCallbacks(rnb0) // handlerタイマー処理をキャンセル
}else{
// 停止中にSTARTが押された時の処理
tflag=true
btS.text="STOP"
cntF=true
CntT=n0.value * 60+n1.value // NumberPickerからカウントダウンタイマーの初期秒数を設定
cld0.timeInMillis=System.currentTimeMillis() //STARTが押された時の時刻値をcld0にセット
hnd0.post(rnb0) // handlerタイマー処理を開始
}
}
override fun onDestroy() {
rt0.stop() // Ringtone(音)を停止
vb0.cancel() // Vibratorを止める
hnd0.removeCallbacks(rnb0) // handlerタイマー処理をキャンセル
super.onDestroy()
}
}
では、今回はここまで!
次回もまたよろしくお願いいたします^^