Kotlin์์ ๊ฐ๋จํ ํ ๊ณ์ฐ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ง๋๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค. ๋ ์ ํํ ๋งํ๋ฉด Kotlin 1.3.21, Android 4, Android Studio 3์
๋๋ค. ์ด ๊ธฐ์ฌ๋ ์ฐ์ Android ์ ํ๋ฆฌ์ผ์ด์
๊ฐ๋ฐ ์ฌ์ ์ ์์ํ๋ ์ฌ๋๋ค์๊ฒ ํฅ๋ฏธ๋ก์ธ ๊ฒ์
๋๋ค. ์์ฉ ํ๋ก๊ทธ๋จ ๋ด์์ ๋ฌด์์ด ์ด๋ป๊ฒ ์๋ํ๋์ง ์ดํดํ ์ ์์ต๋๋ค.
์ด๋ฌํ ๊ณ์ฐ๊ธฐ๋ ์๋น์ด๋ ์นดํ์์ ์๊ฐ์ ๋ณด๋ด๊ธฐ๋ก ๊ฒฐ์ ํ ํ์ฌ์ ํ ๊ธ์ก์ ๊ณ์ฐํด์ผ ํ ๋ ์ ์ฉํฉ๋๋ค. ๋ฌผ๋ก ๋ชจ๋ ์ฌ๋์ด ์๋๊ณ ํญ์ ์จ์ดํฐ๋ฅผ ์ํด ์ฐจ๋ฅผ ๋จ๊ธฐ๋ ๊ฒ์ ์๋๋๋ค. ์ด๊ฒ์ ์์ ์ ํต์ ๊ฐ๊น์ง๋ง ๊ทธ๋ฌํ ์์ฉ ํ๋ก๊ทธ๋จ์ ๊ฐ๋ฐํ๋ ๊ณผ์ ์ ์ด์จ๋ ํฅ๋ฏธ ๋กญ์ต๋๋ค.
์๋ฆผ: "Habr"์ ๋ชจ๋ ๋ ์๋ฅผ ์ํ - "Habr" ํ๋ก๋ชจ์ ์ฝ๋๋ฅผ ์ฌ์ฉํ์ฌ Skillbox ๊ณผ์ ์ ๋ฑ๋กํ ๋ 10 ๋ฃจ๋ธ ํ ์ธ.
Skillbox๋ ๋ค์์ ๊ถ์ฅํฉ๋๋ค. ์ค๊ธฐ ์ฝ์ค
"๋ชจ๋ฐ์ผ ๊ฐ๋ฐ์ PRO .
์ฑ์ด ์คํ ์ค์ผ ๋์ ๋ชจ์ต์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์ด์ก์ ์ํ๋ ๋น์จ, ํ์ ์ฐธ๊ฐ์ ์๋ฅผ ์
๋ ฅํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์ป์ต๋๋ค-๋จ์์ผ ํ ํ์ ์.
ะะฐัะธะฝะฐะตะผ
์ฑ์ ์ ์ฒด ์ธํฐํ์ด์ค๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์ฒซ ๋ฒ์งธ ์กฐ์น -
์ฌ์ฉ์ ์์
์ ์๊ฐ์์ผ๋ก ํ๋ก์ ํธ์ ์์ฑ๋๋ฏ๋ก ๋ชจ๋ ๊ฒ์ด ๋ช
ํํฉ๋๋ค. ์ด๋ฅผ ๋ณด๋ ค๋ฉด ๋ณด๊ธฐ -> ๋๊ตฌ ์ฐฝ -> TODO๋ฅผ ์ฝ๋๋ค.
ํ๋ก์ ํธ๋ฅผ ์ฐ๊ตฌํ๊ณ colors.xml์ ์ด์ด ์์ ํ๋ ํธ๋ฅผ ํ๊ฐํฉ๋๋ค. strings.xml์๋ ํ ์คํธ ๋ฐ์ดํฐ(์บก์ )๊ฐ ํฌํจ๋์ด ์๊ณ styles.xml์๋ ์ฌ๋ฌ ๊ธ๊ผด ํ ํ๋ฆฟ์ด ํฌํจ๋์ด ์์ต๋๋ค.
๋น์ฉ ์น์ ๊ฐ๋ฐ
activity_main.xml์ ์ด๊ณ LinearLayout(#1)์ ์๋ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
<TextView
android_id="@+id/expensePerPersonTextView"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_paddingTop="30dp"
style="@style/h1Bold"
android_textColor="@color/colorAccent"
android_text="0"/>
<TextView
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_paddingBottom="25dp"
style="@style/h2"
android_textColor="@color/colorAccent"
android_text="@string/perPersonStaticText"/>
์ด์ ๊ฐ ๋๋ ํ ๋ฆฌ์ ์คํ์ผ์ ์ง์ ํ๊ฑฐ๋ ๋ค์์ ์ฌ์ฉํ์ฌ ์์์ ๊ฐ์ง๊ณ ๋ ์ ์์ต๋๋ค.
์ด์ ํ๋ก์ ํธ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๋ณด์๋ค์ํผ ๋น์ฉ ๊ณ์ฐ์ ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํฉ๋๋ค.
๊ณ์ ์น์ ๊ฐ๋ฐ
๋น์ฉ ์น์ (#2) ๋ค์์ LinearLayout์ ์๋ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
<LinearLayout
android_layout_width="match_parent"
android_layout_height="match_parent"
android_orientation="vertical"
android_background="@color/colorAccent">
<! โ TODO #3: Build Bill Section โ
โฆ
</LinearLayout>
TODO ๋ชฉ๋ก ๋ค์์ LinearLayout์ ๋ซ์ ๋ค์ ์ ์ฝ๋๋ฅผ ์ถ๊ฐํ์ฌ LinearLayout ์์ ๋ฐฐ์นํฉ๋๋ค(#3).
<TextView
android_layout_margin="15dp"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_textColor="@color/colorWhite"
style="@style/h4"
android_text="@string/billStaticText"/>
<EditText
android_id="@+id/billEditText"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_textColor="@color/colorWhite"
android_inputType="numberDecimal"
android_maxLines="1"
style="@style/h2Bold"
android_text="0"/>
์์ฉ ํ๋ก๊ทธ๋จ์ ์ฃผ์ ์์ ์ ์๋น ๋ชจ์ ์ฐธ๊ฐ์ ๊ฐ๊ฐ์ ๊ฐ๋ณ ๋น์ฉ์ ๊ณ์ฐํ๋ ๊ฒ์ด๋ฏ๋ก costPerPersonTextView๊ฐ ์ฃผ์ ์ญํ ์ ํฉ๋๋ค.
EditText๋ ์ ๋ ฅ์ ํ ์ค๋ก ์ ํํฉ๋๋ค. ์ด ๋งค๊ฐ๋ณ์๋ NumberDecimal inputType์ผ๋ก ์ค์ ํด์ผ ํฉ๋๋ค.
ํ
์คํธ๋ฅผ ์ํ ํ๋ก์ ํธ๋ฅผ ์์ํ๊ณ ์ ์ฒด ์์ ๋งค๊ฐ๋ณ์(๊นจ์ง ์ปต, ์ ์ ๋ฑ)๋ฅผ ์
๋ ฅํฉ๋๋ค.
"์ฌ๋๊ณผ ํ" ์น์ ๊ฐ๋ฐ
ํ ๊ธ์ก ์ ํ๊ธฐ๋ฅผ ์ถ๊ฐํ๋ ค๋ฉด ์๋ ์ฝ๋๋ฅผ ์ LinearLayout ์น์ (#4)์ ๋ถ์ฌ๋ฃ์ผ์ธ์.
<TextView
android_layout_margin="15dp"
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_textColor="@color/colorWhite"
style="@style/h4"
android_text="@string/tipStaticText"/>
<LinearLayout
android_layout_width="match_parent"
android_layout_height="wrap_content"
android_orientation="horizontal">
<ImageButton
android_id="@+id/subtractTipButton"
style="@style/operationButton"
android_layout_marginLeft="20dp"
android_layout_marginStart="20dp"
android_src="@drawable/subtract"/>
<TextView
android_id="@+id/tipTextView"
android_layout_margin="15dp"
android_layout_width="0dp"
android_layout_height="wrap_content"
android_textColor="@color/colorWhite"
android_layout_weight="1"
style="@style/h2Bold"
android_text="20%"/>
<ImageButton
android_id="@+id/addTipButton"
style="@style/operationButton"
android_layout_marginEnd="20dp"
android_layout_marginRight="20dp"
android_src="@drawable/add"/>
</LinearLayout>
์ด ์ฝ๋๋ ํ ๊ธ์ก์ ์ ํํ๊ฒ ๊ณ์ฐํ๋ ๋ฐ ํ์ํฉ๋๋ค. ๊ธฐ๋ณธ ํ ์คํธ ๊ฐ์ 20์ ๋๋ค. ImageButton์๋ ์ฐ๊ธฐ ๊ถํ์ด ์๋ ํด๋์ ์์ด์ฝ์ด ์ ๊ณต๋ฉ๋๋ค.
์ ์ฒด ์น์ ์ ๋ณต์ฌํ๊ณ ๋ค์์ ์ถ๊ฐํฉ๋๋ค(#5).
- ImageButton ID(subtractPeopleButton, addPeopleButton)
- TextView ID(numberOfPeopleStaticText, numberOfPeopleTextView)
- numberOfPeopleTextView์ DefaultText(4์ฌ์ผ ํจ).
์ด์ ์์ฉ ํ๋ก๊ทธ๋จ์ ์์ํ ๋ ์ธ๋ณด์ด์ค ๊ธ์ก์ ์ถ๊ฐํ ์ ์๊ณ ์ถ๊ฐ/๋นผ๊ธฐ ๋ฒํผ๋ ์๋ํ์ง๋ง ์ง๊ธ๊น์ง๋ ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์์ต๋๋ค.
๋ณด๊ธฐ ์ถ๊ฐ
MainActivity.kt๋ฅผ ์ด๊ณ initViews ํจ์(#6)์ ๋ค์์ ์ถ๊ฐํฉ๋๋ค.
private fun initViews() {
expensePerPersonTextView = findViewById(R.id.expensePerPersonTextView)
billEditText = findViewById(R.id.billEditText)
addTipButton = findViewById(R.id.addTipButton)
tipTextView = findViewById(R.id.tipTextView)
subtractTipButton = findViewById(R.id.subtractTipButton)
addPeopleButton = findViewById(R.id.addPeopleButton)
numberOfPeopleTextView = findViewById(R.id.numberOfPeopleTextView)
subtractPeopleButton = findViewById(R.id.subtractPeopleButton)
//TODO #8: Bind Buttons to Listener
//TODO #16: Bind EditText to TextWatcher
}
๋ฒํผ ๋ง๋ฌด๋ฆฌ
๋ฒํผ ํด๋ฆญ์ ๋ํ ์ง์์ ์ถ๊ฐํ๋ ค๋ฉด ํด๋์ค ์์ค(#7)์์ View.OnClickListener๋ฅผ ๊ตฌํํฉ๋๋ค.
ํด๋์ค MainActivity: AppCompatActivity(), View.OnClickListener {
์ง๊ธ ๋ฐ๋ก ํ๋ก์ ํธ๋ฅผ ์ปดํ์ผํ๋ ๊ฒ์ ์๋ํ์ง ์์ต๋๋ค. ๋ช ๊ฐ์ง ๋จ๊ณ๋ฅผ ๋ ์ํํด์ผ ํฉ๋๋ค(# 8).
override fun onClick(v: View?) {
when (v?.id) {
R.id.addTipButton -> incrementTip()
R.id.subtractTipButton -> decrementTip()
R.id.addPeopleButton -> incrementPeople()
R.id.subtractPeopleButton -> decrementPeople()
}
}
๋ฒํผ๊ณผ ์ค์์น ์ธก๋ฉด์์ Kotlin์ ๋ชจ๋ ๊ฒ์ ๋งค์ฐ ๋ฉ์ง๊ฒ ์ ๋ฆฌํ์ต๋๋ค! ๋ชจ๋ ์ฆ๊ฐ ๋ฐ ๊ฐ์ ํจ์์ ์๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ์ญ์์ค.
(#9 โ#12):
private fun incrementTip() {
if (tipPercent != MAX_TIP) {
tipPercent += TIP_INCREMENT_PERCENT
tipTextView.text = String.format("%d%%", tipPercent)
}
}
private fun decrementTip() {
if (tipPercent != MIN_TIP) {
tipPercent -= TIP_INCREMENT_PERCENT
tipTextView.text = String.format("%d%%", tipPercent)
}
}
private fun incrementPeople() {
if (numberOfPeople != MAX_PEOPLE) {
numberOfPeople += PEOPLE_INCREMENT_VALUE
numberOfPeopleTextView.text = numberOfPeople.toString()
}
}
private fun decrementPeople() {
if (numberOfPeople != MIN_PEOPLE) {
numberOfPeople -= PEOPLE_INCREMENT_VALUE
numberOfPeopleTextView.text = numberOfPeople.toString()
}
}
์ฌ๊ธฐ์ ์ฝ๋๋ ์ต๋๊ฐ(MAX_TIP & MAX_PEOPLE)์ผ๋ก ์ฆ๋ถ ํจ์๋ฅผ ๋ณดํธํฉ๋๋ค. ๋ํ ์ฝ๋๋ ์ต์๊ฐ(MIN_TIP & MIN_PEOPLE)์ผ๋ก ๊ฐ์ ํจ์๋ฅผ ๋ณดํธํฉ๋๋ค.
์ด์ initViews ํจ์(#13)์์ ๋ฒํผ์ ๋ฆฌ์ค๋์ ๋ฐ์ธ๋ฉํฉ๋๋ค.
private fun initViews() {
...
addTipButton.setOnClickListener(this)
subtractTipButton.setOnClickListener(this)
addPeopleButton.setOnClickListener(this)
subtractPeopleButton.setOnClickListener(this)
//TODO #15: Bind EditText to TextWatcher
}
์ด์ ์ด ํผํด, ํ ๋ฐ ํ์ ์ฐธ๊ฐ์ ์๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค. ์, ์ด์ ๊ฐ์ฅ ์ค์ํ ๊ฒ์...
๋น์ฉ ์น์
์ด ์ฝ๋๋ ๋น์ฉ์ ๊ณ์ฐํฉ๋๋ค(#14).
private fun calculateExpense() {
val totalBill = billEditText.text.toString().toDouble()
val totalExpense = ((HUNDRED_PERCENT + tipPercent) / HUNDRED_PERCENT) * totalBill
val individualExpense = totalExpense / numberOfPeople
expensePerPersonTextView.text = String.format("$%.2f", individualExpense)
}
์, ์ฌ๊ธฐ ํ์ฌ์ ์ธ์์๋ฅผ ๊ณ ๋ คํ์ฌ ํ์ ๊ณ์ฐํ ์ ์๋ ํจ์๊ฐ ํธ์ถ๋ฉ๋๋ค(#15).
private fun incrementTip() {
โฆ
}
private fun decrementTip() {
โฆ
}
private fun incrementPeople() {
โฆ
}
private fun decrementPeople() {
โฆ
}
์์ฉ ํ๋ก๊ทธ๋จ์ ์์ํฉ๋๋ค. ์ ๋ณด์ด๊ณ ์ ์๋ํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋ ๋์ ์ ์์ต๋๋ค.
์ฒญ๊ตฌ ๊ธ์ก์ ์ญ์ ํ ํ ํํธ๋ ์น๊ตฌ ์๋ฅผ ๋๋ฆฌ๋ ค๊ณ ํ๋ฉด ์์ง ๋น์ฉ ์ ๋ก์ ๋ํ ํ์ธ์ด ์๊ธฐ ๋๋ฌธ์ ์ฑ์ด ์ถฉ๋ํฉ๋๋ค. ๋ํ ์ธ๋ณด์ด์ค ๊ธ์ก์ ๋ณ๊ฒฝํ๋ ค๊ณ ํ๋ฉด ์๊ธ์ด ์ ๋ฐ์ดํธ๋์ง ์์ต๋๋ค.
์ต์ข ๋จ๊ณ
TextWatcher ์ถ๊ฐ(#16):
ํด๋์ค MainActivity: AppCompatActivity(), View.OnClickListener, TextWatcher {
๊ทธ๋ฐ ๋ค์ billEditText ๋ฆฌ์ค๋(#17)๋ฅผ ํฌํจํฉ๋๋ค.
billEditText.addTextChangedListener(์ด)
๋ํ TextWatcher๋ฅผ ์คํํ๋ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค(#18).
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
if (!billEditText.text.isEmpty()) {
calculateExpense()
}
}
override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
์ด์ ๋ชจ๋ ๊ฒ์ด ์๋ํฉ๋๋ค! ์ถํํฉ๋๋ค. Kotlin์ผ๋ก ์์ ๋ง์ "ํ ๊ณ์ฐ๊ธฐ"๋ฅผ ์์ฑํ์ต๋๋ค.
Skillbox๋ ๋ค์์ ๊ถ์ฅํฉ๋๋ค.
- XNUMX๋ ์ค์ต ์ฝ์ค
"์ ๋ PRO ์น ๊ฐ๋ฐ์์ ๋๋ค" .- ์จ๋ผ์ธ ์ฝ์ค
"C# ๊ฐ๋ฐ์" .- ์ค๊ธฐ ์ฝ์ค
"0์์ PRO๋ก์ PHP ๊ฐ๋ฐ์" .
์ถ์ฒ : habr.com