본문 바로가기
안드로이드 코틀린

[Kotlin][Android] Data Bindng을 이용한 계산기 어플 만들기

by teamnova 2021. 6. 20.

안녕하세요. 예전에 자바를 이용해서 계산기를 만들어 봤는데요. 이번에는 코틀린으로 구현해보도록 하겠습니다.

 

이번 예제에서는 특히 화면에 View들이 많이 들어가는데요. 일일이 findVidwID를 통해서 각 View를 접근하기에는 너무 힘들고 귀찮은 작업입니다.

 

그래서 이번에는 Data Binding을 사용해서 현재 Activity와 연결되어 있는 .xml 파일의 View에 접근해보도록 하겠습니다.

 

Data Binding은 Jetpack의 구성요소 중 하나입니다.  제트팩은 2018년 구글 IO 행사에서 발표된 안드로이드 앱 개발 패키지 묶음입니다. 데이터 바인딩은 이름 그대로 액티비티나 프래그먼트의 데이터를 화면에 출력하는 부분을 도와주는 AAC 기법입니다.

 

Data Binding이 무엇인지 안드로이드 개발자 홈페이지를 통해 알아보도록 합시다.

developer.android.com/topic/libraries/data-binding/generated-binding

 

생성된 결합 클래스  |  Android 개발자  |  Android Developers

데이터 결합 라이브러리는 레이아웃의 변수 및 뷰에 액세스하는 데 사용되는 결합 클래스를 생성합니다. 이 페이지에서는 생성된 결합 클래스를 만들고 맞춤설정하는 방법을 보여줍니다. 생성

developer.android.com

공식 홈페이지에서 설명하는 DataBinding

 

공식 홈페이지 설명의 특징을 정리하면, 'Binding Class'라는 녀석을 이용하면 Layout에 있는 View에 접근 할 수 있으며, 이 클래스의 이름은 대게 .xml 파일에서 파스칼 형식으로 바뀌며 접미사로 Binding이 붙는다는 것을 알게 되었습니다.

 

 

Data Binding을 사용하기 위해서 build.gradle (App 단위) 에서 android에 viewBinding 태그를 만들고 enabled 속성을 true로 설정해줍시다.

    dataBinding {
        enabled = true
    }

 

그 다음으로 Acitivity에서 아래와 같이 사용하시면 됩니다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
	// MyLayoutBinding은 사용자의 Activity이름에 따라 달라지겠죠?!
    val binding: MyLayoutBinding = MyLayoutBinding.inflate(layoutInflater) 
    setContentView(binding.root)
}

 

준비도 다 되었겠다. 계산기 레이아웃을 그려줍시다. 화면은 구성은 일반적인 계산기 구성을 따랐습니다.

여기서 다른 Layout과 다른 점은 이 레이아웃의 Root 뷰는 <layout> 이라는 점입니다.

<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorblack"
        android:orientation="vertical"
        tools:context=".CalculateActivity">

        <TextView
            android:id="@+id/tvInput"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:ellipsize="start"
            android:gravity="end"
            android:paddingLeft="10dp"
            android:paddingTop="10dp"
            android:singleLine="true"
            android:text=""
            android:textColor="@color/colorGray"
            android:textSize="50sp" />

        <TextView
            android:id="@+id/tvOutput"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:ellipsize="start"
            android:gravity="end"
            android:paddingLeft="10dp"
            android:singleLine="true"
            android:text=""
            android:textColor="@color/colorWhite"
            android:textSize="60sp" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="bottom"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="80dp"
                android:background="@color/colorWhite"
                android:orientation="horizontal">

                <Button
                    android:id="@+id/btnClear"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="C"
                    android:textColor="@color/colorblack"
                    android:textSize="16sp" />

                <Button
                    android:id="@+id/btnLeftB"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="("
                    android:textColor="@color/colorGray"
                    android:textSize="16sp" />

                <Button
                    android:id="@+id/btnRightB"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text=")"
                    android:textColor="@color/colorGray"
                    android:textSize="16sp" />

                <Button
                    android:id="@+id/btnDivide"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="/"
                    android:textColor="@color/colorPurple"
                    android:textSize="16sp" />

            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="80dp"
                android:background="@color/colorWhite"
                android:orientation="horizontal">

                <Button
                    android:id="@+id/btn1"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="1"
                    android:textColor="@color/colorGray"
                    android:textSize="16sp" />

                <Button
                    android:id="@+id/btn2"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="2"
                    android:textColor="@color/colorGray"
                    android:textSize="16sp" />

                <Button
                    android:id="@+id/btn3"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="3"
                    android:textColor="@color/colorGray"
                    android:textSize="16sp" />

                <Button
                    android:id="@+id/btnMultiply"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="x"
                    android:textColor="@color/colorPurple"
                    android:textSize="16sp" />

            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="80dp"
                android:background="@color/colorWhite"
                android:orientation="horizontal">

                <Button
                    android:id="@+id/btn4"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="4"
                    android:textColor="@color/colorGray"
                    android:textSize="16sp" />

                <Button
                    android:id="@+id/btn5"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="5"
                    android:textColor="@color/colorGray"
                    android:textSize="16sp" />

                <Button
                    android:id="@+id/btn6"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="6"
                    android:textColor="@color/colorGray"
                    android:textSize="16sp" />

                <Button
                    android:id="@+id/btnMinus"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="-"
                    android:textColor="@color/colorPurple"
                    android:textSize="16sp" />

            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="80dp"
                android:background="@color/colorWhite"
                android:orientation="horizontal">

                <Button
                    android:id="@+id/btn7"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="7"
                    android:textColor="@color/colorGray"
                    android:textSize="16sp" />

                <Button
                    android:id="@+id/btn8"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="8"
                    android:textColor="@color/colorGray"
                    android:textSize="16sp" />

                <Button
                    android:id="@+id/btn9"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="9"
                    android:textColor="@color/colorGray"
                    android:textSize="16sp" />

                <Button
                    android:id="@+id/btnPlus"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="+"
                    android:textColor="@color/colorPurple"
                    android:textSize="16sp" />

            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="80dp"
                android:background="@color/colorWhite"
                android:orientation="horizontal">

                <Button
                    android:id="@+id/btn00"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="00"
                    android:textColor="@color/colorGray" />

                <Button
                    android:id="@+id/btn0"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="0"
                    android:textColor="@color/colorGray"
                    android:textSize="16sp" />

                <Button
                    android:id="@+id/btnDot"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:background="@color/colorWhite"
                    android:stateListAnimator="@null"
                    android:text="."
                    android:textColor="@color/colorGray"
                    android:textSize="16sp" />

                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:gravity="center">

                    <Button
                        android:id="@+id/btnEqual"
                        android:layout_width="78dp"
                        android:layout_height="78dp"
                        android:layout_margin="2dp"
                        android:stateListAnimator="@null"
                        android:text="="
                        android:textColor="@color/colorWhite"
                        android:textSize="16sp" />

                </RelativeLayout>


            </LinearLayout>

        </LinearLayout>

    </LinearLayout>
