Little Strange Software

スマホアプリの開発を行う LittleStrangeSoftware のブログです。

Androidアプリ開発初心者がkotlinでカラーピッカーを作ってみるよ! その14

 どうも!LSSです!

 

 今回は前回の続きで、履歴色を記録する部分を作っていきますよ!

 

 

 

まず、仕様から!

  • 一つめの「お気に入りの色」とは別に、数秒以上変更を加えなかった色は自動的に、それ用の履歴として記録する。

とは決まっていますが、もうちょっと煮詰めていきます!

 

  1. まず、「数秒以上」の部分は「10秒以上」とします。
  2. 判定に当たっては、0.1秒毎にループするタイマー処理を使用します。
  3. 処理実行時に、別途変数に記録しておいた「さっきの色」と、現在のcl[0]、cl[1]、cl[2]から算出した「現在の色」ifで比較します。
  4. 「さっきの色」「現在の色」が同一だった場合、まずカウント用変数を+1します。
  5. さらに、カウント用変数が100に達した場合(10秒たった場合)、まず、「最後に記録した色」SQLiteデータベースから読み込み、「最後に記録した色」を扱う変数に代入します。
  6. 「現在の色=さっきの色」「最後に記録した色」ifで比較します。
  7. 「現在の色=さっきの色」「最後に記録した色」が異なる場合、「さっきの色」「最後に記録した色」変数に代入します。
  8. さらに「最後に記録した色」SQLiteデータベースに記録します。
  9. カウント用変数に0を代入します。
  10. 6.のifで「同一」だった場合は何もしません。
  11. 4.のifで「同一でなかった」場合は、カウント用変数を0にし、「さっきの色」変数に、「現在の色」を代入します。
  12. 最後にifがどうであれ、次のループを呼び出して終わりです。

 

…と、こういう処理で考えている動作になりそうです。

 こういうの、文章で書くと伝わるのに限界がありますね^^;
 フローチャートみたいのを書くのがいいですね。

 

 

新たに用意する、必要な変数

「現在の色」 はcl[0]、cl[1]、cl[2]から算出するだけなので、今回は用意しません。

 

 他に必要なものとして、

 

カウント用変数…「cnt」って名前でInt型変数を用意する事にします。

さっきの色…「lastcl」って名前でInt型変数を用意する事にします。

最後に記録した色…「lastrc」って名前でInt型変数を用意する事にします。

 

  これだけでいけそうですね。
 あとはタイマー処理にHandlerRunnableが必要になるぐらいで。

 

 

MainActivity.ktの編集を始めます!

  いつものように、MainActivity.ktの編集をしていきますね。

f:id:little_strange:20191012183859p:plain

 

 まず、変数の宣言ですが、今の変数宣言の最後がSQLoh0なので、その次の行ぐらいから始める事にします。

 

var lastrc=0
var lastcl=0
var cnt=
0

の3行を追記します。

f:id:little_strange:20191012184305p:plain

↑こんな感じですね。

 

 

次に、パーツとなるfunを先に作ります!

 必要なものは2つ。
COLORRCに記録する
COLORRCから最新の1色だけを取り出す
です。

 

 まず記録する部分から手をつけます。
…これも、前回の読み込みと同様、すでに書いた「COLORSVへの記録」と似たコードになるので、

f:id:little_strange:20191012185055p:plain

以前に書いた、

