ساخت اپلیکیشن محاسبه انعام با کاتلین در اندروید – راهنمای کاربردی


در این مقاله با روش استفاده از زبان برنامهنویسی کاتلین به عنوان گزینه نخست اندروید برای طراحی یک اپلیکیشن ماشین حساب آشنا خواهیم شد. نسخه کاتلین مورد استفاده 1.3.21، نسخه اندروید 4 و نسخه اندروید استودیو نیز 3 است. با ما تا انتهای این راهنما همراه باشید تا با شیوه ساخت اپلیکیشن محاسبه انعام با کاتلین در اندروید آشنا شوید. در انتهای این مقاله یک اپلیکیشن برای محاسبه هزینههای شخصی خواهید داشت و همچنین درکی از توسعه اندروید و کار با کاتلین به دست میآورید.
اگر تاکنون با اندروید و کاتلین کار نکردهاید، میتوانید از این آموزش برای آشنایی مقدماتی با کاتلین استفاده کنید:
در این راهنما با شیوه ساخت یک ماشین حساب انعام از صفر تا صد با کاتلین آشنا میشویم. نتیجه کار چیزی مانند تصویر زیر خواهد بود:
در نهایت مجموع کل، مقدار انعام ترجیحی و تعداد افراد برای محاسبه هزینه فرد به صورت آنی به دست میآید.
شروع
از دیدگاه کلی کل اینترفیس به صورت زیر خواهد بود:
پروژه آغازین را از این ریپوی گیتهاب (+) دانلود و آن را در اندروید نسخه 3.0 یا بالاتر باز کنید. پروژه را بیلد و اجرا کنید تا یک صفحه خالی را مشاهده کنید. این نقطه شروع کار ما محسوب میشود:
این پروژه برخی TODO-ها دارد که به ترتیب زمانی برای راهنمایی شما اضافه شدهاند. برای دیدن آنها به منوی View -> Tool Windows -> TODO بروید.
پروژه را بررسی کنید و فایل colors.xml را باز کنید تا قالب رنگی آن را ببینید. در فایل strings.xml متون استاتیک از قبل آماده شده است. در فایل styles.xml چند استایل مانند h1Bold ،h2 ،h2Bold ،h4 و یک operationButton سفارشی برای شما آماده شدهاند.
ساخت بخش مصارف
فایل activity_main.xml را باز کنید و کد زیر را درون LinearLayout اضافه نمایید (#1):
1<TextView
2 android:id="@+id/expensePerPersonTextView"
3 android:layout_width="match_parent"
4 android:layout_height="wrap_content"
5 android:paddingTop="30dp"
6 style="@style/h1Bold"
7 android:textColor="@color/colorAccent"
8 android:text="0"/>
9<TextView
10 android:layout_width="match_parent"
11 android:layout_height="wrap_content"
12 android:paddingBottom="25dp"
13 style="@style/h2"
14 android:textColor="@color/colorAccent"
15 android:text="@string/perPersonStaticText"/>
میتوانید استایل دایرکتوری values را تغییر دهید. همچنین میتوانید با استفاده از ابزار material.io tool با مقادیر مختلف رنگی (colors) کار کنید.
استایلهایی مانند h1 و h2 روشهای خوبی برای نامگذاری استایلهای متنی محسوب میشوند. Paddings امکان ایجاد فاصلهبندی مناسب را فراهم ساخته است.
پروژه را بیلد و اجرا کنید تا مطمئن شوید که چیزی مانند تصویر زیر میبینید:
بخش مصارف به صورت آنی با ایجاد تغییر در پارامترها به محاسبه میپردازد.
ساخت بخش صورتحساب
کد زیر را درون یک LinearLayout جدید پس از بخش Expense اضافه کنید (#2):
1<LinearLayout
2 android:layout_width="match_parent"
3 android:layout_height="match_parent"
4 android:orientation="vertical"
5 android:background="@color/colorAccent">
6<! — TODO #3: Build Bill Section →
7…
8</LinearLayout>
LinearLayout را پس از لیست TODO ببندید. اکنون کد زیر را درون LinearLayout اضافه شده وارد کنید (3#):
1<TextView
2 android:layout_margin="15dp"
3 android:layout_width="match_parent"
4 android:layout_height="wrap_content"
5 android:textColor="@color/colorWhite"
6 style="@style/h4"
7 android:text="@string/billStaticText"/>
8<EditText
9 android:id="@+id/billEditText"
10 android:layout_width="match_parent"
11 android:layout_height="wrap_content"
12 android:textColor="@color/colorWhite"
13 android:inputType="numberDecimal"
14 android:maxLines="1"
15 style="@style/h2Bold"
16 android:text="0"/>
از آنجا که قابلیت اصلی این اپلیکیشن محاسبه هزینههای یک فرد است، استایل متن کمک میکند تا تأکید بیشتری روی expensePerPersonTextView داشته باشیم.
EditText ورودی را محدود به یک خط میکند و نوع ورودی باید numberDecimal باشد.
اکنون پروژه را بیلد و اجرا کنید و مجموع هزینه را وارد نمایید تا این کارکرد آزموده شود.
ساخت بخشهای Tip و People
در ادامه کد زیر را اضافه میکنیم تا یک بخش LinearLayout جدید درون همان LinearLayout درونی برای انتخاب مقدار انعام داشته باشیم:
1<TextView
2 android:layout_margin="15dp"
3 android:layout_width="match_parent"
4 android:layout_height="wrap_content"
5 android:textColor="@color/colorWhite"
6 style="@style/h4"
7 android:text="@string/tipStaticText"/>
8<LinearLayout
9 android:layout_width="match_parent"
10 android:layout_height="wrap_content"
11 android:orientation="horizontal">
12<ImageButton
13 android:id="@+id/subtractTipButton"
14 style="@style/operationButton"
15 android:layout_marginLeft="20dp"
16 android:layout_marginStart="20dp"
17 android:src="@drawable/subtract"/>
18<TextView
19 android:id="@+id/tipTextView"
20 android:layout_margin="15dp"
21 android:layout_width="0dp"
22 android:layout_height="wrap_content"
23 android:textColor="@color/colorWhite"
24 android:layout_weight="1"
25 style="@style/h2Bold"
26 android:text="20%"/>
27<ImageButton
28 android:id="@+id/addTipButton"
29 style="@style/operationButton"
30 android:layout_marginEnd="20dp"
31 android:layout_marginRight="20dp"
32 android:src="@drawable/add"/>
33</LinearLayout>
بدین ترتیب کل بخش مورد نیاز برای افزایش و کاهش مقدار انعام اضافه میشود. متن دارای اندازه پیشفرض 20 است و ImageButtons آیکونهایی دارد که در پوشه drawable قرار دارند.
بخش انتخاب تعداد افراد نیز به طور کامل شبیه بخش انتخاب انعام است. کل آن بخش را کپی بگیرید و موارد زیر را به آن اضافه کنید:
- شناسههای ImageButton (یعنی subtractPeopleButton, addPeopleButton)
- شناسههای TextView (یعنی numberOfPeopleStaticText, numberOfPeopleTextView).
- متن پیشفرض (DefaultText) برای numberOfPeopleTextView باید برابر با 4 باشد.
نکته: جهت حفظ تمیزی کد میتوانید کلیدهای Ctrl+Alt+I را بزنید تا تورفتگیهای خطوط کد به صورت خودکار تنظیم شوند.
اپلیکیشن را اجرا کنید تا مقدار صورتحساب را وارد کنید. اما با زدن کلیدهای افزودن/حذف هنوز هیچ اتفاقی نمیافتد. این لحظهای است که باید روی کارکرد اصلی اپلیکیشن متمرکز شویم.
اتصال نماها
فایل MainActivity.kt را باز کنید و کد زیر را درون تابع initViews اضافه کنید تا نماها به هم متصل شوند (6#):
1private fun initViews() {
2 expensePerPersonTextView = findViewById(R.id.expensePerPersonTextView)
3 billEditText = findViewById(R.id.billEditText)
4addTipButton = findViewById(R.id.addTipButton)
5 tipTextView = findViewById(R.id.tipTextView)
6 subtractTipButton = findViewById(R.id.subtractTipButton)
7addPeopleButton = findViewById(R.id.addPeopleButton)
8 numberOfPeopleTextView = findViewById(R.id.numberOfPeopleTextView)
9 subtractPeopleButton = findViewById(R.id.subtractPeopleButton)
10//TODO #8: Bind Buttons to Listener
11//TODO #16: Bind EditText to TextWatcher
12}
کار روی دکمههای Add/Subtract
برای مدیریت کلیک روی دکمهها، باید View.OnClickListener را در سطح کلاس پیادهسازی کنید (7#):
1class MainActivity : AppCompatActivity(), View.OnClickListener {
2…
بدین ترتیب یک خطای کامپایلر تولید میشود چون اینک باید با پیادهسازی تابع onClick درست پس از تابع initViews با listener سازگاری پیدا کنید (8#):
1override fun onClick(v: View?) {
2 when (v?.id) {
3 R.id.addTipButton -> incrementTip()
4 R.id.subtractTipButton -> decrementTip()
5 R.id.addPeopleButton -> incrementPeople()
6 R.id.subtractPeopleButton -> decrementPeople()
7 }
8 }
کاتلین قالب switch case معمولی را بسیار قدرتمندتر ساخته است. اینک این قالب خوانایی بیشتری دارد و شما را ملزم میسازد که در زمان ایجاد تابعها دقیقتر باشید. کدهای زیر را به همه تابعهای increment و decrement اضافه کنید (12#):
1private fun incrementTip() {
2 if (tipPercent != MAX_TIP) {
3 tipPercent += TIP_INCREMENT_PERCENT
4 tipTextView.text = String.format("%d%%", tipPercent)
5 }
6 }
7private fun decrementTip() {
8 if (tipPercent != MIN_TIP) {
9 tipPercent -= TIP_INCREMENT_PERCENT
10 tipTextView.text = String.format("%d%%", tipPercent)
11 }
12 }
13private fun incrementPeople() {
14 if (numberOfPeople != MAX_PEOPLE) {
15 numberOfPeople += PEOPLE_INCREMENT_VALUE
16 numberOfPeopleTextView.text = numberOfPeople.toString()
17 }
18 }
19private fun decrementPeople() {
20 if (numberOfPeople != MIN_PEOPLE) {
21 numberOfPeople -= PEOPLE_INCREMENT_VALUE
22 numberOfPeopleTextView.text = numberOfPeople.toString()
23 }
24 }
در اینجا کد از تابعهای افزایش با مقادیر بیشینه (MAX_TIP و MAX_PEOPLE) حفاظت میکند به علاوه از تابعهای کاهش نیز با مقادیر کمینه (MIN_TIP و MIN_PEOPLE) حفاظت میکند.
شنوندهها را به صورت زیر در تابعهای initViews به دکمهها bind کنید تا این اتصال تمام شود (13#):
1private fun initViews() {
2...
3addTipButton.setOnClickListener(this)
4 subtractTipButton.setOnClickListener(this)
5addPeopleButton.setOnClickListener(this)
6 subtractPeopleButton.setOnClickListener(this)
7//TODO #15: Bind EditText to TextWatcher
8}
اینک میتوانید اپلیکیشن را باز و با آن کار کنید. مثلاً میتوانید مجموع کل را تغییر دهید و یا با مقادیر دیگر کار کنید.
پیادهسازی محاسبه مصارف
اکنون کد زیر برای پیادهسازی محاسبه مصارف اضافه میکنیم (13#):
1private fun calculateExpense() {
2val totalBill = billEditText.text.toString().toDouble()
3val totalExpense = ((HUNDRED_PERCENT + tipPercent) / HUNDRED_PERCENT) * totalBill
4 val individualExpense = totalExpense / numberOfPeople
5expensePerPersonTextView.text = String.format("$%.2f", individualExpense)
6}
سپس این تابع را در هر جایی که انعام یا تعداد افراد تغییر یابند اضافه خواهیم کرد (14#):
1private fun incrementTip() {
2…
3}
4private fun decrementTip() {
5…
6}
7private fun incrementPeople() {
8…
9}
10private fun decrementPeople() {
11…
12}
اینک اگر اپلیکیشن را اجرا کنید میبینید که امکان وارد کردن مقدار صورتحساب، تنظیم انعام و افراد و مشاهده دیدن هزینه فردی را دارید که همگی به صورت آنی بهروزرسانی میشوند. اما این اپلیکیشن هنوز جای بهتر شدن دارد. اگر تلاش کنید تا مقدار صورتحساب را حذف کنید و سپس انعامها یا افراد را افزایش دهید، اپلیکیشن از کار میافتد چون هنوز هیچ اعتبارسنجی در مورد مقدار صورتحساب خالی صورت نمیگیرد. به علاوه اگر تلاش کنید مقدار صورتحساب را ویرایش کنید، هزینهها بهروزرسانی نمیشوند.
آنی ساختن محاسبه مصارف
TextWatcher را در سطح کلاس پیادهسازی کنید (#15)
1class MainActivity : AppCompatActivity(), View.OnClickListener, TextWatcher {
آن را به صورت زیر به شنونده billEditText وصل کنید (#16):
1billEditText.addTextChangedListener(this)
کدهای زیر را برای پیاده سای تابع جهت سازگاری با TextWatcher اضافه کنید (#17):
1override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
2 if (!billEditText.text.isEmpty()) {
3 calculateExpense()
4 }
5 }
6override fun afterTextChanged(s: Editable?) {}
7 override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
نکته: هر زمان که اعلانی برای وارد کردن چیزی دیدید، میتوانید از کلیدهای میانبر Alt+Enter برای ایمپورت کردت پکیج مورد نیاز استفاده کنید.
با گنجاندن afterTextChanged و beforeTextChanged برای سازگاری با TextWatcher در onTextChanged یک بررسی اعتبارسنجی پیش از محاسبه مصارف صورت میگیرد:
اکنون میتوانید اپلیکیشن را اجرا کرده و از دیدن نتیجه نهایی لذت ببرید.
سخن پایانی
در این مقاله شما موفق شدید یک اپلیکیشن ماشین حساب در کاتلین بسازید. برای دانلود و مشاهده پروژه نهایی میتوانید از این لینک (+) استفاده کنید. کاتلین یک زبان ترجیحی برای توسعه اندروید محسوب میشود که هیجان زیادی در میان جامعه توسعهدهندگان این پلتفرم برانگیخته است زیرا امکانات خوبی از قبیل استنباط نوع و ساختار منسجم ارائه میکند. قطعاً بررسی این زبان ارزش صرف وقت را دارد و بدین ترتیب میتوانید اپلیکیشنهای پیچیدهتری بسازید.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای پروژهمحور برنامهنویسی اندروید
- مجموعه آموزشهای برنامهنویسی
- آموزش عملی مقدماتی زبان برنامه نویسی کاتلین (Kotlin)
- برنامه نویسی اندروید با کاتلین — راهنمای شروع به کار
==