Slevový týden - Květen Office week
Pouze tento týden sleva až 80 % na e-learning týkající se MS Office
30 % bodů zdarma na online výuku díky naší Slevové akci!

Lekce 8 - Android programování - Implementace Java kódu kalkulačky

V minulé lekci, Android programování - ConstraintLayout, jsme si představili základní vlastnosti ConstraintLayout.

V dnešní lekci si konečně ukážeme Java kód budoucí kalkulačky a dostaneme se tedy k programování!

Java kód aplikace

Kód budeme psát do souboru MainActivity.java.

Deklarace proměnných

Ve třídě MainActivity si nejprve deklarujeme proměnné, potřebné k činnosti aplikace:

private TextView obraz;
private TextView cislo1;
private TextView cislo2;
private TextView operace;

private boolean prosel = false;
private boolean c1Nastaven = false;

private double c1;
private double c2;
private double vys;

private int metoda = 0;

private boolean prosel = false;
private boolean c1Nastaven = false;

private double c1;
private double c2;
private double vys;
private int metoda = 0;

Pojďme si je popsat:

  • obraz, cislo1, cislo2, operace - Objekty typu TextView, přes které budeme pracovat s komponentami pro zadávání textu, které jsme si definovali v XML rozvržení aktivity.
  • c1, c2 a vys - Slouží k ukládání čísel jak typ double, abychom s nimi mohli opravdu počítat.
  • metoda - Slouží pro uchování informace o tom, jakou operaci uživatel zvolil.
  • prosel a c1Nastaven - Jsou boolean proměnné pro řídící účely aplikace. Pomocí nich ošetřujeme možné problémy se zadáváním čísel a ujistíme se, že máme zadáno c1, když chceme počítat dál.

V kódu si nebudeme uvádět komentáře, jelikož si metody popisujeme zde v článku.

Metoda onCreate()

Metoda onCreate() je tou nejdůležitější metodou naší aplikace. Zde totiž, po spuštění aplikace, vše začíná:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getSupportActionBar().hide();
    setContentView(R.layout.activity_main);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);

    obraz = findViewById(R.id.obrazovka);
    obraz.setText("0");

    cislo1 = findViewById(R.id.cislo1);
    cislo1.setText("NaN");

    cislo2 = findViewById(R.id.cislo2);
    cislo2.setText("NaN");

    operace = findViewById(R.id.znamenko);
    operace.setText("...");
}

Po zavolání metody předka skryjeme tzv. app bar, kvůli úspoře místa na displeji. Dále nastavíme vzhled grafického uživatelského rozhraní odkazem na XML soubor rozvržení a zakážeme změnu orientace obrazovky (aktivita nebude reagovat na rotaci zařízení).

V metodě dále provádíme inicializaci objektů TextView tím, že jim přiřadíme reference na objekty z XML návrhu. Díky tomu budeme moci s těmito objekty pracovat (určovat, jaký text mají zobrazovat). Zároveň těmto objektům nastavujeme výchozí hodnoty.

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Jistě jste si všimli, že metoda onCreate() přijímá jeden parametr savedInstanceState. Ten je při prvním spuštění aplikace null. Slouží pro ukládání stavu aplikace a například po změně orientace zařízení již null nebude.

zapisCislo()

Tato hlavní metoda je nastavena na tlačítkách "0" až "9" a bude připisovat číslo na obrazovku:

public void zapisCislo(View sender) {
    Button tlac = (Button) sender;
    float number = Float.parseFloat(tlac.getText().toString());

    int pom = obraz.length();

    if (pom >= 9) {
        if (!prosel) {
            if (number == 0) {
                obraz.setText("0");
                return;
            } else {
                obraz.setText(tlac.getText());
                prosel = true;
            }
        }

        return;
    }

    if (!prosel) {
        if (number != 0) {
            obraz.setText(tlac.getText());
            prosel = true;
        }
    } else {
        obraz.append(tlac.getText());
    }
}

Metoda přijímá jeden parametr v proměnné sender, která je typu View. Díky této proměnné dostaneme ID tlačítka, na které uživatel klikl. Konkrétní číslo načteme z tohoto metodou getText(). Zde musíme ošetřit, aby se nám nestalo, že dostaneme na obrazovku řetězec čísel delší než 9 znaků. K tomu nám poslouží několik podmínek a jedna instanční proměnná.

zapisCarku()

Metoda pro zápis desetinné čárky má následující kód:

public void zapisCarku(View v) {
    if (obraz.getText().length() >= 8) {
        return;
    }

    String test = obraz.getText().toString();
    String hled = ".";

    if (!test.contains(hled)) {
        obraz.append(".");
        prosel = true;
    }
}

Zde musíme ošetřit, abychom nedostali na obrazovku dvě čárky. Pro zjištění, zda se již tečka v řetězci vyskytuje, lze použít metodu indexOf(). Metoda se ukončí, pokud je na obrazovce již více než 8 znaků. Pokud se . na obrazovce nenachází, přidá ji na konec řetězce a nastaví true u řídící proměnné prosel. Parametr nám zajistí viditelnost této metody, abychom k ní mohli přistoupit z XML, tzn. metoda onClick().

