やりたいこと
デジタル時計を実装する。仕様は下記の通り。
- シークバーを操作して、時計の文字のサイズを変更できる。
- ボタン押下で、ミリ秒の表示ができる。
- ギャラリー内の写真を選択し、背景に好きな写真を設定できる。
実装
画面
<?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:id="@+id/constraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="serif"
android:text="時:分:秒"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.458" />
<SeekBar
android:id="@+id/skb"
android:layout_width="304dp"
android:layout_height="71dp"
android:layout_marginBottom="24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/milliSecond"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:text="ミリ秒"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Switch
android:id="@+id/switch1"
android:layout_width="134dp"
android:layout_height="52dp"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:text="文字サイズ"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/openPhotoGalleryBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="写真"
app:layout_constraintEnd_toStartOf="@+id/milliSecond"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textViewMilliSec"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="ミリ秒"
android:textSize="36sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
</androidx.constraintlayout.widget.ConstraintLayout>
メイン処理
package com.example.yamato200605c
import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.BitmapFactory
import android.icu.util.Calendar
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.view.View
import android.widget.ImageView
import android.widget.SeekBar
import android.widget.Toast
import androidx.annotation.RequiresApi
import kotlinx.android.synthetic.main.activity_main.*
import kotlin.concurrent.timer
class MainActivity : AppCompatActivity() {
@RequiresApi(Build.VERSION_CODES.O)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
skb.visibility = View.INVISIBLE
textViewMilliSec.visibility = View.INVISIBLE
milliSecond.setOnClickListener(object : View.OnClickListener {
override
fun onClick(view: View) {
textViewMilliSec.visibility = View.VISIBLE
}
})
switch1.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
skb.visibility = View.VISIBLE
} else {
skb.visibility = View.INVISIBLE
}
}
setupOpenPhotoGalleryButton()
setupSeekBar()
var millisecound: Boolean = true
handler(millisecound)
}
/**
* シークバーを設置する。
*/
@RequiresApi(Build.VERSION_CODES.O)
private fun setupSeekBar()
{
skb.progress = 10
skb.min = 35
skb.max = 80
skb.setOnSeekBarChangeListener(
object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
textView.textSize = progress.toFloat()
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
}
})
}
/**
* フォトギャラリーから戻ってきたときの処理。
*/
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
super.onActivityResult(requestCode, resultCode, resultData)
if (resultCode != RESULT_OK) {
return
}
when (requestCode) {
READ_REQUEST_CODE -> {
try {
resultData?.data?.also { uri ->
val inputStream = contentResolver?.openInputStream(uri)
val image = BitmapFactory.decodeStream(inputStream)
var iv: ImageView = ImageView(applicationContext)
iv.setImageBitmap(image)
constraintLayout.background = iv.drawable
}
} catch (e: Exception) {
Toast.makeText(this, "エラーが発生しました", Toast.LENGTH_LONG).show()
}
}
}
}
/**
* フォトギャラリーを開くためのボタンを設置する。
*/
private fun setupOpenPhotoGalleryButton()
{
openPhotoGalleryBtn.setOnClickListener(object : View.OnClickListener {
override
fun onClick(view: View) {
openPhotoGallery()
}
})
}
/**
* Android端末のフォトギャラリー(写真を保存している内部フォルダ)を開く。
*/
private fun openPhotoGallery() {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "image/*"
}
startActivityForResult(intent, READ_REQUEST_CODE)
}
companion object {
private const val READ_REQUEST_CODE: Int = 42
}
/**
* 時計の表示を更新する。引数でtrueを受け取るとミリ秒まで表示する。
*/
@SuppressLint("SetTextI18n")
@RequiresApi(Build.VERSION_CODES.N)
private fun handler(millisecound: Boolean)
{
var periodNum: Long = 1000 // 1秒ごとに更新する。
if (millisecound) {
periodNum = 10
}
val handler = Handler()
timer(name = "tm", period = periodNum) {
val calendar = Calendar.getInstance()
val hour = calendar.get(Calendar.HOUR_OF_DAY)
val hourPad: String = hour.toString().padStart(2, '0')
val minute = calendar.get(Calendar.MINUTE)
val minutePad = minute.toString().padStart(2, '0')
val second = calendar.get(Calendar.SECOND)
val secondPad: String = second.toString().padStart(2, '0')
val millisecond = calendar.get(Calendar.MILLISECOND) / 10
val millisecondPad = millisecond.toString().padStart(2, '0')
handler.post {
if (millisecound) {
textView.text = "${hourPad}:${minutePad}:${secondPad}"
textViewMilliSec.text = "${millisecondPad}"
} else {
textView.text = "${hourPad}:${minutePad}:${secondPad}"
}
}
}
}
}