Android Studioで電卓アプリを作る

Android Studioを使い始めたばかりですが電卓アプリを作ってみます。
前回の投稿はこちら --> [夏休みに始めるAndroidアプリ開発](https://qiita.com/yanasep/items/b0638c9bf6071beef9a3)

プロジェクト作成時にInclude Kotlin Supportにチェックを入れ、Kotlinで開発します。
#レイアウトの作成
新しいプロジェクトを作ったら、まずはレイアウトエディターでレイアウトを作成します。今回はオブジェクトを碁盤目状に配置できる、TableLayoutを使っていきます。

Layoutsタブを選び、TableLayoutをドラッグ＆ドロップでConstraintLayoutに重ねます。
![Screenshot (18)_LI.jpg](https://qiita-image-store.s3.amazonaws.com/0/153141/3ebc36a4-0928-f71b-0901-b7fc92321ed6.jpeg)

TableLayoutにはTableRowが4つ入っていますが、今回は数式１段、ボタン５段の計６段を必要なので、同じようにTableRowをTableLayoutの下にドラッグ＆ドロップして６つにしましょう。

##TextViewの配置
１段目には数式を表示するためのTextViewを配置します。TextViewを一番上のTableRowにドラッグ＆ドロップし、
- ID : formula
- textSize : 30
- textAlignment : 右寄せ
にし、textはStringに。Resource nameをformula_text、Resource valueは空白にしてOKをクリック。![Screenshot (40)_LI.jpg](https://qiita-image-store.s3.amazonaws.com/0/153141/9981344f-34e8-7bca-7825-a331401551cb.jpeg)

後でボタンをタップすることによってtextが変わるようにしていきます。

##ボタンの配置
ボタンを順にTableRowに入れていきます。面倒くさいですが頑張ります。
![Screenshot (41)_LI.jpg](https://qiita-image-store.s3.amazonaws.com/0/153141/4ec95599-ca4a-097b-38e9-3743c32c2e24.jpeg)

##レイアウトの整形
配置が全体的に左上に寄ってしまっているので、画面めいっぱい使うように調整しましょう。textViewのheightを130、weightを1、同様にボタンのheightを85、weightを1にします。
![Capture.JPG](https://qiita-image-store.s3.amazonaws.com/0/153141/b278edf7-6340-abb1-d3fc-52fa89bceab3.jpeg)


電卓っぽくなりました。heightはハードコードでなく、画面サイズにあわせて調整したいのですがやり方が分からず…(－д－)


#ボタンに動作をつける
MainActivityにコードを書いていきます。

```kotlin:MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
        ...

        ボタンのid.setOnClickListener {
            //ボタンの動作
        }
}
```
とするとアプリ起動時に、ボタンが押された時の動作を付加することができます。

###数字ボタン
```kotlin
var nStr : String = ""
val nList = ArrayList<Double>() // 数式に含まれる数を保持する配列

override fun onCreate(savedInstanceState: Bundle?) {
        ...

        num0.setOnClickListener {
            formula.text = "${formula.text}0" //表示する数式に0を追加
            nStr += "0"                       //数字の文字列に0を追加
        }
        num1.setOnClickListener {
            formula.text = "${formula.text}1" //表示する数式に1を追加
            nStr += "1"
        }
        .
        .
        //num9まで同様

        //小数点
        point.setOnClickListener {
            formula.text = "${formula.text}."
            nStr += "."
        }
}
```
"${formula.text}"で現在の数式を取得し、そこにボタンの数を追加し、代入しています。ボタンを押すごとに数字が並ぶことになります。

nStrは、formula.textとは別に、入力された数字を文字列として保持しています。+, -, *, /, = ボタンが押された時に、Double型の数値に変換し、nListに入れ、nStrを空文字に戻します。

小数点も数値と同様に扱います。

###四則演算ボタン
```kotlin
var nStr : String = ""
val nList = ArrayList<Double>() // 数式に含まれる数を保持する配列
val oList = ArrayList<Double>() // 数式に含まれるオペレーション（四則演算）を保持する配列

override fun onCreate(savedInstanceState: Bundle?) {
        ...
        add.setOnClickListener {
            formula.text = "${formula.text}+"
            addList(nStr,'+')                 //後述、nStrを小数に変換しnListに入れ、"+"をoListに入れる。
            nStr = ""                         //nStrを空に戻す
        }
        .
        .
        //引き算、掛け算、割り算も同様
}
```
四則演算もほぼ同様ですが、自分で定義したaddList関数を使っています。

```kotlin
fun addList(str : String, ope : Char) {
    try {
        var num = str.toDouble()         //小数に変換
        nList.add(num)                   //nListに追加
        if (ope != '=') oList.add(ope)   //演算子をoListに追加
    }catch(e:Exception){
        formula.text = "Numeric error"   //小数に変換できなかった時にエラーを表示
    }
}
```

###DELボタン

```kotlin
delete.setOnClickListener {
    var formulaStr = formula.text.toString()
    if (!formulaStr.isEmpty()) {
        formula.text = formulaStr.subSequence(0,formulaStr.lastIndex)
    }
    if (!nStr.isEmpty()) {
        nStr = nStr.substring(0, nStr.lastIndex)
    }
}
```
数式とnStrのそれぞれ最後の一文字を削除します。

###Cボタン
```kotlin
clear.setOnClickListener {
    formula.text = ""
    nStr = ""
    nList.clear()
    oList.clear()
}
```
すべてのテキスト、リストを初期化します。

###=ボタン
```kotlin
equal.setOnClickListener {
    if (nList.size != oList.size + 1) 
        return

    formula.text = "${formula.text}="
    addList(nStr,'=')
    var result = calcualte().toString()
    formula.text = result
    nStr = result
    nList.clear()
    oList.clear()
}
```

nListに最後の数を追加し、計算します。さらに計算結果を文字列に変換し、表示し、リストを初期化します。計算結果をnStrに入れておくことで、それを使って続けて計算できるようにします。

calculateファンクションではnListとoListを使って計算します。
![calcProcess.gif](https://qiita-image-store.s3.amazonaws.com/0/153141/cc694d6c-d273-3714-bd0b-66ff8d5fb3f5.gif)
前から順に掛け算、割り算を計算し、リストを置き換えていってます。引き算はマイナスの足し算に変数することで、最後はリストの合計を求めるだけでよくなります。
ループ中にリストが変わっていくので、iの値に注意。

```kotlin
fun calcualte() : Double {

    var i = 0
    while (i < oList.size) {

        //先に掛け算、割り算を前から順に行う
        if(oList.get(i) == '*' || oList.get(i) == '/') {
            var result = if (oList.get(i) == '*') nList.get(i) * nList.get(i+1) else nList.get(i) / nList.get(i+1)
            nList.set(i,result)   //計算に使った一つ目の数を計算結果に置き換え
            nList.removeAt(i+1)   //二つ目の数をリストから削除
            oList.removeAt(i)     //使い終わった演算子をリストから削除
            i--                   //リストの次の要素が一つ手前に来たのでiを一つ戻す
        }

        // 引き算を足し算に変える
        else if(oList.get(i) == '-'){
            oList.set(i,'+')
            nList.set(i+1,nList.get(i+1) * -1) //引く数を-1倍
        }
        i++
    }

     // 足し算だけ残るので、リストに残った数を合計する
    var result = 0.0
    for (i in nList){
        result += i
    }
     return result
}// end fun calcualte
```

これで一通りボタンの動作をつけることができました。
※%と+/- ボタンはとばします。

コードを全部載せておきます。

```kotlin:MainActivity.xml

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    var nStr : String = ""
    val nList = ArrayList<Double>() // arraylist to store numbers
    val oList = ArrayList<Char>() // arraylist to store operations

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

        num0.setOnClickListener {
            formula.text = "${formula.text}0"
            nStr += "0"
        }
        num1.setOnClickListener {
            formula.text = "${formula.text}1"
            nStr += "1"
        }
        num2.setOnClickListener {
            formula.text = "${formula.text}2"
            nStr += "2"
        }
        num3.setOnClickListener {
            formula.text = "${formula.text}3"
            nStr += "3"
        }
        num4.setOnClickListener {
            formula.text = "${formula.text}4"
            nStr += "4"
        }
        num5.setOnClickListener {
            formula.text = "${formula.text}5"
            nStr += "5"
        }
        num6.setOnClickListener {
            formula.text = "${formula.text}6"
            nStr += "6"
        }
        num7.setOnClickListener {
            formula.text = "${formula.text}7"
            nStr += "7"
        }
        num8.setOnClickListener {
            formula.text = "${formula.text}8"
            nStr += "8"
        }
        num9.setOnClickListener {
            formula.text = "${formula.text}9"
            nStr += "9"
        }
        point.setOnClickListener {
            formula.text = "${formula.text}."
            nStr += "."
        }
        equal.setOnClickListener {
            formula.text = "${formula.text}="
            addList(nStr)
            var result = calcualte().toString()
            formula.text = result
            nStr = result
            nList.clear()
            oList.clear()
        }
        add.setOnClickListener {
            formula.text = "${formula.text}+"
            addList(nStr,'+')
            nStr = ""
        }
        subtract.setOnClickListener {
            formula.text = "${formula.text}-"
            addList(nStr,'-')
            nStr = ""
        }
        multiply.setOnClickListener {
            formula.text = "${formula.text}*"
            addList(nStr,'*')
            nStr = ""
        }
        divide.setOnClickListener {
            formula.text = "${formula.text}/"
            addList(nStr,'/')
            nStr = ""
        }
        delete.setOnClickListener {
            var formulaStr = formula.text.toString()
            if (!formulaStr.isEmpty()) {
                formula.text = formulaStr.subSequence(0,formulaStr.lastIndex)
            }
            if (!nStr.isEmpty()) {
                nStr = nStr.substring(0, nStr.lastIndex)
            }
        }
        percent.setOnClickListener {
            formula.text = "${formula.text}%"
        }
        sign.setOnClickListener {

        }
        clear.setOnClickListener {
            formula.text = ""
            nStr = ""
            nList.clear()
            oList.clear()
        }

    } // end fun onCreate

    fun addList(str : String, ope : Char) {
        try {
            var num = str.toDouble()
            nList.add(num)
            oList.add(ope)
        }catch(e:Exception){
            formula.text = "Numeric error"
        }
    }

    fun addList(str : String) {
        try {
            var num = str.toDouble()
            nList.add(num)
        }catch(e:Exception){
            formula.text = "Numeric error"
        }
    }

    fun calcualte() : Double {

        var i = 0
        while (i < oList.size) {
            //do multiplication and division first
            if(oList.get(i) == '*' || oList.get(i) == '/') {
                var result = if (oList.get(i) == '*') nList.get(i) * nList.get(i+1) else nList.get(i) / nList.get(i+1)
                nList.set(i,result)
                nList.removeAt(i+1)
                oList.removeAt(i)
                i--
            }
            // change subtraction to addition
            else if(oList.get(i) == '-'){
                oList.set(i,'+')
                nList.set(i+1,nList.get(i+1) * -1)
            }
            i++
        }

        // get sum
        var result = 0.0
        for (i in nList){
            result += i
        }

        return result
    }// end fun calcualte

} // end class
```

動作確認をしてみます。
![Screenshot (44).png](https://qiita-image-store.s3.amazonaws.com/0/153141/ed2191c8-f2e6-48e8-8549-7ee0d5aed7d3.png)
無事動いていますね。

最後にデザインを変えてみましょう。
#デザインを変更する
ボーダーレスのボタンにしてみます。ボーダーレスとはその名の通り、枠のないボタンです。activity_main.xmlの左下、Textに切り替えます。
![Screenshot (46)_LI.jpg](https://qiita-image-store.s3.amazonaws.com/0/153141/e65ea80a-eb94-659f-e9ad-c804013f10c2.jpeg)

二段目以降のTableRowのところに、以下の二行を追加します。

```xml:activity_main.xml
<TableRow
     ...
     android:background="#ff0000"  // 背景色を赤に
     android:style="?android:attr/buttonBarStyle" > // ボタンのスタイル
```
色はRGBで指定します。

Buttonには以下の二行を

```activity_main.xml

<Button
      android:textColor="#000000"  // 文字を黒に
      android:style="?android:attr/buttonBarButtonStyle" /> // ボーダーレスボタンのスタイルに設定
```

ボーダーレスボタンにするとなぜか文字色がピンクになってしまうので黒に直します。
二行目はさっきと微妙に違うので注意！

![Screenshot (47).png](https://qiita-image-store.s3.amazonaws.com/0/153141/eadabb57-f565-3dbd-93a9-6ad9b57c78f0.png)
レインボーにしてみました。(笑)

#コメント
デザインの勉強をしましょう。