fun btSave(v:View){

のあるあたりまで画面をスクロールします。

 そしてその、

 

fun btSave(v:View){
val dbW=sqloh0.writableDatabase
val cldr=Calendar.getInstance()

var SQLstr=dbW.compileStatement("INSERT INTO COLORSV ( SV , SVTIME ) VALUES ( ? , ? )")
SQLstr.bindString(1,(cl[0]*256*256+cl[1]*256+cl[2]).toString())
SQLstr.bindString(2,cldr.timeInMillis.toString())
SQLstr.executeInsert()
}

 

を選択し、コピーします。

f:id:little_strange:20191012185314p:plain

画面でいうと、↑こういう状態です。

 で、それを、すぐあとにペーストします。

f:id:little_strange:20191012185459p:plain

↑こうなります。

 

 今回はこの2つあるうち、下のほうのものを、
COLORRCに記録する
用に書き換えていきます!

 

fun btSave(v:View){
    val dbW=sqloh0.writableDatabase
    val cldr=Calendar.getInstance()
    var SQLstr=dbW.compileStatement("INSERT INTO COLORSV ( SV , SVTIME ) VALUES ( ? , ? )")
    SQLstr.bindString(1,(cl[0]*256*256+cl[1]*256+cl[2]).toString())
    SQLstr.bindString(2,cldr.timeInMillis.toString())
    SQLstr.executeInsert()
}

 

 書き換える部分を赤字で示すと↑の部分になります。

btSave(v:VIEW)rcSave()に打ち換えます。

SV…3つともRCに打ち換えます。

(cl[0]*256*256+cl[1]*256+cl[2])lastrcに打ち換えます。

 

以上で、「COLORRCに記録する」部分は完成!

 

 画面は 

f:id:little_strange:20191012190326p:plain

こんな風になります。

 

 

 続けて、

COLORRCから最新の1色だけを取り出す

部分を作ります。

 これは前回作った、COLORRCの読み込み部分と似ているので、

f:id:little_strange:20191012190749p:plain

この、

fun btRCTclk(v:View){
val dbR=sqloh0.readableDatabase
val cursor=dbR.rawQuery("select RC , RCTIME from COLORRC order by RCTIME desc",null)


for (i in 0..15){
if (cursor.moveToNext()){
btcl[i]=cursor.getInt(cursor.getColumnIndex("RC"))
btns[i].setBackgroundColor(255*256*256*256+btcl[i])
}else{
btcl[i]= 0
btns[i].setBackgroundColor(255*256*256*256)

}
}
cursor.close()
}

 

をまた、コピーし、ペーストします。

 

f:id:little_strange:20191012191148p:plain

↑こうなります。

 

 さて、今度は上のほうのやつを書き換える事にします!

 

fun btRCTclk(v:View){
    val dbR=sqloh0.readableDatabase
    val cursor=dbR.rawQuery("select RC , RCTIME from COLORRC order by RCTIME desc",null)

    for (i in 0..15){
        if (cursor.moveToNext()){
            btcl[i]=cursor.getInt(cursor.getColumnIndex("RC"))
            btns[i].setBackgroundColor(255*256*256*256+btcl[i])
        }else{
            btcl[i]= 0
            btns[i].setBackgroundColor(255*256*256*256)
        }
    }
    cursor.close()
}

 

 今度は、
「バッサリ削除する分を緑字+取り消し線
「書き換える部分を赤字
で示してみました。

 まず、緑部分バッサリ削除してしまってから…

btRCTclklastrcLoadに打ち換えます。

desc"c"の間に、まずスペースを一つ開けてからlimit 1を追記します。
   desc limit 1"
    となります。

NextFirstに打ち換えます。

btcl[i]…2つともlastrcに打ち換えます。

 

 以上です!

画面は、 

f:id:little_strange:20191012195048p:plain

 こんな感じになります。

 

 さて!本日のメインイベント!!タイマー処理を書いていきます!

 

 パーツの用意が出来たところで、いよいよ、それらを利用するタイマー処理の部分を書いていきます!

 タイマーについては以前、こちらの記事でも書きましたので、良かったら見てください^^

 

 画面はまた、最初に変数宣言したあたりまでスクロールで戻しておきます。 

f:id:little_strange:20191012223524p:plain

 この、cntの後に続けて書いていきますね。

 

 まずは、
var hnd0=Handler()
と入力します。が、途中で、

f:id:little_strange:20191012223852p:plain

こんな候補が出てくるので、Handler複数ありますが、ここはとりあえずandroid.os)とつくものを選択しておきます。

 補完されたHandlerには()がついていなかったので、付け足しておきます。

 

 

 続けて、 