</layout>

 

다음으로 메인 코드를 작성해보도록 하겠습니다.

 

앞서 BindingData를 사용하는 방법에서 서술했듯이 bindingData 클래스를 생성해주고 관련된 레이아웃과 연결해줍니다.

 

 

각 버튼에 대해 클릭 이벤트를 달아주었습니다.

binding 

버튼 클릭이벤트 리스너에 해당하는 함수입니다. 

연산 결과를 나타내는 버튼을 클릭하게 되면 연산작업을 하라는 로직을 실행하게 됩니다. 저는 한 라이브러리를 발견해서 구현하였습니다. 이 라이브러리를 dependencies에 넣어줍시다.

dependencies{
	...
	// 계산 라이브러리
    implementation 'net.objecthunter:exp4j:0.4.8'
}

 

전체 코드

package com.example.stickcodekotlin

import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import com.example.stickcodekotlin.databinding.ActivityCalculateBinding
import net.objecthunter.exp4j.ExpressionBuilder

class CalculateActivity : AppCompatActivity() {
    private lateinit var binding: ActivityCalculateBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_calculate)

        //숫자 버튼 클릭 이벤트 리스너
        binding.btn00.setOnClickListener { appendOnClick(true, "00") }
        binding.btn0.setOnClickListener { appendOnClick(true, "0") }
        binding.btn1.setOnClickListener { appendOnClick(true, "1") }
        binding.btn2.setOnClickListener { appendOnClick(true, "2") }
        binding.btn3.setOnClickListener { appendOnClick(true, "3") }
        binding.btn4.setOnClickListener { appendOnClick(true, "4") }
        binding.btn5.setOnClickListener { appendOnClick(true, "5") }
        binding.btn6.setOnClickListener { appendOnClick(true, "6") }
        binding.btn7.setOnClickListener { appendOnClick(true, "7") }
        binding.btn8.setOnClickListener { appendOnClick(true, "8") }
        binding.btn9.setOnClickListener { appendOnClick(true, "9") }
        binding.btnDot.setOnClickListener { appendOnClick(true, ".") }

        // 연산자 버튼 클릭 이벤트
        binding.btnPlus.setOnClickListener { appendOnClick(false, "+") }
        binding.btnMinus.setOnClickListener { appendOnClick(false, "-") }
        binding.btnMultiply.setOnClickListener { appendOnClick(false, "*") }
        binding.btnDivide.setOnClickListener { appendOnClick(false, "/") }
        binding.btnLeftB.setOnClickListener { appendOnClick(false, "(") }
        binding.btnRightB.setOnClickListener { appendOnClick(false, ")") }


        binding.btnClear.setOnClickListener {
            clear()
        }

        binding.btnEqual.setOnClickListener {
            calculate()
        }
    }

    private fun appendOnClick(clear: Boolean, string: String) {
        if (clear) {
            binding.tvOutput.text = ""
            binding.tvInput.append(string)
        } else {
            binding.tvInput.append(binding.tvOutput.text)
            binding.tvInput.append(string)
            binding.tvOutput.text = ""
        }
    }

    private fun clear() {
        binding.tvInput.text = ""
        binding.tvOutput.text = ""
    }

    private fun calculate() {
        try {
            val input = ExpressionBuilder(binding.tvInput.text.toString()).build()
            val output = input.evaluate()
            val longOutput = output.toLong()
            if (output == longOutput.toDouble()){
                binding.tvOutput.text = longOutput.toString()
            }else{
                binding.tvOutput.text = output.toString()
            }

        }catch (e:Exception){
            Toast.makeText(this,e.message,Toast.LENGTH_LONG).show()
        }
    }
}

stickode.com/detail.html?no=2173

 

스틱코드

 

stickode.com

결과