Приложение Калькулятор

Последнее обновление: 27.11.2023

Зная некоторые основы компоновки и такие элементы как 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:id="@+id/n7" />
        <Button
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="8"
            android:id="@+id/n8"/>
        <Button
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="9"
            android:id="@+id/n9"/>
        <Button
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="/"
            android:id="@+id/div"/>
    </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:id="@+id/n4"/>
        <Button
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="5"
            android:id="@+id/n5"/>
        <Button
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="6"
            android:id="@+id/n6"/>
        <Button
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="*"
            android:id="@+id/mul"/>
    </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:id="@+id/n1"/>
        <Button
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="2"
            android:tag="num"
            android:id="@+id/n2"/>
        <Button
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="3"
            android:id="@+id/n3"/>
        <Button
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="-"
            android:id="@+id/sub" />
    </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:id="@+id/n0"/>
        <Button
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text=","
            android:id="@+id/comma"/>
        <Button
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="+"
            android:id="@+id/add"/>
        <Button
            android:layout_weight="1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="="
            android:id="@+id/eq"/>
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

В итоге весь интерфейс будет выглядеть следующим образом:

Калькулятор на Android и Java

Корневой контейнер компоновки представляет элемент ConstraintLayout . Сверху в нем определены два текстовых поля TextView: одно для вывода результата вычислений и одно для вывода текущего знака операции.

Затем идет элемент EditText, предназначенный для ввода чисел.

И далее расположены четыре элемента LinearLayout с горизонтальными рядами кнопок. Чтобы все кнопки занимали равное пространство внутри контейнера, для них установлены атрибуты android:layout_weight="1" и android:layout_width="0dp".

Для каждой кнопки установлен идентификатор, чтобы в коде можно было прикрепить к ней определенный обработчик нажатия.

Теперь изменим класс MainActivity:

package com.metanit.calculator;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
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);

        findViewById(R.id.add).setOnClickListener((view)->onOperationClick("+"));
        findViewById(R.id.sub).setOnClickListener((view)->onOperationClick("-"));
        findViewById(R.id.mul).setOnClickListener((view)->onOperationClick("*"));
        findViewById(R.id.div).setOnClickListener((view)->onOperationClick("/"));
        findViewById(R.id.eq).setOnClickListener((view)->onOperationClick("="));

        findViewById(R.id.n0).setOnClickListener((view)->onNumberClick("0"));
        findViewById(R.id.n1).setOnClickListener((view)->onNumberClick("1"));
        findViewById(R.id.n2).setOnClickListener((view)->onNumberClick("2"));
        findViewById(R.id.n3).setOnClickListener((view)->onNumberClick("3"));
        findViewById(R.id.n4).setOnClickListener((view)->onNumberClick("4"));
        findViewById(R.id.n5).setOnClickListener((view)->onNumberClick("5"));
        findViewById(R.id.n6).setOnClickListener((view)->onNumberClick("6"));
        findViewById(R.id.n7).setOnClickListener((view)->onNumberClick("7"));
        findViewById(R.id.n8).setOnClickListener((view)->onNumberClick("8"));
        findViewById(R.id.n9).setOnClickListener((view)->onNumberClick("9"));
        findViewById(R.id.comma).setOnClickListener((view)->onNumberClick(","));
    }
    // сохранение состояния
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putString("OPERATION", lastOperation);
        if(operand!=null)
            outState.putDouble("OPERAND", operand);
        super.onSaveInstanceState(outState);
    }
    // получение ранее сохраненного состояния
    @Override
    protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        lastOperation = savedInstanceState.getString("OPERATION");
        operand= savedInstanceState.getDouble("OPERAND");
        resultField.setText(operand.toString());
        operationField.setText(lastOperation);
    }
    // обработка нажатия на числовую кнопку
    public void onNumberClick(String number){
        numberField.append(number);
        if(lastOperation.equals("=") && operand!=null){
            operand = null;
        }
    }
    // обработка нажатия на кнопку операции
    public void onOperationClick(String op){

        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);

Далее для каждой кнопки назначаем определенный обработчик нажатия - в зависимости от типа кнопки это либо метод onNumberClick, в который передается нажатое число, либо onOperationClick, в который передается знак операции.

Результат операции будет попадать в переменную operand, которая представляет тип Double, а знак операции - в переменную lastOperation:

Double operand = null;
String lastOperation = "=";

Так как при переходе от портретной ориентации к альбомной или наоборот мы можем потерять все введенные данные, то чтобы их не потерять, мы их сохраняем в методе onSaveInstanceState() и обратно получаем в методе onRestoreInstanceState().

При нажатии на числовую кнопку будет вызываться метод onNumberClick, в котором добавляем введенную цифру или знак запятой к тексту в поле numberField:

numberField.append(number);

if(lastOperation.equals("=") && operand!=null){
    operand = null;
}

При этом если последняя операция представляла собой получение результата (знак "равно"), то мы сбрасываем переменную operand.

В методе onOperationClick происходит обработка нажатия на кнопку со знаком операции:

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.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850