var rnb0=object : Runnable{
override fun run() {
if (cl[0]*256*256+cl[1]*256+cl[2]==lastcl){
cnt++
if(cnt>=100){
lastrcLoad()
if(lastcl!=lastrc){
lastrc=lastcl
rcSave()

cnt=0
}

}
}else{
cnt=0
lastcl=cl[0]*256*256+cl[1]*256+cl[2]

}
hnd0.postDelayed(this,100)
}
}

…を、ちょっと長いですがガシガシと打ち込みます。
※今回の記事の冒頭の1~12をkotlinに翻訳するとこんな感じになります。

 

  最後の
hnd0.postDelayed(this,100)

で、2回目以降、100ミリ秒ごとに再度処理されるのですが、一番最初の起動がまだ書いていないので、

f:id:little_strange:20191012230041p:plain

onCreate内、最後のRedraw()を呼び出している後にでも続けて、

hnd0.post(rnb0)

 と、追加しておきます。

 

 あ、それと!

 コード最下部、

override fun onDestroy() {
sqloh0.close()
super.onDestroy()
}

の中に、
hnd0.removeCallbacks(rnb0)

を追記しておきましょう。

f:id:little_strange:20191012232537p:plain

↑こんな感じで。

 

 以上で、完成!!です!

 

 

 エミュレータにビルドしてみましょう

 

f:id:little_strange:20191012231706p:plain

  1.  シークバーで適当に色を選んで、 
  2. 10秒ぐらい、その色のまま置いておき、
  3. 最近みた色」ボタンを押すと、勝手にそこに記録されているのが確認できれば成功です!

 

 やー、前後編に分かれて、結構なボリュームのコードを書いたような気がしますが、実際はそれほどでもないんですね^^;

一応、現時点でのMainActivity.ktのコード全文、のっけておきます。

 MainActivity.kt

package jp.littlestrangesoftware.a20190919colorselect

import android.content.Context
import android.content.SharedPreferences
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.view.View
import android.widget.Button
import android.widget.SeekBar
import kotlinx.android.synthetic.main.activity_main.*
import java.util.*

class MainActivity : AppCompatActivity() {

lateinit var sb : List<SeekBar>
lateinit var btns:List<Button>
lateinit var prf:SharedPreferences

var rnd = Random()

var btcl=Array<Int>(16,{0})

var cl= mutableListOf<Int>(0,0,0)
var i :Int = 0

val sqloh0=SQLoh(this)

var lastrc=0
var lastcl=0
var cnt=0
var hnd0=Handler()
var rnb0=object : Runnable{
override fun run() {
if (cl[0]*256*256+cl[1]*256+cl[2]==lastcl){
cnt++
if(cnt>=100){
lastrcLoad()
if(lastcl!=lastrc){
lastrc=lastcl
rcSave()
cnt=0
}
}
}else{
cnt=0
lastcl=cl[0]*256*256+cl[1]*256+cl[2]
}
hnd0.postDelayed(this,100)
}
}




override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

prf=getSharedPreferences("COLORS", Context.MODE_PRIVATE)
cl[0]=prf.getInt("cl0p",0)
cl[1]=prf.getInt("cl1p",0)
cl[2]=prf.getInt("cl2p",0)

sb=listOf(sbR,sbG,sbB)
btns=listOf(bt00,bt01,bt02,bt03,bt04,bt05,bt06,bt07,bt08,bt09,bt10,bt11,bt12,bt13,bt14,bt15)

rndcl()

for (i in 0..2){
sb[i].setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
if(p2) {
cl[i] = sb[i].progress
Redraw()
}
}
override fun onStartTrackingTouch(p0: SeekBar?) {}
override fun onStopTrackingTouch(p0: SeekBar?) {}
})
}
Redraw()
hnd0.post(rnb0)
}