vymazVse()

Metoda pro vymazání a vynulování všech proměnných včetně obrazovky:

public void vymazVse(View v) {
    prosel = false;
    c1 = 0;
    c2 = 0;
    vys = 0;
    metoda = 5;

    obraz.setText("0");
    cislo1.setText("NaN");
    cislo2.setText("NaN");
    operace.setText("...");
}

vymazJeden()

Metoda na základě délky řetězce buď smaže poslední znak nebo nastaví TextView obraz na "0", což je hodnota, kterou uživatel na kalkulačce po jejím vymazání očekává:

public void vymazJeden(View v) {
    int delka = obraz.length();

    if (delka > 1) {
        String puvodnistring = obraz.getText().toString();
        String substring = puvodnistring.substring(0, delka - 1);
        obraz.setText(substring);
    } else if (delka > 0) {
        obraz.setText("0");
        prosel = false;
    }
}

zapor()

Tato metoda přepíše znaménko zapsaného čísla:

public void zapor(View v) {
    float k = Float.parseFloat(obraz.getText().toString());
    if (k == 0) {
        return;
    }

    String test = obraz.getText().toString();
    String hled = "-";

    if (test.contains(hled)) {
        test = test.replace("-", "");
        obraz.setText(test);
    } else {
        if (test.length() <= 8) {
            test = "-" + test;
            obraz.setText(test);
        }
    }
}

Pokud je na obrazovce zápor, přepíše číslo na kladnou hodnotu. Pokud je na obrazovce kladné číslo, přepíše ho na záporné. Toho docílíme tak, že vložíme před řetězec čísel mínus. Pokud se mínus již v řetězci vyskytuje, odstraníme ho metodou substring().

odmocni()

Metoda slouží k odmocnění čísla:

public void odmocni(View v) {
    double number = Math.sqrt(Double.parseDouble(obraz.getText().toString()));
    vymazVse(v);

    if (number >= 0) {
        String vysledek = (String.valueOf(number));

        if (vysledek.length() >= 9) {
            String substring = vysledek.substring(0, 9);

            if (substring.equals("1.0000000") || substring.equals("0.9999998") || substring.equals("0.9999999")) {
                obraz.setText("1");
                return;
            } else {
                obraz.setText(substring);
                return;
            }
        }

        if (number != 0) {
            Double zbav = Double.parseDouble(vysledek);
            int zbav2 = (int) Math.round(zbav);
            obraz.setText(String.valueOf(zbav2));
        } else {
            obraz.setText("0");
        }
    } else {
        Toast.makeText(this, "Nelze odmocnit záporné číslo!", Toast.LENGTH_LONG).show();
        vymazVse(v);
    }
}

Protože budeme odmocňovat, je třeba vymazat všechny proměnné. Pokud bude výsledek delší než 9 znaků, vytvoříme substring prvních 9 čísel. Pomocí podmínek ošetříme, aby se nezobrazovala nežádoucí čísla.

secti(), odecti(), vynasob(), vydel()

Čtyři metody pro operace +, -, * a / budou následující:

public void secti(View v) {
    c1 = Double.parseDouble(obraz.getText().toString());

    metoda = 1;
    obraz.setText("0");
    prosel = false;
    c1Nastaven = true;

    cislo1.setText(String.valueOf(c1));
    operace.setText("+");
}

public void odecti(View v) {
    c1 = Double.parseDouble(obraz.getText().toString());

    metoda = 2;
    obraz.setText("0");
    prosel = false;
    c1Nastaven = true;

    cislo1.setText(String.valueOf(c1));
    operace.setText("-");
}

public void vynasob(View V) {
    c1 = Double.parseDouble(obraz.getText().toString());

    metoda = 3;
    obraz.setText("0");
    prosel = false;
    c1Nastaven = true;

    cislo1.setText(String.valueOf(c1));
    operace.setText("*");
}

public void vydel(View V) {
    c1 = Double.parseDouble(obraz.getText().toString());

    metoda = 4;
    obraz.setText("0");
    prosel = false;
    c1Nastaven = true;

    cislo1.setText(String.valueOf(c1));
    operace.setText("/");
}

Každá z těchto metod z obrazovky načte první číslo, se kterým bude kalkulačka počítat. Poté do instanční proměnné uloží informaci o tom, jakou operaci jsme zvolili. Další důležitý krok je zobrazení uloženého čísla a zvolené operace do TextView v horní části obrazovky, abychom zvýšili přehlednost.

vypocti()

Poslední metoda v aplikaci načte z obrazovky druhé číslo, se kterým bude počítat:

