В этом руководстве мы расскажем, как создать калькулятор на Java для Android. Если вы новичок в программировании и никогда раньше не создавали приложения, ознакомьтесь с нашим предыдущим руководством по написанию первого приложения для Android:
Предполагается, что у вас есть хотя бы минимальный базовый опыт создания Android – приложений.
Полный исходный код калькулятора, описанного ниже, доступен для использования и изменения на github.
- Создание проекта
- Включение привязки данных в проекте
- Разработка макета калькулятора
- Общие принципы создания виджетов макета
- Создание макета калькулятора
- Внутренние компоненты калькулятора
- Обработка нажатий на цифры
- Обработка кликов по кнопкам операторов
- Заключение
Первое, что нужно сделать — это создать в Android Studio новый проект: Start a new Android Studio project или File — New — New Project:
Для этого руководства мы выбрали в панели «Add an Activity to Mobile» опцию «EmptyActivity», для «MainActivity» мы оставили имя по умолчанию – «Activity». На этом этапе структура должна выглядеть, как показано на рисунке ниже. У вас есть MainActivity внутри пакета проекта и файл activity_main.xml в папке layout:
Перед тем, как создать приложение для Андроид с нуля, нужно уяснить, что использование привязки данных помогает напрямую обращаться к виджетам (Buttons, EditText и TextView), а не находить их с помощью методов findViewById(). Чтобы включить привязку данных, добавить следующую строку кода в файл build.gradle.
JAVA
android { ... dataBinding.enabled = true ...
Для включения привязки данных в файле activity_main.xml требуется еще одно изменение. Оберните сгенерированный корневой тег (RelativeLayout) в layout, таким образом сделав его новым корневым тегом.
XML
<?xml version="1.0" encoding="utf-8"?> <layout> <RelativeLayout> ... </RelativeLayout> </layout>
Как научиться создавать приложения для Андроид? Читайте наше руководство дальше.
Тег layout — это предупреждает систему построения приложения, что этот файл макета будет использовать привязку данных. Затем система генерирует для этого файла макета класс Binding. Поскольку целевой XML-файл называется activity_main.xml, система построения приложения создаст класс ActivityMainBinding, который можно использовать в приложении, как и любой другой класс Java. Имя класса составляется из имени файла макета, в котором каждое слово через подчеркивание будет начинаться с заглавной буквы, а сами подчеркивания убираются, и к имени добавляется слово «Binding».
Теперь перейдите к файлу MainActivity.java. Создайте закрытый экземпляр ActivityMainBinding внутри вашего класса, а в методе onCreate() удалите строку setContentView () и вместо нее добавьте DataBindingUtil.setContentView(), как показано ниже.
JAVA
public class MainActivity extends AppCompatActivity { private ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.activity_main); } }
В приложении калькулятора есть четыре основных элемента:
RelativeLayout — определяет, как другие элементы будут укладываться или отображаться на экране. RelativeLayout используется для позиционирования дочерних элементов по отношению друг к другу или к самим себе.
TextView — элемент используется для отображения текста. Пользователи не должны взаимодействовать с этим элементом. С помощью TextView отображается результат вычислений.
EditText — похож на элемент TextView, с той лишь разницей, что пользователи могут взаимодействовать с ним и редактировать текст. Но поскольку калькулятор допускает только фиксированный набор вводимых данных, мы устанавливаем для него статус «не редактируемый». Когда пользователь нажимает на цифры, мы выводим их в EditText.
Button — реагирует на клики пользователя. При создании простого приложения для Андроид мы используем кнопки для цифр и операторов действий в калькуляторе.
Код макета калькулятора объемный. Это связано с тем, что мы должны явно определять и тщательно позиционировать каждую из кнопок интерфейса. Ниже представлен фрагмент сокращенной версии файла макета activity_main:
<layout> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.sample.foo.samplecalculator.MainActivity"> <TextView android:id="@+id/infoTextView" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="30dp" android:textSize="30sp" /> <EditText android:id="@+id/editText" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/infoTextView" android:enabled="false" android:gravity="bottom" android:lines="2" android:maxLines="2" android:textSize="20sp" /> <Button android:id="@+id/buttonSeven" style="@style/Widget.AppCompat.Button.Borderless" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/editText" android:text="7" android:textSize="20sp" /> <Button android:id="@+id/buttonEight" style="@style/Widget.AppCompat.Button.Borderless" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/editText" android:layout_toRightOf="@id/buttonSeven" android:text="8" android:textSize="20sp" /> <Button android:id="@+id/buttonNine" style="@style/Widget.AppCompat.Button.Borderless" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/editText" android:layout_toRightOf="@id/buttonEight" android:text="9" android:textSize="20sp" /> ... ... <Button android:id="@+id/buttonDot" style="@style/Widget.AppCompat.Button.Borderless" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/buttonOne" android:text="." android:textSize="20sp" /> <Button android:id="@+id/buttonZero" style="@style/Widget.AppCompat.Button.Borderless" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignRight="@id/buttonEight" android:layout_below="@id/buttonTwo" android:text="0" android:textSize="20sp" /> <Button android:id="@+id/buttonEqual" style="@style/Widget.AppCompat.Button.Borderless" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignRight="@id/buttonNine" android:layout_below="@id/buttonThree" android:text="=" android:textSize="20sp" /> <Button android:id="@+id/buttonDivide" style="@style/Widget.AppCompat.Button.Borderless" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@id/buttonNine" android:layout_toRightOf="@id/buttonNine" android:text="/" android:textSize="20sp" /> <Button android:id="@+id/buttonMultiply" style="@style/Widget.AppCompat.Button.Borderless" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@id/buttonSix" android:layout_toRightOf="@id/buttonSix" android:text="*" android:textSize="20sp" /> <Button android:id="@+id/buttonSubtract" style="@style/Widget.AppCompat.Button.Borderless" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@id/buttonThree" android:layout_toRightOf="@id/buttonThree" android:text="-" android:textSize="20sp" /> <Button android:id="@+id/buttonAdd" style="@style/Widget.AppCompat.Button.Borderless" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@id/buttonEqual" android:layout_toRightOf="@id/buttonEqual" android:text="+" android:textSize="20sp" /> <Button android:id="@+id/buttonClear" style="@style/Widget.AppCompat.Button.Borderless" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignRight="@id/buttonAdd" android:layout_below="@id/buttonAdd" android:layout_marginTop="@dimen/activity_vertical_margin" android:text="C" android:textSize="20sp" /> </RelativeLayout> </layout>
Перед тем, как создать приложение на телефон Android, отметим, что valueOne и valueTwo содержат цифры, которые будут использоваться. Обе переменные имеют тип double, поэтому могут содержать числа с десятичными знаками и без них. Мы устанавливаем для valueOne специальное значение NaN (не число) — подробнее это будет пояснено ниже.
private double valueOne = Double.NaN; private double valueTwo;
Этот простой калькулятор сможет выполнять только операции сложения, вычитания, умножения и деления. Поэтому мы определяем четыре статических символа для представления этих операций и переменную CURRENT_ACTION, содержащую следующую операцию, которую мы намереваемся выполнить.
private static final char ADDITION = '+'; private static final char SUBTRACTION = '-'; private static final char MULTIPLICATION = '*'; private static final char DIVISION = '/'; private char CURRENT_ACTION;
Затем мы используем класс DecimalFormat для форматирования результата. Конструктор десятичного формата позволяет отображать до десяти знаков после запятой.
decimalFormat = new DecimalFormat("#.##########");
В нашем создаваемом простом приложении для Андроид всякий раз, когда пользователь нажимает на цифру или точку, нам нужно добавить эту цифру в editText. Пример кода ниже иллюстрирует, как это делается для цифры ноль (0).
binding.buttonZero.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { binding.editText.setText(binding.editText.getText() + "0"); } });
Обработка нажатия кнопок операторов (действий) выполняется по-другому. Сначала нужно выполнить все ожидающие в очереди вычисления. Поэтому мы определяем метод computeCalculation. В computeCalculation, если valueOne является допустимым числом, мы считываем valueTwo из editText и выполняем текущие операции в очереди. Если же valueOne является NaN, для valueOne присваивается цифра в editText.
JAVA
private void computeCalculation() { if(!Double.isNaN(valueOne)) { valueTwo = Double.parseDouble(binding.editText.getText().toString()); binding.editText.setText(null); if(CURRENT_ACTION == ADDITION) valueOne = this.valueOne + valueTwo; else if(CURRENT_ACTION == SUBTRACTION) valueOne = this.valueOne - valueTwo; else if(CURRENT_ACTION == MULTIPLICATION) valueOne = this.valueOne * valueTwo; else if(CURRENT_ACTION == DIVISION) valueOne = this.valueOne / valueTwo; } else { try { valueOne = Double.parseDouble(binding.editText.getText().toString()); } catch (Exception e){} } }
Продолжаем создавать копию приложения на Андроид. Для каждого оператора мы сначала вызываем computeCalculation(), а затем устанавливаем для выбранного оператора CURRENT_ACTION. Для оператора равно (=) мы вызываем computeCalculation(), а затем очищаем содержимое valueOne и CURRENT_ACTION.
JAVA
binding.buttonAdd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { computeCalculation(); CURRENT_ACTION = ADDITION; binding.infoTextView.setText(decimalFormat.format(valueOne) + "+"); binding.editText.setText(null); } }); binding.buttonSubtract.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { computeCalculation(); CURRENT_ACTION = SUBTRACTION; binding.infoTextView.setText(decimalFormat.format(valueOne) + "-"); binding.editText.setText(null); } }); binding.buttonMultiply.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { computeCalculation(); CURRENT_ACTION = MULTIPLICATION; binding.infoTextView.setText(decimalFormat.format(valueOne) + "*"); binding.editText.setText(null); } }); binding.buttonDivide.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { computeCalculation(); CURRENT_ACTION = DIVISION; binding.infoTextView.setText(decimalFormat.format(valueOne) + "/"); binding.editText.setText(null); } }); binding.buttonEqual.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { computeCalculation(); binding.infoTextView.setText(binding.infoTextView.getText().toString() + decimalFormat.format(valueTwo) + " = " + decimalFormat.format(valueOne)); valueOne = Double.NaN; CURRENT_ACTION = '0'; } });
Поздравляю! Мы завершили создание простого калькулятора. Теперь вы сможете создать приложение для Андроид сами.
Если вы запустите и протестируете данное приложение, то увидите некоторые моменты, которые можно улучшить: 1) возможность нажимать на кнопку оператора, когда editText очищен (т. е. без необходимости ввода первой цифры), 2) возможность продолжать вычисления после нажатия кнопки «Равно».
Полный код примера доступен на github.
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
androidx.constraintlayout.widget.ConstraintLayout
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:background
=
"#8BC34A"
android:backgroundTint
=
"@android:color/darker_gray"
tools:context
=
".MainActivity"
>
<
TextView
android:layout_width
=
"194dp"
android:layout_height
=
"43dp"
android:layout_marginStart
=
"114dp"
android:layout_marginLeft
=
"114dp"
android:layout_marginTop
=
"58dp"
android:layout_marginEnd
=
"103dp"
android:layout_marginRight
=
"103dp"
android:layout_marginBottom
=
"502dp"
android:scrollbarSize
=
"30dp"
android:text
=
" Calculator"
android:textAppearance
=
"@style/TextAppearance.AppCompat.Body1"
android:textSize
=
"30dp"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
EditText
android:id
=
"@+id/num1"
android:layout_width
=
"364dp"
android:layout_height
=
"28dp"
android:layout_marginStart
=
"72dp"
android:layout_marginTop
=
"70dp"
android:layout_marginEnd
=
"71dp"
android:layout_marginBottom
=
"416dp"
android:background
=
"@android:color/white"
android:ems
=
"10"
android:onClick
=
"clearTextNum1"
android:inputType
=
"number"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
EditText
android:id
=
"@+id/num2"
android:layout_width
=
"363dp"
android:layout_height
=
"30dp"
android:layout_marginStart
=
"72dp"
android:layout_marginTop
=
"112dp"
android:layout_marginEnd
=
"71dp"
android:layout_marginBottom
=
"374dp"
android:background
=
"@android:color/white"
android:ems
=
"10"
android:onClick
=
"clearTextNum2"
android:inputType
=
"number"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
TextView
android:id
=
"@+id/result"
android:layout_width
=
"356dp"
android:layout_height
=
"71dp"
android:layout_marginStart
=
"41dp"
android:layout_marginTop
=
"151dp"
android:layout_marginEnd
=
"48dp"
android:layout_marginBottom
=
"287dp"
android:background
=
"@android:color/white"
android:text
=
"result"
android:textColorLink
=
"#673AB7"
android:textSize
=
"25sp"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
Button
android:id
=
"@+id/sum"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginStart
=
"16dp"
android:layout_marginTop
=
"292dp"
android:layout_marginEnd
=
"307dp"
android:layout_marginBottom
=
"263dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doSum"
android:text
=
"+"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
Button
android:id
=
"@+id/sub"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginStart
=
"210dp"
android:layout_marginTop
=
"292dp"
android:layout_marginEnd
=
"113dp"
android:layout_marginBottom
=
"263dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doSub"
android:text
=
"-"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintHorizontal_bias
=
"1.0"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
app:layout_constraintVertical_bias
=
"0.507"
/>
<
Button
android:id
=
"@+id/div"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginStart
=
"307dp"
android:layout_marginTop
=
"292dp"
android:layout_marginEnd
=
"16dp"
android:layout_marginBottom
=
"263dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doDiv"
android:text
=
"/"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintHorizontal_bias
=
"0.0"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
Button
android:id
=
"@+id/mul"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginStart
=
"16dp"
android:layout_marginTop
=
"356dp"
android:layout_marginEnd
=
"307dp"
android:layout_marginBottom
=
"199dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doMul"
android:text
=
"x"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
Button
android:id
=
"@+id/button"
android:layout_width
=
"103dp"
android:layout_height
=
"46dp"
android:layout_marginStart
=
"113dp"
android:layout_marginTop
=
"356dp"
android:layout_marginEnd
=
"206dp"
android:layout_marginBottom
=
"199dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doMod"
android:text
=
"%(mod)"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
app:layout_constraintVertical_bias
=
"0.515"
/>
<
Button
android:id
=
"@+id/pow"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginStart
=
"113dp"
android:layout_marginTop
=
"292dp"
android:layout_marginEnd
=
"210dp"
android:layout_marginBottom
=
"263dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doPow"
android:text
=
"n1^n2"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintHorizontal_bias
=
"0.0"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
app:layout_constraintVertical_bias
=
"0.507"
/>
</
androidx.constraintlayout.widget.ConstraintLayout
>
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
androidx.constraintlayout.widget.ConstraintLayout
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:background
=
"#8BC34A"
android:backgroundTint
=
"@android:color/darker_gray"
tools:context
=
".MainActivity"
>
<
TextView
android:layout_width
=
"194dp"
android:layout_height
=
"43dp"
android:layout_marginStart
=
"114dp"
android:layout_marginLeft
=
"114dp"
android:layout_marginTop
=
"58dp"
android:layout_marginEnd
=
"103dp"
android:layout_marginRight
=
"103dp"
android:layout_marginBottom
=
"502dp"
android:scrollbarSize
=
"30dp"
android:text
=
" Calculator"
android:textAppearance
=
"@style/TextAppearance.AppCompat.Body1"
android:textSize
=
"30dp"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
EditText
android:id
=
"@+id/num1"
android:layout_width
=
"364dp"
android:layout_height
=
"28dp"
android:layout_marginStart
=
"72dp"
android:layout_marginTop
=
"70dp"
android:layout_marginEnd
=
"71dp"
android:layout_marginBottom
=
"416dp"
android:background
=
"@android:color/white"
android:ems
=
"10"
android:onClick
=
"clearTextNum1"
android:inputType
=
"number"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
EditText
android:id
=
"@+id/num2"
android:layout_width
=
"363dp"
android:layout_height
=
"30dp"
android:layout_marginStart
=
"72dp"
android:layout_marginTop
=
"112dp"
android:layout_marginEnd
=
"71dp"
android:layout_marginBottom
=
"374dp"
android:background
=
"@android:color/white"
android:ems
=
"10"
android:onClick
=
"clearTextNum2"
android:inputType
=
"number"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
TextView
android:id
=
"@+id/result"
android:layout_width
=
"356dp"
android:layout_height
=
"71dp"
android:layout_marginStart
=
"41dp"
android:layout_marginTop
=
"151dp"
android:layout_marginEnd
=
"48dp"
android:layout_marginBottom
=
"287dp"
android:background
=
"@android:color/white"
android:text
=
"result"
android:textColorLink
=
"#673AB7"
android:textSize
=
"25sp"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
Button
android:id
=
"@+id/sum"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginStart
=
"16dp"
android:layout_marginTop
=
"292dp"
android:layout_marginEnd
=
"307dp"
android:layout_marginBottom
=
"263dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doSum"
android:text
=
"+"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
Button
android:id
=
"@+id/sub"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginStart
=
"210dp"
android:layout_marginTop
=
"292dp"
android:layout_marginEnd
=
"113dp"
android:layout_marginBottom
=
"263dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doSub"
android:text
=
"-"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintHorizontal_bias
=
"1.0"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
app:layout_constraintVertical_bias
=
"0.507"
/>
<
Button
android:id
=
"@+id/div"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginStart
=
"307dp"
android:layout_marginTop
=
"292dp"
android:layout_marginEnd
=
"16dp"
android:layout_marginBottom
=
"263dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doDiv"
android:text
=
"/"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintHorizontal_bias
=
"0.0"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
Button
android:id
=
"@+id/mul"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginStart
=
"16dp"
android:layout_marginTop
=
"356dp"
android:layout_marginEnd
=
"307dp"
android:layout_marginBottom
=
"199dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doMul"
android:text
=
"x"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
Button
android:id
=
"@+id/button"
android:layout_width
=
"103dp"
android:layout_height
=
"46dp"
android:layout_marginStart
=
"113dp"
android:layout_marginTop
=
"356dp"
android:layout_marginEnd
=
"206dp"
android:layout_marginBottom
=
"199dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doMod"
android:text
=
"%(mod)"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
app:layout_constraintVertical_bias
=
"0.515"
/>
<
Button
android:id
=
"@+id/pow"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginStart
=
"113dp"
android:layout_marginTop
=
"292dp"
android:layout_marginEnd
=
"210dp"
android:layout_marginBottom
=
"263dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doPow"
android:text
=
"n1^n2"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintHorizontal_bias
=
"0.0"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
app:layout_constraintVertical_bias
=
"0.507"
/>
</
androidx.constraintlayout.widget.ConstraintLayout
>
В этом уроке мы:
— пишем приложение — калькулятор
Попробуем написать простейший калькулятор, который берет два числа и проводит с ними операции сложения, вычитания, умножения или деления. Результат отображает в виде полного выражения.
Создадим проект:
Project name: P0191_SimpleCalculator
Build Target: Android 2.3.3
Application name: SimpleCalculator
Package name: ru.startandroid.develop.simplecalculator
Create Activity: MainActivity
Откроем main.xml и нарисуем экран:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/linearLayout1" android:layout_marginLeft="10pt" android:layout_marginRight="10pt" android:layout_marginTop="3pt"> <EditText android:layout_weight="1" android:layout_height="wrap_content" android:layout_marginRight="5pt" android:id="@+id/etNum1" android:layout_width="match_parent" android:inputType="numberDecimal"> </EditText> <EditText android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginLeft="5pt" android:id="@+id/etNum2" android:layout_width="match_parent" android:inputType="numberDecimal"> </EditText> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/linearLayout2" android:layout_marginTop="3pt" android:layout_marginLeft="5pt" android:layout_marginRight="5pt"> <Button android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_weight="1" android:text="+" android:textSize="8pt" android:id="@+id/btnAdd"> </Button> <Button android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_weight="1" android:text="-" android:textSize="8pt" android:id="@+id/btnSub"> </Button> <Button android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_weight="1" android:text="*" android:textSize="8pt" android:id="@+id/btnMult"> </Button> <Button android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_weight="1" android:text="/" android:textSize="8pt" android:id="@+id/btnDiv"> </Button> </LinearLayout> <TextView android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_marginLeft="5pt" android:layout_marginRight="5pt" android:textSize="12pt" android:layout_marginTop="3pt" android:id="@+id/tvResult" android:gravity="center_horizontal"> </TextView> </LinearLayout>
Тут есть два поля ввода, 4 кнопки и текстовое поле для вывода. Обратите внимание на атрибут inputType для EditText. Он задает тип содержимого. Я указал numberDecimal – т.е. в поле получится ввести только цифры и запятую, буквы он не пропустит. Это удобно, не надо самому кодить различные проверки.
Для TextView указан атрибут gravity. Он указывает, как будет расположен текст в TextView. Не путайте с layout_gravity, который отвечает за размещение TextView в ViewGroup.
Теперь нам надо читать содержимое полей, определять какую кнопку нажали и выводить нужный результат. Открываем MainActivity.java и пишем код
public class MainActivity extends Activity implements OnClickListener { EditText etNum1; EditText etNum2; Button btnAdd; Button btnSub; Button btnMult; Button btnDiv; TextView tvResult; String oper = ""; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // находим элементы etNum1 = (EditText) findViewById(R.id.etNum1); etNum2 = (EditText) findViewById(R.id.etNum2); btnAdd = (Button) findViewById(R.id.btnAdd); btnSub = (Button) findViewById(R.id.btnSub); btnMult = (Button) findViewById(R.id.btnMult); btnDiv = (Button) findViewById(R.id.btnDiv); tvResult = (TextView) findViewById(R.id.tvResult); // прописываем обработчик btnAdd.setOnClickListener(this); btnSub.setOnClickListener(this); btnMult.setOnClickListener(this); btnDiv.setOnClickListener(this); } @Override public void onClick(View v) { // TODO Auto-generated method stub float num1 = 0; float num2 = 0; float result = 0; // Проверяем поля на пустоту if (TextUtils.isEmpty(etNum1.getText().toString()) || TextUtils.isEmpty(etNum2.getText().toString())) { return; } // читаем EditText и заполняем переменные числами num1 = Float.parseFloat(etNum1.getText().toString()); num2 = Float.parseFloat(etNum2.getText().toString()); // определяем нажатую кнопку и выполняем соответствующую операцию // в oper пишем операцию, потом будем использовать в выводе switch (v.getId()) { case R.id.btnAdd: oper = "+"; result = num1 + num2; break; case R.id.btnSub: oper = "-"; result = num1 - num2; break; case R.id.btnMult: oper = "*"; result = num1 * num2; break; case R.id.btnDiv: oper = "/"; result = num1 / num2; break; default: break; } // формируем строку вывода tvResult.setText(num1 + " " + oper + " " + num2 + " = " + result); } }
Думаю, все понятно по каментам. Читаем значения, определяем кнопку, выполняем операцию и выводим в текстовое поле. Обработчиком нажатий на кнопки выступает Activity.
Все сохраним и запустим.
Давайте для большего функционала сделаем меню с пунктами очистки полей и выхода из приложения. Пункты будут называться Reset и Quit.
Добавим две константы – это будут ID пунктов меню.
public class MainActivity extends Activity implements OnClickListener { final int MENU_RESET_ID = 1; final int MENU_QUIT_ID = 2; EditText etNum1;
(добавляете только строки 3 и 4)
И напишем код создания и обработки меню:
// создание меню @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, MENU_RESET_ID, 0, "Reset"); menu.add(0, MENU_QUIT_ID, 0, "Quit"); return super.onCreateOptionsMenu(menu); } // обработка нажатий на пункты меню @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_RESET_ID: // очищаем поля etNum1.setText(""); etNum2.setText(""); tvResult.setText(""); break; case MENU_QUIT_ID: // выход из приложения finish(); break; } return super.onOptionsItemSelected(item); }
Сохраним все, запустим. Появилось два пункта меню:
Reset – очищает все поля
Quit – закрывает приложение
В качестве самостоятельной работы вы можете реализовать проверку деления на ноль. И выводить какое-нить сообщение с помощью Toast или прямо в поле результата.
На следующем уроке:
— рассмотрим анимацию View-компонентов
Присоединяйтесь к нам в Telegram:
— в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
— в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance
— ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
androidx.constraintlayout.widget.ConstraintLayout
android:layout_width
=
"match_parent"
android:layout_height
=
"match_parent"
android:background
=
"#8BC34A"
android:backgroundTint
=
"@android:color/darker_gray"
tools:context
=
".MainActivity"
>
<
TextView
android:id
=
"@+id/textView"
android:layout_width
=
"133dp"
android:layout_height
=
"28dp"
android:layout_marginStart
=
"139dp"
android:layout_marginLeft
=
"139dp"
android:layout_marginTop
=
"16dp"
android:layout_marginEnd
=
"139dp"
android:layout_marginRight
=
"139dp"
android:layout_marginBottom
=
"559dp"
android:background="#0F9D58"
android:text="gfg_myFirstApp"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<
TextView
android:layout_width
=
"194dp"
android:layout_height
=
"43dp"
android:layout_marginStart
=
"114dp"
android:layout_marginLeft
=
"114dp"
android:layout_marginTop
=
"58dp"
android:layout_marginEnd
=
"103dp"
android:layout_marginRight
=
"103dp"
android:layout_marginBottom
=
"502dp"
android:scrollbarSize
=
"30dp"
android:text
=
" Calculator"
android:textAppearance
=
"@style/TextAppearance.AppCompat.Body1"
android:textSize
=
"30dp"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
EditText
android:id
=
"@+id/num1"
android:layout_width
=
"364dp"
android:layout_height
=
"28dp"
android:layout_marginStart
=
"72dp"
android:layout_marginTop
=
"70dp"
android:layout_marginEnd
=
"71dp"
android:layout_marginBottom
=
"416dp"
android:background
=
"@android:color/white"
android:ems
=
"10"
android:hint
=
"Number1(0)"
android:inputType
=
"number"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
EditText
android:id
=
"@+id/num2"
android:layout_width
=
"363dp"
android:layout_height
=
"30dp"
android:layout_marginStart
=
"72dp"
android:layout_marginTop
=
"112dp"
android:layout_marginEnd
=
"71dp"
android:layout_marginBottom
=
"374dp"
android:background
=
"@android:color/white"
android:ems
=
"10"
android:hint
=
"number2(0)"
android:inputType
=
"number"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
TextView
android:id
=
"@+id/result"
android:layout_width
=
"356dp"
android:layout_height
=
"71dp"
android:layout_marginStart
=
"41dp"
android:layout_marginTop
=
"151dp"
android:layout_marginEnd
=
"48dp"
android:layout_marginBottom
=
"287dp"
android:background
=
"@android:color/white"
android:text
=
"result"
android:textColorLink
=
"#673AB7"
android:textSize
=
"25sp"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
Button
android:id
=
"@+id/sum"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginStart
=
"16dp"
android:layout_marginTop
=
"292dp"
android:layout_marginEnd
=
"307dp"
android:layout_marginBottom
=
"263dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doSum"
android:text
=
"+"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
Button
android:id
=
"@+id/sub"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginStart
=
"210dp"
android:layout_marginTop
=
"292dp"
android:layout_marginEnd
=
"113dp"
android:layout_marginBottom
=
"263dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doSub"
android:text
=
"-"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
Button
android:id
=
"@+id/div"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginStart
=
"307dp"
android:layout_marginTop
=
"292dp"
android:layout_marginEnd
=
"16dp"
android:layout_marginBottom
=
"263dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doDiv"
android:text
=
"/"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintHorizontal_bias
=
"0.0"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
Button
android:id
=
"@+id/mul"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginStart
=
"16dp"
android:layout_marginTop
=
"356dp"
android:layout_marginEnd
=
"307dp"
android:layout_marginBottom
=
"199dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doMul"
android:text
=
"x"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
Button
android:id
=
"@+id/button"
android:layout_width
=
"92dp"
android:layout_height
=
"48dp"
android:layout_marginStart
=
"113dp"
android:layout_marginTop
=
"356dp"
android:layout_marginEnd
=
"206dp"
android:layout_marginBottom
=
"199dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doMod"
android:text
=
"%(mod)"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
<
Button
android:id
=
"@+id/pow"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:layout_marginStart
=
"113dp"
android:layout_marginTop
=
"292dp"
android:layout_marginEnd
=
"210dp"
android:layout_marginBottom
=
"263dp"
android:backgroundTint
=
"@android:color/holo_red_light"
android:onClick
=
"doPow"
android:text
=
"n1^n2"
app:layout_constraintBottom_toBottomOf
=
"parent"
app:layout_constraintEnd_toEndOf
=
"parent"
app:layout_constraintStart_toStartOf
=
"parent"
app:layout_constraintTop_toTopOf
=
"parent"
/>
</
androidx.constraintlayout.widget.ConstraintLayout
>
Приложение Калькулятор
Последнее обновление: 15.10.2021
Зная некоторые основы компоновки и такие элементы как TextView, EditText и Button, уже можно составить более менее полноценное приложение. В данном случае мы сделаем простенький калькулятор.
Для этого создадим новый проект и определим в файле activity_main.xml следующий интерфейс:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="8dp"> <!-- поле результата --> <TextView android:id="@+id/resultField" android:layout_width="0dp" android:layout_height="wrap_content" app:layout_constraintHorizontal_weight="1" android:textSize="18sp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/operationField"/> <!-- поле знака операции --> <TextView android:id="@+id/operationField" android:layout_width="0dp" android:layout_height="wrap_content" app:layout_constraintHorizontal_weight="1" android:textSize="18sp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintLeft_toRightOf="@+id/resultField" /> <!-- поле ввода чисел --> <EditText android:id="@+id/numberField" android:layout_width="0dp" android:layout_height="wrap_content" android:inputType="phone" app:layout_constraintTop_toBottomOf="@+id/resultField" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"/> <LinearLayout android:id="@+id/firstButtonPanel" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="16dp" app:layout_constraintTop_toBottomOf="@+id/numberField" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="7" android:onClick="onNumberClick"/> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="8" android:onClick="onNumberClick"/> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="9" android:onClick="onNumberClick"/> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="/" android:onClick="onOperationClick"/> </LinearLayout> <LinearLayout android:id="@+id/secondButtonPanel" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="16dp" app:layout_constraintTop_toBottomOf="@+id/firstButtonPanel" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="4" android:onClick="onNumberClick"/> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="5" android:onClick="onNumberClick"/> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="6" android:onClick="onNumberClick"/> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="*" android:onClick="onOperationClick"/> </LinearLayout> <LinearLayout android:id="@+id/thirdButtonPanel" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="16dp" app:layout_constraintTop_toBottomOf="@+id/secondButtonPanel" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="1" android:onClick="onNumberClick"/> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="2" android:onClick="onNumberClick"/> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="3" android:onClick="onNumberClick"/> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="-" android:onClick="onOperationClick"/> </LinearLayout> <LinearLayout android:id="@+id/forthButtonPanel" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="16dp" app:layout_constraintTop_toBottomOf="@+id/thirdButtonPanel" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="0" android:onClick="onNumberClick"/> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="," android:onClick="onNumberClick"/> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="+" android:onClick="onOperationClick"/> <Button android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="=" android:onClick="onOperationClick"/> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>
В итоге весь интерфейс будет выглядеть следующим образом:
Корневой контейнер компоновки представляет элемент ConstraintLayout . Сверху в нем определены два текстовых поля TextView: одно для вывода результата вычислений и одно для вывода текущего знака операции.
Затем идет элемент EditText, предназначенный для ввода чисел.
И далее расположены четыре элемента LinearLayout с горизонтальными рядами кнопок. Чтобы все кнопки занимали равное пространство внутри контейнера, для них установлены атрибуты
android:layout_weight="1"
и android:layout_width="0dp"
.
Кроме того, для числовых кнопок в качестве обработчика нажатия установлен метод onNumberClick
, а для кнопок со знаками операций атрибут onClick
указывает на метод onOperationClick
.
Теперь изменим класс MainActivity:
package com.example.viewapp; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class MainActivity extends AppCompatActivity { TextView resultField; // текстовое поле для вывода результата EditText numberField; // поле для ввода числа TextView operationField; // текстовое поле для вывода знака операции Double operand = null; // операнд операции String lastOperation = "="; // последняя операция @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // получаем все поля по id из activity_main.xml resultField = findViewById(R.id.resultField); numberField = findViewById(R.id.numberField); operationField = findViewById(R.id.operationField); } // сохранение состояния @Override protected void onSaveInstanceState(Bundle outState) { outState.putString("OPERATION", lastOperation); if(operand!=null) outState.putDouble("OPERAND", operand); super.onSaveInstanceState(outState); } // получение ранее сохраненного состояния @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); lastOperation = savedInstanceState.getString("OPERATION"); operand= savedInstanceState.getDouble("OPERAND"); resultField.setText(operand.toString()); operationField.setText(lastOperation); } // обработка нажатия на числовую кнопку public void onNumberClick(View view){ Button button = (Button)view; numberField.append(button.getText()); if(lastOperation.equals("=") && operand!=null){ operand = null; } } // обработка нажатия на кнопку операции public void onOperationClick(View view){ Button button = (Button)view; String op = button.getText().toString(); String number = numberField.getText().toString(); // если введенно что-нибудь if(number.length()>0){ number = number.replace(',', '.'); try{ performOperation(Double.valueOf(number), op); }catch (NumberFormatException ex){ numberField.setText(""); } } lastOperation = op; operationField.setText(lastOperation); } private void performOperation(Double number, String operation){ // если операнд ранее не был установлен (при вводе самой первой операции) if(operand ==null){ operand = number; } else{ if(lastOperation.equals("=")){ lastOperation = operation; } switch(lastOperation){ case "=": operand =number; break; case "/": if(number==0){ operand =0.0; } else{ operand /=number; } break; case "*": operand *=number; break; case "+": operand +=number; break; case "-": operand -=number; break; } } resultField.setText(operand.toString().replace('.', ',')); numberField.setText(""); } }
Разберем этот код. Вначале в методе onCreate()
получаем все поля из activity_main.xml, текст которых будет изменяться:
resultField = findViewById(R.id.resultField); numberField = findViewById(R.id.numberField); operationField = findViewById(R.id.operationField);
Результат операции будет попадать в переменную operand, которая представляет тип Double, а знак операции — в переменную lastOperation:
Double operand = null; String lastOperation = "=";
Так как при переходе от портретной ориентации к альбомной или наоборот мы можем потерять все введенные данные, то чтобы их не потерять, мы их сохраняем в методе
onSaveInstanceState()
и обратно получаем в методе onRestoreInstanceState()
.
При нажатии на числовую кнопку будет вызываться метод onNumberClick
, в котором добавляем введенную цифру или знак запятой к тексту в поле numberField:
Button button = (Button)view; numberField.append(button.getText()); if(lastOperation.equals("=") && operand!=null){ operand = null; }
При этом если последняя операция представляла собой получение результата (знак «равно»), то мы сбрасываем переменную operand.
В методе onOperationClick
происходит обработка нажатия на кнопку со знаком операции:
Button button = (Button)view; String op = button.getText().toString(); String number = numberField.getText().toString(); if(number.length()>0){ number = number.replace(',', '.'); try{ performOperation(Double.valueOf(number), op); }catch (NumberFormatException ex){ numberField.setText(""); } } lastOperation = op; operationField.setText(lastOperation);
Здесь получаем ранее введенное число и введенную операцию и передаем их в метод performOperation()
. Так как в метод передается не просто строка, а число
Double, то нам надо преобразовать строку в чсло. И поскольку теоретически могут быть введены нечисловые символы, то для отлова исключения, которое может возникнуть при преобразовании
используется конструкция try…catch.
Кроме того, так как разделителем целой и дробной части в Double в java является точка, то нам надо заменить запятую на точку, так как предполагается, что мы используем в качестве разделителя запятую.
А методе performOperation()
выполняем собственно операцию. При вводе первой операции, когда операнд еще не установлен, мы просто устанавливаем операнд:
if(operand ==null){ operand = number; }
При вводе второй и последующих операций применяем предыдущую операцию, знак которой хранится в переменной lastOperation, к операнду operand и второму числу, которое было введено в числовое поле.
Полученный результат операции сохраняем в переменной operand.
xml version = 1.0 encoding = utf-8 ?>
< RelativeLayout xmlns : android = http://schemas.android.com/apk/res/android
xmlns : tools = http://schemas.android.com/tools
Android : ID = @ + ID / родственник1
android : layout_width = match_parent
android : layout_height = match_parent
tools : context = .MainActivity >
< EditText
android : id = @ + id / edt1
android : layout_width = match_parent
android : layout_height = wrap_content / >
< Кнопка
android : id = @ + id / button1
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_alignEnd = @ + id / button4
android : layout_alignRight = @ + id / button4
android : layout_below = @ + id / edt1
android : layout_marginTop = 94dp
android : text = 1 / >
< Кнопка
android : id = @ + id / button2
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_alignTop = @ + id / button1
android : layout_toLeftOf = @ + id / button3
android : layout_toStartOf = @ + id / button3
android : text = 2 / >
< Кнопка
android : id = @ + id / button3
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_alignTop = @ + id / button2
android : layout_centerHor horizontal = true
android : text = 3 / >
< Кнопка
android : id = @ + id / button4
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_below = @ + id / button1
android : layout_toLeftOf = @ + id / button2
android : text = 4 / >
< Кнопка
android : id = @ + id / button5
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_alignBottom = @ + id / button4
android : layout_alignLeft = @ + id / button2
android : layout_alignStart = @ + id / button2
android : text = 5 / >
< Кнопка
android : id = @ + id / button6
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_alignLeft = @ + id / button3
android : layout_alignStart = @ + id / button3
android : layout_below = @ + id / button3
android : text = 6 / >
< Кнопка
android : id = @ + id / button7
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_below = @ + id / button4
android : layout_toLeftOf = @ + id / button2
android : text = 7 / >
< Кнопка
android : id = @ + id / button8
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_alignLeft = @ + id / button5
android : layout_alignStart = @ + id / button5
android : layout_below = @ + id / button5
android : text = 8 / >
< Кнопка
android : id = @ + id / button9
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_alignLeft = @ + id / button6
android : layout_alignStart = @ + id / button6
android : layout_below = @ + id / button6
android : text = 9 / >
< Кнопка
android : id = @ + id / buttonadd
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_alignEnd = @ + id / edt1
android : layout_alignRight = @ + id / edt1
android : layout_alignTop = @ + id / button3
android : layout_marginLeft = 46dp
android : layout_marginStart = 46dp
android : layout_toRightOf = @ + id / button3
android : text = + / >
< Кнопка
android : id = @ + id / buttonsub
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_alignEnd = @ + id / buttonadd
android : layout_alignLeft = @ + id / buttonadd
android : layout_alignRight = @ + id / buttonadd
android : layout_alignStart = @ + id / buttonadd
android : layout_below = @ + id / buttonadd
android : text = — / >
< Кнопка
android : id = @ + id / buttonmul
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_alignLeft = @ + id / buttonsub
android : layout_alignParentEnd = true
android : layout_alignParentRight = true
android : layout_alignStart = @ + id / buttonsub
android : layout_below = @ + id / buttonsub
android : text = * / >
< Кнопка
android : id = @ + id / button10
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_below = @ + id / button7
android : layout_toLeftOf = @ + id / button2
android : text = . / >
< Кнопка
android : id = @ + id / button0
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_alignLeft = @ + id / button8
android : layout_alignStart = @ + id / button8
android : layout_below = @ + id / button8
android : text = / >
< Кнопка
android : id = @ + id / buttonC
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_alignLeft = @ + id / button9
android : layout_alignStart = @ + id / button9
android : layout_below = @ + id / button9
android : text = C / >
< Кнопка
android : id = @ + id / buttondiv
style = ? android: attr / buttonStyleSmall
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_alignEnd = @ + id / buttonmul
android : layout_alignLeft = @ + id / buttonmul
android : layout_alignRight = @ + id / buttonmul
android : layout_alignStart = @ + id / buttonmul
android : layout_below = @ + id / buttonmul
android : text = / / >
< Кнопка
android : id = @ + id / buttoneql
android : layout_width = wrap_content
android : layout_height = wrap_content
android : layout_alignEnd = @ + id / buttondiv
android : layout_alignLeft = @ + id / button10
android : layout_alignRight = @ + id / buttondiv
android : layout_alignStart = @ + id / button10
android : layout_below = @ + id / button0
android : layout_marginTop = 37dp
android : text = = / >
< / RelativeLayout >
Здравствуйте.
Изучаю разработку под Андроид, пишу банальные задачки (сейчас — калькулятор).
И вот собственно встал вопрос — строку с выражением я сформировал, как мне теперь её посчитать? Если бы у меня сложный калькулятор, то использовал бы методы обратной польской записи и другие уже известные алгоритмы. Но у меня +, -, *, /. В скриптовых языках я бы использовал что-то вроде eval(), а вот тут запнулся…
Помогите, если сталкивались, пожалуйста
задан 9 ноя 2012 в 19:47
andrewshkaandrewshka
1,6052 золотых знака30 серебряных знаков59 бронзовых знаков
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<EditText
android:id="@+id/editText1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="number" >
<requestFocus />
</EditText>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<Button
android:id="@+id/button1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:text=" 1 " />
<Button
android:id="@+id/button2"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text=" 2 " />
<Button
android:id="@+id/button3"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text=" 3 " />
<Button
android:id="@+id/button4"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text=" + " />
<Button
android:id="@+id/button5"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text=" - " />
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<Button
android:id="@+id/button6"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:text=" 4 " />
<Button
android:id="@+id/button7"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text=" 5 " />
<Button
android:id="@+id/button8"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text=" 6 " />
<Button
android:id="@+id/button9"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text=" / " />
<Button
android:id="@+id/button10"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text=" * " />
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<Button
android:id="@+id/button11"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:text=" 7 " />
<Button
android:id="@+id/button12"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text=" 8 " />
<Button
android:id="@+id/button13"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text=" 9 " />
<Button
android:id="@+id/button20"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text=" 0 " />
<Button
android:id="@+id/button14"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text=" = " />
</TableRow>
<TableRow
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<Button
android:id="@+id/button16"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="Decimal" />
<Button
android:id="@+id/button23"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="Binary" />
<Button
android:id="@+id/button22"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="Clear" />
</TableRow>
</LinearLayout>
Activity.java
package calc.calc;
import java.util.ArrayList;
import android.app.Activity;
import android.os.Bundle;
import android.text.method.DigitsKeyListener;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
public class CalcActivity extends Activity {
/**Переменная текстбокса*/
EditText calcDialogDisplay;
/**Переменные кнопок*/
TextView binary;
TextView allClear;
TextView seven;
TextView eight;
TextView nine;
TextView division;
TextView four;
TextView five;
TextView six;
TextView multiply;
TextView one;
TextView two;
TextView three;
TextView subtract;
TextView decimal;
TextView zero;
TextView equals;
TextView addition;
/**Результат который заносится в масив для обработки*/
ArrayList<Float> result = new ArrayList<Float>();
/**Первое введенное число*/
float number1;
/**Второе введенное число*/
float number2;
int currentOperation = 0;
int nextOperation;
/**Прибавление*/
final static int ADD = 1;
/**Вычитание*/
final static int SUBTRACT = 2;
/**Умножение*/
final static int MULTIPLY = 3;
/**Деление*/
final static int DIVISION = 4;
/**Равно*/
final static int EQUALS = 5;
/**Нахождение целого значение из двоичного числа*/
final static int DECIMAL = 6;
/**Нахождение двоичного числа из целого*/
final static int BINARY = 7;
final static int CLEAR = 1;
final static int DONT_CLEAR = 0;
int clearCalcDisplay = 0;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
calcDialogDisplay = (EditText) findViewById(R.id.editText1);
binary = (TextView) findViewById(R.id.button23);
allClear = (TextView) findViewById(R.id.button22);
seven = (TextView) findViewById(R.id.button11);
eight = (TextView) findViewById(R.id.button12);
nine = (TextView) findViewById(R.id.button13);
division =(TextView) findViewById(R.id.button9);
four = (TextView) findViewById(R.id.button6);
five = (TextView) findViewById(R.id.button7);
six =(TextView) findViewById(R.id.button8);
multiply = (TextView) findViewById(R.id.button10);
one = (TextView) findViewById(R.id.button1);
two = (TextView) findViewById(R.id.button2);
three = (TextView) findViewById(R.id.button3);
subtract = (TextView) findViewById(R.id.button5);
decimal = (TextView) findViewById(R.id.button16);
zero = (TextView) findViewById(R.id.button20);
equals = (TextView) findViewById(R.id.button14);
//addition = (TextView) findViewById(R.id.addition);
calcDialogDisplay.setKeyListener(DigitsKeyListener.getInstance(true,true));
registerListeners();
}
/*Обработка нажатия на экран*/
public void registerListeners () {
seven.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (clearCalcDisplay == CLEAR) {
calcDialogDisplay.setText("");
}
clearCalcDisplay = DONT_CLEAR;
calcDialogDisplay.append("7");
}
});
eight.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (clearCalcDisplay == CLEAR) {
calcDialogDisplay.setText("");
}
clearCalcDisplay = DONT_CLEAR;
calcDialogDisplay.append("8");
}
});
nine.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (clearCalcDisplay == CLEAR) {
calcDialogDisplay.setText("");
}
clearCalcDisplay = DONT_CLEAR;
calcDialogDisplay.append("9");
}
});
division.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
calcLogic(DIVISION);
}
});
allClear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
calcDialogDisplay.setText("");
number1 = 0;
number2 = 0;
result.removeAll(result);
currentOperation = 0;
nextOperation = 0;
}
});
four.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (clearCalcDisplay == CLEAR) {
calcDialogDisplay.setText("");
}
clearCalcDisplay = DONT_CLEAR;
calcDialogDisplay.append("4");
}
});
five.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (clearCalcDisplay == CLEAR) {
calcDialogDisplay.setText("");
}
clearCalcDisplay = DONT_CLEAR;
calcDialogDisplay.append("5");
}
});
six.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (clearCalcDisplay == CLEAR) {
calcDialogDisplay.setText("");
}
clearCalcDisplay = DONT_CLEAR;
calcDialogDisplay.append("6");
}
});
zero.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (clearCalcDisplay == CLEAR) {
calcDialogDisplay.setText("");
}
clearCalcDisplay = DONT_CLEAR;
calcDialogDisplay.append("0");
}
});
decimal.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
calcLogic(DECIMAL);
}
});
multiply.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
calcLogic(MULTIPLY);
}
});
one.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (clearCalcDisplay == CLEAR) {
calcDialogDisplay.setText("");
}
clearCalcDisplay = DONT_CLEAR;
calcDialogDisplay.append("1");
}
});
two.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (clearCalcDisplay == CLEAR) {
calcDialogDisplay.setText("");
}
clearCalcDisplay = DONT_CLEAR;
calcDialogDisplay.append("2");
}
});
three.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (clearCalcDisplay == CLEAR) {
calcDialogDisplay.setText("");
}
clearCalcDisplay = DONT_CLEAR;
calcDialogDisplay.append("3");
}
});
subtract.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
calcLogic(SUBTRACT);
}
});
equals.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
calcLogic(EQUALS);
}
});
binary.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
calcLogic(BINARY);
}
});
}
/*Функция перевода из десятичного в двоичное значение*/
private float decToBin(float bin) {
int i, b;
long result = 0;
for(i=0; bin > 0; i++) {
b = (int) (bin % 2);
bin = (bin-b)/2;
result += b * Math.pow(10,i);
}
return result;
}
/*Функция перевода из двличного в десятичное значение*/
private float binToDec(float dec) {
int result = 0;
int mult = 1;
while(dec > 0) {
result += mult * ((int)dec % 10);
dec /= 10;
mult *= 2;
}
return result;
}
/*Функция расчета введенных значений*/
private void calcLogic(int operator) {
result.add(Float.parseFloat(calcDialogDisplay.getText().toString()));
if (operator != EQUALS) {
nextOperation = operator;
}else if (operator == EQUALS){
nextOperation = 0;
}
switch (currentOperation) {
/*Прибавление*/
case ADD:
number1 = result.get(0);
number2 = result.get(1);
result.removeAll(result);
result.add(number1 + number2);
calcDialogDisplay.setText(String.format("%.0f", result.get(0)));
break;
/*Вычитание*/
case SUBTRACT:
number1 = result.get(0);
number2 = result.get(1);
result.removeAll(result);
result.add(number1 - number2);
calcDialogDisplay.setText(String.format("%.0f", result.get(0)));
break;
/*Умножение*/
case MULTIPLY:
number1 = result.get(0);
number2 = result.get(1);
result.removeAll(result);
result.add(number1 * number2);
calcDialogDisplay.setText(String.format("%.0f", result.get(0)));
break;
/*Деление*/
case DIVISION:
number1 = result.get(0);
number2 = result.get(1);
result.removeAll(result);
result.add(number1 / number2);
calcDialogDisplay.setText(String.format("%.0f", result.get(0)));
break;
/*Получание двоичного числа*/
case DECIMAL:
number2 = result.get(1);
result.removeAll(result);
result.add(decToBin(number2));
calcDialogDisplay.setText(String.format("%.0f", result.get(0)));
break;
/*Получение десятичного числа*/
case BINARY:
number2 = result.get(1);
result.removeAll(result);
result.add(binToDec(number2));
calcDialogDisplay.setText(String.format("%.0f", result.get(0)));
break;
}
clearCalcDisplay = CLEAR;
currentOperation = nextOperation;
if (operator == EQUALS) {
number1 = 0;
number2 = 0;
result.removeAll(result);
}
}
}
Когда — то давно прогал для собеседования
ответ дан 9 ноя 2012 в 21:51
5
Парсите строку и складывайте числа, если после числа идет пробел(ы), или «+»,»-» если пробелы и «*», «/» то сначала выполните действие и посмотрите дальше (рекурсия), если потом число, то складывайте, если нет повторите.
ответ дан 9 ноя 2012 в 19:51
gadfilgadfil
2,6291 золотой знак14 серебряных знаков23 бронзовых знака
2