fun Redraw(){

val prfe=prf.edit()
prfe.putInt("cl0p",cl[0])
prfe.putInt("cl1p",cl[1])
prfe.putInt("cl2p",cl[2])
prfe.apply()

for (i in 0..2){sb[i].progress = cl[i]}
et0.setText(String.format("#%02X%02X%02X",cl[0],cl[1],cl[2]))
LL0.setBackgroundColor(Color.rgb(cl[0],cl[1],cl[2]))
}

fun btDclk(v:View){
for (i in 0..2){cl[i] = (cl[i] * 0.9).toInt() }
Redraw()
}

fun btLclk(v:View){
for (i in 0..2){cl[i] = ((cl[i] * 9 + 255)/10).toInt() }
Redraw()
}

fun btRclk(v:View){
rndcl()
}


fun rndcl(){
for(i in 0..15){
btcl[i]=rnd.nextInt(256*256*256)
btns[i].setBackgroundColor(255*256*256*256+btcl[i])
}
}


fun btSave(v:View){
val dbW=sqloh0.writableDatabase
val cldr=Calendar.getInstance()
var SQLstr=dbW.compileStatement("INSERT INTO COLORSV ( SV , SVTIME ) VALUES ( ? , ? )")
SQLstr.bindString(1,(cl[0]*256*256+cl[1]*256+cl[2]).toString())
SQLstr.bindString(2,cldr.timeInMillis.toString())
SQLstr.executeInsert()
}

fun rcSave(){
val dbW=sqloh0.writableDatabase
val cldr=Calendar.getInstance()
var SQLstr=dbW.compileStatement("INSERT INTO COLORRC ( RC , RCTIME ) VALUES ( ? , ? )")
SQLstr.bindString(1,lastrc.toString())
SQLstr.bindString(2,cldr.timeInMillis.toString())
SQLstr.executeInsert()
}

fun lastrcLoad(){
val dbR=sqloh0.readableDatabase
val cursor=dbR.rawQuery("select RC , RCTIME from COLORRC order by RCTIME desc limit 1",null)

if (cursor.moveToFirst()){
lastrc=cursor.getInt(cursor.getColumnIndex("RC"))
}else{
lastrc= 0
}
cursor.close()
}

fun btRCTclk(v:View){
val dbR=sqloh0.readableDatabase
val cursor=dbR.rawQuery("select RC , RCTIME from COLORRC order by RCTIME desc",null)

for (i in 0..15){
if (cursor.moveToNext()){
btcl[i]=cursor.getInt(cursor.getColumnIndex("RC"))
btns[i].setBackgroundColor(255*256*256*256+btcl[i])
}else{
btcl[i]= 0
btns[i].setBackgroundColor(255*256*256*256)
}
}
cursor.close()
}


fun btSVDclk(v:View){
val dbR=sqloh0.readableDatabase
val cursor=dbR.rawQuery("select SV , SVTIME from COLORSV order by SVTIME desc",null)

for (i in 0..15){
if (cursor.moveToNext()){
btcl[i]=cursor.getInt(cursor.getColumnIndex("SV"))
btns[i].setBackgroundColor(255*256*256*256+btcl[i])
}else{
btcl[i]= 0
btns[i].setBackgroundColor(255*256*256*256)
}
}
cursor.close()
}



fun btnclk(v:View){
for(i in 0..15){
if(v==btns[i]){
cl[0]=(btcl[i]/(256*256)).toInt()
cl[1]=(btcl[i]/256).toInt()%256
cl[2]=btcl[i]%256
Redraw()
}
}
}


override fun onDestroy() {
hnd0.removeCallbacks(rnb0)
sqloh0.close()
super.onDestroy()
}

}

 

  以上で、「最近みた色」機能の追加の説明を終わります!!

 

 読んでくださった方、ありがとうございます!

 また次回も、よろしくお願いしますね^^

 

 

追記。

 それにしても…なんだかむしょうに疲れました^^;

 ↑こういうの欲しい!w

 ハンディマッサージャー以上、電気マッサージ椅子以下、といった価格帯ですねぇ。

 この価格設定もまた気になりますw