public void vypocti(View v) {
    if (c1Nastaven) {
        if (metoda != 5) {
            c2 = Double.parseDouble(obraz.getText().toString());
            cislo2.setText(String.valueOf(c2));
        }

        switch (metoda) {
            case 1: {
                vys = c1 + c2;
                metoda = 5;
                break;
            }

            case 2: {
                vys = c1 - c2;
                metoda = 5;
                break;
            }

            case 3: {
                vys = c1 * c2;
                metoda = 5;
                break;
            }

            case 4: {
                if (c2 != 0) {
                    vys = c1 / c2;
                    metoda = 5;
                    break;
                } else {
                    Toast.makeText(this, "Nelze dělit nulou!", Toast.LENGTH_LONG).show();
                    vymazVse(v);
                    break;
                }
            }

            case 5: {
                break;
            }
        }

        if (vys == 0) {
            obraz.setText("0");
        } else {
            DecimalFormat df = new DecimalFormat("#.########");
            String vysl = df.format(vys);
            vysl = vysl.replace(",", ".");

            int poz = vysl.indexOf(".");

            if (poz >= 8) {
                Toast.makeText(this, "Byl překročen limit 9 čísel", Toast.LENGTH_LONG).show();
                vymazVse(v);
                return;
            }

            if (vysl.length() >= 10) {
                String substring = vysl.substring(0, 9);
                obraz.setText(substring);
                return;
            } else {
                obraz.setText(vysl);
            }

            c1Nastaven = false;
            prosel = false;
        }
    }
}

Pokud jsou splněny všechny nezbytné požadavky, jako uložení prvního čísla a nepřesáhnutí devíti znaků, můžeme počítat podle toho, jakou jsme zvolili operaci. K větvení jsme použili konstrukci switch. Dále musíme ošetřit, abychom na obrazovku nedostali číslo, které bude delší než devět znaků. K tomu použijeme podmínky a DecimalFormat. Při dělení vznikají dlouhé řetězce čísel, proto je třeba po počítání zjistit, na jakém místě je desetinná čárka a podle toho zaokrouhlit.

Kód kalkulačky tímto máme hotový :)

Příště, v lekci Android programování - Dokončení implementace kalkulačky, se budeme věnovat ladění a generování .apk souboru.


 

 

Článek pro vás napsal Jiří Frank
Avatar
Jak se ti líbí článek?
7 hlasů
Autor se věnuje programování v C# a vývoji aplikací pro platformu Android a dalším věcem spojeným s Android OS
Předchozí článek
Android programování - ConstraintLayout
Všechny články v sekci
Základy vývoje Android aplikací v Javě
Miniatura
Následující článek
Android programování - Dokončení implementace kalkulačky
Aktivity (11)

 

 

Komentáře
Zobrazit starší komentáře (13)

Avatar
Libor Šimo (libcosenior):8.10.2018 8:02

Díky, vyskúšam to.

Odpovědět
8.10.2018 8:02
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Libor Šimo (libcosenior):9.10.2018 20:02

Wau, stalo sa mi, že som niečo testoval a určite som nemal niečo košér, ale že mi to zmazalo veľkú časť kódu, to som vážne nečakal. Tiež riešenie. Keď si debil, píš všetko znovu a nauč sa to poriadne. :-D

Odpovědět
9.10.2018 20:02
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Libor Šimo (libcosenior):9.10.2018 20:03

Zatiaľ výsledky nič moc, ale zááááábava. :-D

Odpovědět
9.10.2018 20:03
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Libor Šimo (libcosenior):9.10.2018 20:05

import android.app.Ac­tivity;

public class MainActivity extends Activity {
....

Odpovědět
9.10.2018 20:05
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Libor Šimo (libcosenior):26.10.2018 21:17

Prišiel som na ďalšiu srandu.
V prílohe je kus kódu, ktorý označuje premennú R ako neplatnú. Nedivím sa. Nikde nie je definovaná.
Je zaujímavé, že pred časom mi to fungovalo aj bez definície a deklarácie R.

Odpovědět
26.10.2018 21:17
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Petr Štechmüller
Překladatel
Avatar
Odpovídá na Libor Šimo (libcosenior)
Petr Štechmüller:26.10.2018 21:19

Ahoj, R je automaticky generovaná třída. R znamená resources a obsahuje unikátní identifikátory na všechny resourcy přiložené k projektu.

Odpovědět
26.10.2018 21:19
Pokud spolu kód a komentář nekorespondují, budou patrně oba chybné
Avatar
Libor Šimo (libcosenior):26.10.2018 21:26

Príloha, zabudol som.

Odpovědět
26.10.2018 21:26
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na Petr Štechmüller
Libor Šimo (libcosenior):26.10.2018 21:27

Tk potom nechápem, prečo mi ju farbí na červeno ako chybu.

Odpovědět
26.10.2018 21:27
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovědět
26.10.2018 21:29
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Avatar
Odpovídá na Petr Štechmüller
Libor Šimo (libcosenior):28.10.2018 11:23

Bolo to tým, že som v android studiu otvoril projekt, ktorý používal nesprávny layout.

Odpovědět
28.10.2018 11:23
Aj tisícmíľová cesta musí začať jednoduchým krokom.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 23. Zobrazit vše