Рассказываем, как создать простое приложение для расчета чаевых на языке Kotlin. Если точнее, то Kotlin 1.3.21, Android 4, Android Studio 3. Статья будет интересной, в первую очередь, для тех, кто начинает свой путь в разработке Android-приложений. Она позволяет понять, что и как работает внутри приложения.
Такой калькулятор пригодится, когда нужно подсчитать сумму чаевых с компании, решившей провести время в ресторане или кафе. Конечно, не все и не всегда оставляют официантам на чай, это больше западная традиция, но процесс разработки такого приложения в любом случае интересен.
Напоминаем: для всех читателей «Хабра» — скидка 10 000 рублей при записи на любой курс Skillbox по промокоду «Хабр».Вот как выглядит приложение в процессе работы:
Skillbox рекомендует: Практический курс «Мобильный разработчик PRO.
Вы вводите желаемый процент с общей суммы, количество участников встречи и получаете результат — сумму чаевых, которые стоит оставить.
Начинаем
Полный интерфейс приложения выглядит следующим образом:
Первое действие — загрузка основы проекта. Открываем ее в Android Studio 3.0 или более поздней версии. Строим и запускаем проект и видим белый экран. Все нормально, так и должно быть.
Действия пользователя прописаны в проекте в хронологическом порядке, чтобы все было понятно. Для его просмотра открываем View -> Tool Windows -> 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"/>
Теперь можно настроить стиль директории values или поиграть с цветами, используя инструмент material.io.
Сейчас проект выглядит так:
Как видите, расчет затрат производится по данным, которые вносит пользователь.
Разработка раздела счетов
Добавляем код, размещенный ниже, в LinearLayout после Expense Section (#2):
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorAccent">
<! — TODO #3: Build Bill Section →
…
</LinearLayout>
Закрываем LinearLayout после списка TODOs, а затем добавляем новый код, размещая его внутри 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. ImageButtons снабжены иконками в папке с правами записи.
Полностью копируем раздел и добавляем следующее (#5):
- ImageButton ids (subtractPeopleButton, addPeopleButton)
- TextView ids (numberOfPeopleStaticText, numberOfPeopleTextView)
- DefaultText для numberOfPeopleTextView (должен быть 4).
Теперь при запуске приложения есть возможность добавить сумму счета, также работают кнопки «Добавить/Вычесть», но пока ничего не происходит.
Добавляем Views
Открываем 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
}
Доделываем кнопки
Чтобы добавить поддержку клика кнопок, внедряем View.OnClickListener на уровне класса (#7):
class 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 все организовано очень круто! Добавляем размещенный ниже код во все функции increment и decrement
(#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):
class MainActivity : AppCompatActivity(), View.OnClickListener, TextWatcher {
Затем встраиваем слушатель billEditText (#17):
billEditText.addTextChangedListener(this)
Плюс добавляем код для выполнения 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 рекомендует:
- Двухлетний практический курс «Я — Веб-разработчик PRO».
- Онлайн-курс «С#-разработчик».
- Практический годовой курс «PHP-разработчик с 0 до PRO».