Przejdź do głównej treści
INF.04-01-22.06-SGCzerwiec 2022 · 22 kroki · ok. 66 min · 34 kryteria z klucza

Rozwiązanie krok po kroku: Aplikacja konsolowa i mobilna (Java + Android)

Rozwiązujemy arkusz z przeszukiwaniem tablicy z wartownikiem i ofertą turystyczną w wersji Java + Android Studio: w konsoli program, który wypełnia tablicę 50 liczbami losowymi w jednej funkcji, w drugiej szuka liczby podanej z klawiatury metodą z wartownikiem i wypisuje tablicę oraz indeks albo informację o braku; w aplikacji mobilnej ekran „Domek w górach” z obrazem, trzema przyciskami na pasku w kolorze Teal i licznikiem polubień, który nie spada poniżej zera. Do tego dokumentacja funkcji według wzoru z arkusza, zrzuty i dokument egzamin.

Kroki idą zdanie po zdaniu za treścią arkusza - każdy zaczyna się poleceniem z arkusza, a kod pokazuje dokładnie te linie, które je spełniają. Najpierw piszemy najprostszą wersję, której wymaga klucz, a w etapie „Dobre praktyki” poprawiamy to, czego klucz nie sprawdza.

Co widać w podglądzie. Wyniki programu konsolowego pochodzą z prawdziwego uruchomienia kodu z danego kroku (JDK 21); dla każdego uruchomienia sprawdziliśmy na wypisanej tablicy, że indeks jest pierwszym wystąpieniem liczby, a komunikat o braku pojawia się tylko wtedy, gdy liczby w tablicy nie ma. Ekran telefonu to symulacja w przeglądarce zbudowana z pliku XML danego kroku, z obrazem z archiwum zad1.zip; jej zachowanie odpowiada kodowi Javy z kroku - klikaj „POLUB” i „USUŃ”. Każdy stan aplikacji zbudowaliśmy też w Android Studio (Gradle) i sprawdziliśmy na emulatorze Pixel 8.

Arkusz pozwala też na C++, C# albo Pythona w konsoli i na .NET MAUI w części mobilnej - ten wariant to jedna z możliwych dróg.

Jak liczą się punkty. Klucz ma 34 kryteria (R.1.1 - R.4.8), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 26 punktów - można stracić 8 kryteriów i nadal zdać. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.

  1. Etap 1: Przygotowanie

    Krok 1 · po tym etapie masz 0 z 34 kryteriów (pkt)

    Krok 1: Folder zdającego, podfoldery i obraz z zad1.zip

    ok. 2 min
    Polecenie z arkusza

    Do wykonania aplikacji należy wykorzystać obraz z archiwum zad1.zip znajdującego się na pulpicie konta Egzamin i zabezpieczonego hasłem: !Turystyk@

    Na pulpicie zakładamy folder o nazwie z numerem PESEL, a w nim konsola, mobilna i dokumentacja. Archiwum zad1.zip rozpakowujemy hasłem z arkusza - jest w nim jeden plik, obraz.jpg (górski krajobraz z domkami), potrzebny w aplikacji mobilnej.

  2. Etap 2: Aplikacja konsolowa

    Kroki 2-8 · po tym etapie masz 17 z 34 kryteriów (pkt)

    Krok 2: Projekt konsola w Javie

    ok. 3 min
    Polecenie z arkusza

    Napisz program implementujący algorytm przeszukiwania tablicy z wartownikiem. Program wykonywany w konsoli. Zastosowany obiektowy język programowania zgodny z zainstalowanym na stanowisku egzaminacyjnym: C++ lub C#, lub Java, lub Python.

    Wybieramy Javę - tę samą, w której napiszemy aplikację mobilną. W IntelliJ IDEA: New Project → Java, nazwa konsola. Funkcje programu będą metodami statycznymi klasy Main.

    konsola/src/Main.java Java nowy plik
    public class Main {
        public static void main(String[] args) {
        }
    }
  3. Krok 3: Funkcja fillArray: 50 liczb losowych 1-100

    Kryteria: , , ,

    R.2.1 Program składa się z programu głównego oraz dwóch funkcji: do wypełniania tablicy i do szukania elementu w tablicy. Zawartość przynajmniej jednej funkcji jest zgodna z przeznaczeniem (może być niedokończona lub zawierać błędy)

    R.2.6 Tablica jest wypełniana liczbami losowymi z zakresu od 1 do 100 oraz liczba szukana jest pobierana z klawiatury

    R.1.3 Użyto znaczące nazewnictwo funkcji

    R.1.5 Zastosowano typy zmiennych pasujące do problemu (np. dowolny typ całkowity dla tablicy; typ całkowity dla iteratora pętli) oraz typ elementu tablicy jest taki sam jak typ szukanej. W przypadku Python zastosowano jawną konwersję do typu int dla wczytywanej liczby oraz zastosowano funkcję losującą liczby całkowite (randint)

    ok. 3 min
    Polecenie z arkusza

    Przeszukiwana jest minimum 50 elementowa tablica liczb całkowitych wypełniona wartościami pseudolosowymi z zakresu od 1 do 100. Wypełnianie tablicy i przeszukiwanie jest realizowane w oddzielnych funkcjach / metodach.

    Liczbę elementów zapisujemy raz, w stałej SIZE (static final - nie da się jej zmienić). Funkcja dostaje tablicę jako argument i wypełnia jej pierwsze 50 pozycji liczbami losowymi: random.nextInt(100) daje 0-99, więc dodajemy 1 (R.2.6, R.1.5).

    Dlaczego „pierwsze 50”, a nie cała tablica? Tablica będzie miała 51 komórek - ostatnia jest zarezerwowana dla wartownika z następnego kroku.

    konsola/src/Main.java Java zmienione: 11 linii
    import java.util.Random;
    
    public class Main {
        static final int SIZE = 50;
    
        static void fillArray(int[] numbers) {
            Random random = new Random();
            for (int i = 0; i < SIZE; i++) {
                numbers[i] = random.nextInt(100) + 1;
            }
        }
    
        public static void main(String[] args) {
        }
    }
  4. Krok 4: Funkcja searchWithSentinel: wyszukiwanie z wartownikiem

    Kryteria: , , , ,

    R.2.1 Program składa się z programu głównego oraz dwóch funkcji: do wypełniania tablicy i do szukania elementu w tablicy. Zawartość przynajmniej jednej funkcji jest zgodna z przeznaczeniem (może być niedokończona lub zawierać błędy)

    R.2.2 Utworzono funkcję szukającą, która zwraca wartość indeksu (typ liczbowy). Typ funkcji jest zgodny z typem zwracanej wartości

    R.2.3 Zastosowano algorytm przeszukiwania z wartownikiem: wartość szukana jest wstawiona do tablicy za ostatnim jej elementem, pętla przeszukująca działa od pierwszego elementu tablicy do momentu odnalezienia wartości

    R.2.8 Program nie powoduje błędów dostępu do pamięci lub wyjątków: podczas wstawiania elementu szukanego tablicy oraz podczas przeszukiwania w pętli

    R.1.2 Kod zapisano z wcięciami dla zagłębień bloków

    ok. 4 min
    Polecenie z arkusza

    By odnaleźć element x podejmiemy następujące kroki: na końcu tablicy (pod indeksem n+1) wstawimy szukany element x - będzie to nasz wartownik, w przypadku, gdy nie znajdziemy go nigdzie indziej w tablicy, zabezpieczy nas on przed wyjściem poza tablicę, przejdziemy po kolejnych elementach tablicy, tak długo aż nie znajdziemy szukanego elementu. Wyszukiwane jest pierwsze wystąpienie elementu w tablicy. Funkcja przeszukująca zwraca indeks odnalezionego elementu.

    Algorytm krok po kroku (R.2.3):

    1. numbers[SIZE] = value - szukaną liczbę wstawiamy do zarezerwowanej komórki za ostatnią liczbą tablicy. To jest wartownik.
    2. Pętla while idzie od indeksu 0, dopóki element nie jest szukaną liczbą. Nie potrzebuje warunku „czy nie wyszliśmy poza tablicę”: najpóźniej na wartowniku pętla na pewno się zatrzyma (R.2.8). Na tym polega oszczędność - jedno porównanie w każdym obrocie zamiast dwóch.
    3. Funkcja zwraca indeks, na którym się zatrzymała - typ int (R.2.2). Pętla zatrzymuje się na pierwszym wystąpieniu.

    Indeks SIZE oznacza, że pętla dotarła do wartownika, czyli liczby w tablicy nie było - to rozstrzygniemy w programie głównym.

    Typowe błędy

    Tablica new int[SIZE] (bez miejsca na wartownika) - przypisanie numbers[SIZE] rzuca ArrayIndexOutOfBoundsException (R.2.8).

    konsola/src/Main.java Java zmienione: 9 linii
    import java.util.Random;
    
    public class Main {
        static final int SIZE = 50;
    
        static void fillArray(int[] numbers) {
            Random random = new Random();
            for (int i = 0; i < SIZE; i++) {
                numbers[i] = random.nextInt(100) + 1;
            }
        }
    
        static int searchWithSentinel(int[] numbers, int value) {
            numbers[SIZE] = value;
            int index = 0;
            while (numbers[index] != value) {
                index++;
            }
            return index;
        }
    
        public static void main(String[] args) {
        }
    }
  5. Krok 5: Program główny: tablica z miejscem na wartownika i liczba z klawiatury

    Kryteria: , ,

    R.2.6 Tablica jest wypełniana liczbami losowymi z zakresu od 1 do 100 oraz liczba szukana jest pobierana z klawiatury

    R.1.7 Program nawiązuje zrozumiałą komunikację z użytkownikiem. Wyświetla przynajmniej jeden komunikat: Monit o podanie szukanej liczby lub komunikat z odnalezionym indeksem elementu lub jego brakiem. Jeżeli kod nie uruchamia się z powodu błędów kompilacji - sprawdzić w kodzie aplikacji

    R.1.4 Użyto znaczące nazewnictwo zmiennych (przynajmniej jedna). Wyjątkami od reguły są zmienne bufor, tmp, iteratory pętli itp. Dopuszcza się x jako nazwę szukanej. Kryterium nie jest spełnione tylko wtedy, gdy nazwy zmiennych nic nie znaczą, np. a, fun, foo

    ok. 3 min
    Polecenie z arkusza

    Wartość do wyszukania jest pobierana z klawiatury. Program główny powinien zawierać test działania aplikacji.

    Tablicę tworzymy o jeden element większą: new int[SIZE + 1] - 50 liczb i miejsce na wartownika. Wypełniamy ją, wczytujemy liczbę z klawiatury z czytelnym komunikatem (R.1.7, R.2.6) i wywołujemy wyszukiwanie. Typ szukanej (int) jest taki sam jak typ elementów tablicy (R.1.5). Wyniku jeszcze nie wypisujemy.

    konsola/src/Main.java Java zmienione: 8 linii
    import java.util.Scanner;
    import java.util.Random;
    
    public class Main {
        static final int SIZE = 50;
    
        static void fillArray(int[] numbers) {
            Random random = new Random();
            for (int i = 0; i < SIZE; i++) {
                numbers[i] = random.nextInt(100) + 1;
            }
        }
    
        static int searchWithSentinel(int[] numbers, int value) {
            numbers[SIZE] = value;
            int index = 0;
            while (numbers[index] != value) {
                index++;
            }
            return index;
        }
    
        public static void main(String[] args) {
            int[] numbers = new int[SIZE + 1];
            fillArray(numbers);
    
            Scanner scanner = new Scanner(System.in);
            System.out.print("Podaj liczbę do wyszukania (1-100): ");
            int value = scanner.nextInt();
            int index = searchWithSentinel(numbers, value);
        }
    }
  6. Krok 6: Wypisanie tablicy po przecinku

    Kryteria:

    R.2.7 Elementy tablicy, oddzielone przecinkami, są wyświetlane na ekranie

    ok. 2 min
    Polecenie z arkusza

    Po przeszukaniu tablicy na ekranie wyświetlana jest zawartość tablicy (liczby oddzielone przecinkami).

    Wypisujemy tylko 50 liczb (bez wartownika). Przecinek stawiamy między liczbami: po każdej oprócz ostatniej - stąd warunek i < SIZE - 1 (R.2.7). Podgląd to prawdziwe uruchomienie.

    konsola/src/Main.java Java zmienione: 9 linii
    import java.util.Scanner;
    import java.util.Random;
    
    public class Main {
        static final int SIZE = 50;
    
        static void fillArray(int[] numbers) {
            Random random = new Random();
            for (int i = 0; i < SIZE; i++) {
                numbers[i] = random.nextInt(100) + 1;
            }
        }
    
        static int searchWithSentinel(int[] numbers, int value) {
            numbers[SIZE] = value;
            int index = 0;
            while (numbers[index] != value) {
                index++;
            }
            return index;
        }
    
        public static void main(String[] args) {
            int[] numbers = new int[SIZE + 1];
            fillArray(numbers);
    
            Scanner scanner = new Scanner(System.in);
            System.out.print("Podaj liczbę do wyszukania (1-100): ");
            int value = scanner.nextInt();
            int index = searchWithSentinel(numbers, value);
    
            System.out.print("Tablica: ");
            for (int i = 0; i < SIZE; i++) {
                System.out.print(numbers[i]);
                if (i < SIZE - 1) {
                    System.out.print(", ");
                }
            }
            System.out.println();
        }
    }
    Wynik programu po tym kroku
    > java Main
    Podaj liczbę do wyszukania (1-100): 25
    Tablica: 55, 24, 97, 59, 88, 19, 3, 37, 43, 100, 4, 2, 91, 99, 71, 62, 70, 36, 93, 38, 17, 53, 61, 51, 94, 63, 17, 94, 70, 6, 96, 49, 10, 15, 58, 58, 5, 70, 76, 50, 35, 76, 28, 72, 30, 5, 1, 16, 26, 11
  7. Krok 7: Indeks albo komunikat o braku

    Kryteria: , , ,

    R.2.4 Tylko gdy wyszukany indeks jest ostatnim w tablicy, wyświetlany jest komunikat o nieodnalezieniu elementu

    R.2.5 Tylko gdy wyszukany indeks nie jest ostatnim w tablicy wyświetlany jest indeks wyszukanego elementu

    R.2.9 Program kompiluje się i uruchamia w konsoli, co udokumentowano zrzutem ekranu

    R.1.1 Kod źródłowy zapisano w sposób czytelny: instrukcje w osobnych liniach, stosowane spacje pomiędzy operatorami, konsekwentnie stosowana wybrana konwencja dla nawiasów klamrowych instrukcji blokowej

    ok. 3 min
    Polecenie z arkusza

    Jeżeli jest to ostatni element tablicy (n+1) to trafiliśmy na naszego wartownika i oznacza to, że w tablicy nie było szukanego elementu x, w przeciwnym razie element x został odnaleziony. Po przeszukaniu tablicy na ekranie wyświetlana jest indeks, pod którym odszukano wartość lub w przypadku jej braku – stosowny komunikat.

    Funkcja zwraca indeks zatrzymania. Jeśli to SIZE - pozycja wartownika - liczby w tablicy nie było (R.2.4); w przeciwnym razie wypisujemy znaleziony indeks (R.2.5).

    Podgląd to dwa prawdziwe uruchomienia: jedno, w którym liczba jest w tablicy (sprawdziliśmy, że to jej pierwsze wystąpienie), i jedno, w którym jej nie ma. Tablica jest losowana za każdym razem od nowa.

    konsola/src/Main.java Java zmienione: 6 linii
    import java.util.Scanner;
    import java.util.Random;
    
    public class Main {
        static final int SIZE = 50;
    
        static void fillArray(int[] numbers) {
            Random random = new Random();
            for (int i = 0; i < SIZE; i++) {
                numbers[i] = random.nextInt(100) + 1;
            }
        }
    
        static int searchWithSentinel(int[] numbers, int value) {
            numbers[SIZE] = value;
            int index = 0;
            while (numbers[index] != value) {
                index++;
            }
            return index;
        }
    
        public static void main(String[] args) {
            int[] numbers = new int[SIZE + 1];
            fillArray(numbers);
    
            Scanner scanner = new Scanner(System.in);
            System.out.print("Podaj liczbę do wyszukania (1-100): ");
            int value = scanner.nextInt();
            int index = searchWithSentinel(numbers, value);
    
            System.out.print("Tablica: ");
            for (int i = 0; i < SIZE; i++) {
                System.out.print(numbers[i]);
                if (i < SIZE - 1) {
                    System.out.print(", ");
                }
            }
            System.out.println();
    
            if (index == SIZE) {
                System.out.println("Nie znaleziono liczby " + value + " w tablicy");
            } else {
                System.out.println("Liczba " + value + " znajduje się pod indeksem " + index);
            }
        }
    }
    Wynik programu po tym kroku
    > java Main
    Podaj liczbę do wyszukania (1-100): 25
    Tablica: 43, 76, 53, 90, 60, 10, 40, 66, 28, 47, 5, 46, 10, 53, 91, 62, 13, 13, 90, 1, 77, 38, 40, 74, 8, 64, 13, 34, 93, 15, 92, 32, 86, 2, 41, 6, 50, 92, 75, 27, 57, 95, 15, 70, 25, 19, 87, 30, 55, 30
    Liczba 25 znajduje się pod indeksem 44
    
    > java Main
    Podaj liczbę do wyszukania (1-100): 25
    Tablica: 5, 27, 96, 4, 54, 57, 91, 86, 100, 45, 73, 49, 87, 79, 89, 28, 75, 69, 78, 26, 100, 27, 33, 37, 61, 32, 51, 87, 85, 96, 78, 6, 53, 80, 15, 63, 30, 18, 22, 100, 78, 82, 34, 56, 6, 12, 43, 20, 34, 19
    Nie znaleziono liczby 25 w tablicy
  8. Krok 8: Folder konsola: archiwum, źródło i zrzuty

    Kryteria: ,

    R.1.6 Podjęto próbę skompilowania kodu, co udokumentowano zrzutem ekranowym przedstawiającym wykonywany program lub jego kompilację

    R.4.6 Zapisano przynajmniej jeden zrzut ekranu z uruchomienia lub kompilacji aplikacji konsolowej, na zrzucie widoczne jest środowisko, w którym powstała aplikacja

    ok. 3 min
    Polecenie z arkusza

    Kod aplikacji przygotuj do nagrania na płytę. W podfolderze konsola powinno znaleźć się archiwum całego projektu o nazwie konsola.zip, plik z kodem źródłowym programu oraz plik uruchomieniowy, jeżeli istnieje. Aplikacja konsolowa – dowolna liczba zrzutów nazwanych konsola1, konsola2 ...

    Dwa zrzuty całego ekranu z IntelliJ: liczba znaleziona i nieznaleziona - konsola1, konsola2 w folderze dokumentacja (R.1.6, R.4.6). Folder projektu pakujemy do konsola.zip (po dopisaniu komentarza z części III), obok kopiujemy Main.java.

    Wynik programu bez zmian - taki jak po kroku 7.

  9. Etap 3: Aplikacja mobilna

    Kroki 9-17 · po tym etapie masz 28 z 34 kryteriów (pkt)

    Krok 9: Nowy projekt Domek w Android Studio

    ok. 3 min
    Polecenie z arkusza

    Wykonaj aplikację mobilną za pomocą środowiska programistycznego dostępnego na stanowisku egzaminacyjnym oraz uruchom ją w dostępnym emulatorze systemu mobilnego. Aplikacja jest fragmentem programu do przeglądania ofert turystycznych.

    New Project → szablon Empty Views Activity (z widokami w XML). Nazwa Domek, pakiet com.example.domek, język Java. Będziemy zmieniać MainActivity.java (logika) i res/layout/activity_main.xml (wygląd). Obraz obraz.jpg kopiujemy do app/src/main/res/drawable - w XML będzie dostępny jako @drawable/obraz.

    Domek/app/src/main/java/com/example/domek/MainActivity.java Java nowy plik
    package com.example.domek;
    
    import android.os.Bundle;
    
    import androidx.activity.EdgeToEdge;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.graphics.Insets;
    import androidx.core.view.ViewCompat;
    import androidx.core.view.WindowInsetsCompat;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            EdgeToEdge.enable(this);
            setContentView(R.layout.activity_main);
            ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
                Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
                v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
                return insets;
            });
        }
    }
    Domek/app/src/main/res/layout/activity_main.xml XML nowy plik
    <?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"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  10. Krok 10: Pionowy LinearLayout z marginesem 20dp i tytuł

    Kryteria: , ,

    R.3.1 Zastosowano język znaczników XML/XAML lub inny do opisu interfejsu użytkownika oraz kod zawiera przynajmniej jeden element / kontrolkę interfejsu graficznego

    R.3.2 Zastosowano rozkład typu liniowego wertykalnego (LinearLayout / StackLayout lub inny o tej idei) z zagłębionym rozkładem liniowym horyzontalnym dla przycisków oraz ustawiono margines wewnętrzny górny dla całej strony lub rozkładu 20px (lub dp)

    R.3.3 Zastosowano kontrolki tekstu i przycisku. Tytuł jest zapisany czcionką o największym rozmiarze spośród stosowanych w aplikacji, czcionka napisu "Opis" jest pogrubiona. Napis z liczbą polubień jest wyrównany do prawej

    ok. 3 min
    Polecenie z arkusza

    Interfejs użytkownika zapisany za pomocą języka znaczników wspieranego w danym środowisku (np. XAML, XML). Zastosowany typ rozkładu liniowy wertykalny (Linear / Stack lub inny o tej idei). Margines wewnętrzny górny dla całej strony lub rozkładu wertykalnego: 20 px (lub dp). Tytuł o treści: „Domek w górach”. Czcionka tytułu ma rozmiar największy spośród użytych w aplikacji.

    W widoku Code zamieniamy ConstraintLayout na pionowy LinearLayout (R.3.1, R.3.2) z marginesem wewnętrznym górnym android:paddingTop="20dp". Zostawiamy android:id="@+id/main". Pierwszy element to tytuł z czcionką 30sp - największą na ekranie (R.3.3).

    W podglądzie margines jeszcze nie działa - w następnym kroku wyjaśniamy dlaczego.

    Domek/app/src/main/res/layout/activity_main.xml XML zmienione: 6 linii
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="20dp"
        tools:context=".MainActivity">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Domek w górach"
            android:textSize="30sp" />
    
    </LinearLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  11. Krok 11: Margines 20dp zachowany w trybie edge-to-edge

    Kryteria:

    R.3.2 Zastosowano rozkład typu liniowego wertykalnego (LinearLayout / StackLayout lub inny o tej idei) z zagłębionym rozkładem liniowym horyzontalnym dla przycisków oraz ustawiono margines wewnętrzny górny dla całej strony lub rozkładu 20px (lub dp)

    ok. 3 min
    Polecenie z arkusza

    Margines wewnętrzny górny dla całej strony lub rozkładu wertykalnego: 20 px (lub dp).

    Kod szablonu w onCreate ustawia głównemu widokowi padding równy wysokości pasków systemowych - i przy tym nadpisuje nasze 20dp z XML. Zapamiętujemy więc padding z XML (getPaddingTop() zwraca 20dp przeliczone na piksele), zanim szablon go zmieni, i dodajemy go do wysokości paska stanu: systemBars.top + basePaddingTop. Teraz tytuł stoi 20dp pod paskiem stanu (R.3.2).

    Typowe błędy

    Bez tej zmiany paddingTop w XML jest na miejscu, ale w działającej aplikacji go nie widać - szablon edge-to-edge zastępuje go wysokością paska stanu.

    Domek/app/src/main/java/com/example/domek/MainActivity.java Java zmienione: 2 linie
    package com.example.domek;
    
    import android.os.Bundle;
    
    import androidx.activity.EdgeToEdge;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.graphics.Insets;
    import androidx.core.view.ViewCompat;
    import androidx.core.view.WindowInsetsCompat;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            EdgeToEdge.enable(this);
            setContentView(R.layout.activity_main);
            int basePaddingTop = findViewById(R.id.main).getPaddingTop();
            ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
                Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
                v.setPadding(systemBars.left, systemBars.top + basePaddingTop, systemBars.right, systemBars.bottom);
                return insets;
            });
        }
    }
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  12. Krok 12: Obraz na całą szerokość

    Kryteria:

    R.3.5 Aplikacja wyświetla obraz o nazwie obraz.jpg , jest on rozciągnięty na całą szerokość ekranu (może być obcięty) np. AspectFill, FitCenter, adjustViewBounds

    ok. 2 min
    Polecenie z arkusza

    Obraz o nazwie obraz.jpg wypakowany z archiwum. Obraz wypełnia całą szerokość strony (zależnie od zastosowanego aspektu może być automatycznie obcięty przez emulator – zobacz obraz 1b).

    ImageView z layout_width="match_parent" zajmuje całą szerokość ekranu. Sama szerokość nie wystarczy: obraz 400 × 213 zostałby wyśrodkowany w ramce o wysokości obrazu, z pustymi pasami po bokach. adjustViewBounds="true" pozwala kontrolce dopasować wysokość do proporcji obrazu - obraz rozciąga się na całą szerokość, a wysokość rośnie proporcjonalnie (R.3.5).

    Domek/app/src/main/res/layout/activity_main.xml XML zmienione: 7 linii
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="20dp"
        tools:context=".MainActivity">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Domek w górach"
            android:textSize="30sp" />
    
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:contentDescription="Domek w górach"
            android:src="@drawable/obraz" />
    
    </LinearLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  13. Krok 13: Pasek Teal z trzema przyciskami obok siebie

    Kryteria: , ,

    R.3.2 Zastosowano rozkład typu liniowego wertykalnego (LinearLayout / StackLayout lub inny o tej idei) z zagłębionym rozkładem liniowym horyzontalnym dla przycisków oraz ustawiono margines wewnętrzny górny dla całej strony lub rozkładu 20px (lub dp)

    R.3.3 Zastosowano kontrolki tekstu i przycisku. Tytuł jest zapisany czcionką o największym rozmiarze spośród stosowanych w aplikacji, czcionka napisu "Opis" jest pogrubiona. Napis z liczbą polubień jest wyrównany do prawej

    R.3.4 Nadano kolor Teal (#008080) dla tła przycisków i rozkładu, w którym się one znajdują, kolor czcionki przycisków jest biały, kolor tekstu "Odwiedź..." jest Gray (#808080)

    ok. 3 min
    Polecenie z arkusza

    Trzy przyciski o treści: „POLUB”, „USUŃ”, „ZAPISZ” umiejscowione obok siebie. Zastosowany typ rozkładu liniowy wertykalny z zagłębionym rozkładem liniowym horyzontalnym dla przycisków. Kolor tła przycisków i rozkładu, w którym się znajdują: Teal (#008080), zgodnie z Obrazem 1a. Kolory czcionki: biały dla przycisków.

    Zagnieżdżony poziomy LinearLayout z tłem #008080 (R.3.2, R.3.4). Trzy przyciski dzielą szerokość po równo: layout_width="0dp" i layout_weight="1". Kolor przycisków dajemy przez backgroundTint - w motywie Material 3 przycisk barwi swoje tło kolorem motywu, a backgroundTint podmienia go na Teal; na pasku w tym samym kolorze przyciski wyglądają jak na obrazie 1b. Biały tekst - textColor="#FFFFFF" (R.3.4).

    Domek/app/src/main/res/layout/activity_main.xml XML zmienione: 35 linii
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="20dp"
        tools:context=".MainActivity">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Domek w górach"
            android:textSize="30sp" />
    
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:contentDescription="Domek w górach"
            android:src="@drawable/obraz" />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#008080"
            android:orientation="horizontal">
    
            <Button
                android:id="@+id/likeButton"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:backgroundTint="#008080"
                android:text="POLUB"
                android:textColor="#FFFFFF" />
    
            <Button
                android:id="@+id/removeButton"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:backgroundTint="#008080"
                android:text="USUŃ"
                android:textColor="#FFFFFF" />
    
            <Button
                android:id="@+id/saveButton"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:backgroundTint="#008080"
                android:text="ZAPISZ"
                android:textColor="#FFFFFF" />
    
        </LinearLayout>
    
    </LinearLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  14. Krok 14: Licznik polubień, linia i opis

    Kryteria: , , ,

    R.3.3 Zastosowano kontrolki tekstu i przycisku. Tytuł jest zapisany czcionką o największym rozmiarze spośród stosowanych w aplikacji, czcionka napisu "Opis" jest pogrubiona. Napis z liczbą polubień jest wyrównany do prawej

    R.3.4 Nadano kolor Teal (#008080) dla tła przycisków i rozkładu, w którym się one znajdują, kolor czcionki przycisków jest biały, kolor tekstu "Odwiedź..." jest Gray (#808080)

    R.3.6 Wyświetlono linię horyzontalną (np. BoxView o wysokości 1) koloru Gray (#808080)

    R.3.10 Aplikacja kompiluje się i uruchamia w emulatorze. Zawiera co najmniej 7 elementów oraz wygląd zgodny z obrazem 1a lub 1b w arkuszu egzaminacyjnym. Napis liczby polubień wyświetla "0 polubień", co udokumentowano zrzutem ekranu

    ok. 3 min
    Polecenie z arkusza

    Napis o treści „0 polubień”. Linia horyzontalna. Napis o treści „Opis”. Napis o treści „Odwiedź komfortowy domek w Sudetach, blisko do szlaków turystycznych”. Kolory czcionki: Gray (#808080) dla napisu „Odwiedź...”, zgodnie z Obrazem 1a. Czcionka napisu „Opis” jest pogrubiona. Napis o liczbie polubień jest wyrównany do prawej. Linia horyzontalna jest koloru Gray (#808080), dopuszcza się również prostokąt o wysokości 1.

    Pozostałe elementy, od góry:

    • licznik na całą szerokość z android:gravity="end" - tekst przy prawej krawędzi (end zamiast right, żeby w językach pisanych od prawej układ odwrócił się sam) (R.3.3),
    • linia - zwykły View o wysokości 1dp, szerokości ekranu i tle #808080 (R.3.6),
    • „Opis” z textStyle="bold" i opis w kolorze #808080 (R.3.3, R.3.4).

    Ekran ma wszystkie siedem elementów z obrazu 1a (R.3.10).

    Domek/app/src/main/res/layout/activity_main.xml XML zmienione: 25 linii
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="20dp"
        tools:context=".MainActivity">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Domek w górach"
            android:textSize="30sp" />
    
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:contentDescription="Domek w górach"
            android:src="@drawable/obraz" />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#008080"
            android:orientation="horizontal">
    
            <Button
                android:id="@+id/likeButton"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:backgroundTint="#008080"
                android:text="POLUB"
                android:textColor="#FFFFFF" />
    
            <Button
                android:id="@+id/removeButton"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:backgroundTint="#008080"
                android:text="USUŃ"
                android:textColor="#FFFFFF" />
    
            <Button
                android:id="@+id/saveButton"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:backgroundTint="#008080"
                android:text="ZAPISZ"
                android:textColor="#FFFFFF" />
    
        </LinearLayout>
    
        <TextView
            android:id="@+id/likesText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="end"
            android:text="0 polubień" />
    
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#808080" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:text="Opis"
            android:textStyle="bold" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Odwiedź komfortowy domek w Sudetach, blisko do szlaków turystycznych"
            android:textColor="#808080" />
    
    </LinearLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  15. Krok 15: POLUB: licznik w górę

    Kryteria: ,

    R.3.7 Zdefiniowano zmienną typu liczbowego całkowitego, która na początku działania aplikacji jest równa 0 oraz jest inkrementowana i dekrementowana w funkcjach obsługujących zdarzenia kliknięcia przycisku (wystarczy jedna zdefiniowana funkcja)

    R.3.9 Po wciśnięciu przycisku "POLUB" wyświetla się zwiększona o 1 liczba polubień oraz po wciśnięciu przycisku "USUŃ" wyświetla się zmniejszona o 1 liczba polubień

    ok. 3 min
    Polecenie z arkusza

    Aplikacja implementuje licznik polubień, który w stanie początkowym aplikacji jest równy 0, następnie jego stan jest: inkrementowany po wciśnięciu przycisku „POLUB”. Stan licznika jest wyświetlany pod przyciskami, w formie napisu „<x> polubień”, gdzie <x> oznacza aktualną wartość licznika.

    Licznik to pole aktywności int likes = 0 - przetrwa między kliknięciami (R.3.7). Napis znajdujemy przez findViewById. Metodę like wiążemy z przyciskiem atrybutem android:onClick="like": zwiększa licznik i wpisuje do napisu liczbę ze słowem „polubień”. Kliknij w podglądzie kilka razy „POLUB” - jak na obrazie 1b.

    Domek/app/src/main/java/com/example/domek/MainActivity.java Java zmienione: 12 linii
    package com.example.domek;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.TextView;
    
    import androidx.activity.EdgeToEdge;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.graphics.Insets;
    import androidx.core.view.ViewCompat;
    import androidx.core.view.WindowInsetsCompat;
    
    public class MainActivity extends AppCompatActivity {
    
        private int likes = 0;
        private TextView likesText;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            EdgeToEdge.enable(this);
            setContentView(R.layout.activity_main);
            int basePaddingTop = findViewById(R.id.main).getPaddingTop();
            ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
                Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
                v.setPadding(systemBars.left, systemBars.top + basePaddingTop, systemBars.right, systemBars.bottom);
                return insets;
            });
    
            likesText = findViewById(R.id.likesText);
        }
    
        public void like(View view) {
            likes++;
            likesText.setText(likes + " polubień");
        }
    }
    Domek/app/src/main/res/layout/activity_main.xml XML zmienione: 1 linia
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="20dp"
        tools:context=".MainActivity">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Domek w górach"
            android:textSize="30sp" />
    
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:contentDescription="Domek w górach"
            android:src="@drawable/obraz" />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#008080"
            android:orientation="horizontal">
    
            <Button
                android:id="@+id/likeButton"
                android:onClick="like"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:backgroundTint="#008080"
                android:text="POLUB"
                android:textColor="#FFFFFF" />
    
            <Button
                android:id="@+id/removeButton"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:backgroundTint="#008080"
                android:text="USUŃ"
                android:textColor="#FFFFFF" />
    
            <Button
                android:id="@+id/saveButton"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:backgroundTint="#008080"
                android:text="ZAPISZ"
                android:textColor="#FFFFFF" />
    
        </LinearLayout>
    
        <TextView
            android:id="@+id/likesText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="end"
            android:text="0 polubień" />
    
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#808080" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:text="Opis"
            android:textStyle="bold" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Odwiedź komfortowy domek w Sudetach, blisko do szlaków turystycznych"
            android:textColor="#808080" />
    
    </LinearLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  16. Krok 16: USUŃ: licznik w dół, ale nie poniżej zera

    Kryteria: , ,

    R.3.7 Zdefiniowano zmienną typu liczbowego całkowitego, która na początku działania aplikacji jest równa 0 oraz jest inkrementowana i dekrementowana w funkcjach obsługujących zdarzenia kliknięcia przycisku (wystarczy jedna zdefiniowana funkcja)

    R.3.8 Gdy licznik polubień jest równy 0 wciśnięcie przycisku "USUŃ" nie zmniejsza jego wartości

    R.3.9 Po wciśnięciu przycisku "POLUB" wyświetla się zwiększona o 1 liczba polubień oraz po wciśnięciu przycisku "USUŃ" wyświetla się zmniejszona o 1 liczba polubień

    ok. 2 min
    Polecenie z arkusza

    Dekrementowany po wciśnięciu przycisku „USUŃ”. Licznik nie może być niższy niż 0.

    Druga metoda zmniejsza licznik tylko wtedy, gdy jest większy od zera - przy zerze kliknięcie zostawia 0 (R.3.8, R.3.9). Przycisk „ZAPISZ” zostaje bez obsługi - arkusz nie opisuje jego działania. Sprawdź w podglądzie: dwa razy „POLUB”, trzy razy „USUŃ” - licznik kończy na 0.

    Typowe błędy

    likes-- bez warunku daje „-1 polubień” po kliknięciu „USUŃ” na starcie (R.3.8).

    Domek/app/src/main/java/com/example/domek/MainActivity.java Java zmienione: 7 linii
    package com.example.domek;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.TextView;
    
    import androidx.activity.EdgeToEdge;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.graphics.Insets;
    import androidx.core.view.ViewCompat;
    import androidx.core.view.WindowInsetsCompat;
    
    public class MainActivity extends AppCompatActivity {
    
        private int likes = 0;
        private TextView likesText;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            EdgeToEdge.enable(this);
            setContentView(R.layout.activity_main);
            int basePaddingTop = findViewById(R.id.main).getPaddingTop();
            ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
                Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
                v.setPadding(systemBars.left, systemBars.top + basePaddingTop, systemBars.right, systemBars.bottom);
                return insets;
            });
    
            likesText = findViewById(R.id.likesText);
        }
    
        public void like(View view) {
            likes++;
            likesText.setText(likes + " polubień");
        }
    
        public void removeLike(View view) {
            if (likes > 0) {
                likes--;
            }
            likesText.setText(likes + " polubień");
        }
    }
    Domek/app/src/main/res/layout/activity_main.xml XML zmienione: 1 linia
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingTop="20dp"
        tools:context=".MainActivity">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Domek w górach"
            android:textSize="30sp" />
    
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:contentDescription="Domek w górach"
            android:src="@drawable/obraz" />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#008080"
            android:orientation="horizontal">
    
            <Button
                android:id="@+id/likeButton"
                android:onClick="like"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:backgroundTint="#008080"
                android:text="POLUB"
                android:textColor="#FFFFFF" />
    
            <Button
                android:id="@+id/removeButton"
                android:onClick="removeLike"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:backgroundTint="#008080"
                android:text="USUŃ"
                android:textColor="#FFFFFF" />
    
            <Button
                android:id="@+id/saveButton"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:backgroundTint="#008080"
                android:text="ZAPISZ"
                android:textColor="#FFFFFF" />
    
        </LinearLayout>
    
        <TextView
            android:id="@+id/likesText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="end"
            android:text="0 polubień" />
    
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#808080" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:text="Opis"
            android:textStyle="bold" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Odwiedź komfortowy domek w Sudetach, blisko do szlaków turystycznych"
            android:textColor="#808080" />
    
    </LinearLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  17. Krok 17: Uruchomienie w emulatorze, zrzuty i folder mobilna

    Kryteria: ,

    R.3.10 Aplikacja kompiluje się i uruchamia w emulatorze. Zawiera co najmniej 7 elementów oraz wygląd zgodny z obrazem 1a lub 1b w arkuszu egzaminacyjnym. Napis liczby polubień wyświetla "0 polubień", co udokumentowano zrzutem ekranu

    R.4.7 Zapisano przynajmniej jeden zrzut ekranu z uruchomienia lub kompilacji aplikacji mobilnej, na zrzucie widoczne jest środowisko, w którym powstała aplikacja

    ok. 3 min
    Polecenie z arkusza

    Aplikacja mobilna – dowolna liczba zrzutów nazwanych mobile1, mobile2 ... (np. stan początkowy, po wciśnięciu przycisku polubień). W podfolderze mobilna powinno znaleźć się archiwum całego projektu o nazwie mobilna.zip, plik źródłowy interfejsu użytkownika (XAML lub XML) oraz plik źródłowy kodu skojarzonego z interfejsem użytkownika.

    Uruchamiamy aplikację w emulatorze. Zrzuty całego ekranu z Android Studio: mobile1 - stan początkowy, mobile2 - po kilku polubieniach - do folderu dokumentacja (R.4.7). W folderze mobilna: mobilna.zip z całym projektem, activity_main.xml i MainActivity.java.

    Ekran telefonu bez zmian - taki jak po kroku 16.

  18. Etap 4: Dokumentacja

    Kroki 18-19 · po tym etapie masz 34 z 34 kryteriów (pkt)

    Krok 18: Nagłówek funkcji searchWithSentinel według listingu 1

    Kryteria: , , , ,

    R.4.1 Dla funkcji wyszukującej z aplikacji konsolowej zapisano nagłówek w postaci komentarza zgodny z Listingiem 1 z arkusza egzaminacyjnego, umieszczony w komentarzu wieloliniowym lub kilku jednoliniowych

    R.4.2 W komentarzu ujęto nazwę funkcji

    R.4.3 Jeżeli funkcja przyjmuje argumenty w komentarzu ujęto ich nazwy wraz z opisem oraz ujęto typ zwracany (nazwa lub opis np. "liczba całkowita") z krótką informacją

    R.4.4 W komentarzu zawarto informacje o funkcji, które zawierają przynajmniej sformułowanie dotyczące algorytmu i metody, np. "przeszukiwanie tablicy z wartownikiem"

    R.4.5 W komentarzu ujęto numer zdającego

    ok. 4 min
    Polecenie z arkusza

    W kodzie źródłowym aplikacji konsolowej utwórz nagłówek funkcji przeszukującej, według wzoru zgodnie z listingiem 1. Nagłówek powinien znaleźć się w kodzie źródłowym nad funkcją. W miejscu nawiasów <> należy podać nazwę funkcji, nazwy argumentów wraz z krótkim opisem, typ zwracany wraz z krótkim opisem, krótki opis zawierający przynajmniej nazwę algorytmu. W miejscu autor należy podać swój numer.

    Komentarz wieloliniowy nad funkcją z polami listingu 1 (R.4.1): nazwa (R.4.2), oba argumenty z opisem i typ zwracany z opisem (R.4.3), w informacjach nazwa algorytmu - przeszukiwanie z wartownikiem (R.4.4) - i autor (R.4.5). Na egzaminie w polu autor wpisujemy numer PESEL - tu stoi Bartosz Bryniarski.

    konsola/src/Main.java Java zmienione: 11 linii
    import java.util.Scanner;
    import java.util.Random;
    
    public class Main {
        static final int SIZE = 50;
    
        static void fillArray(int[] numbers) {
            Random random = new Random();
            for (int i = 0; i < SIZE; i++) {
                numbers[i] = random.nextInt(100) + 1;
            }
        }
    
        /*
        ******************************************************
          nazwa funkcji: searchWithSentinel
          argumenty:     numbers - tablica liczb z wolną komórką na końcu (pod indeksem SIZE) na wartownika
                         value - szukana liczba
          typ zwracany:  int, indeks pierwszego wystąpienia szukanej liczby albo SIZE, gdy jej nie ma
          informacje:    przeszukiwanie tablicy z wartownikiem - szukana liczba wstawiona za ostatnim
                         elementem zatrzymuje pętlę bez sprawdzania końca tablicy
          autor:         Bartosz Bryniarski
        *****************************************************
        */
        static int searchWithSentinel(int[] numbers, int value) {
            numbers[SIZE] = value;
            int index = 0;
            while (numbers[index] != value) {
                index++;
            }
            return index;
        }
    
        public static void main(String[] args) {
            int[] numbers = new int[SIZE + 1];
            fillArray(numbers);
    
            Scanner scanner = new Scanner(System.in);
            System.out.print("Podaj liczbę do wyszukania (1-100): ");
            int value = scanner.nextInt();
            int index = searchWithSentinel(numbers, value);
    
            System.out.print("Tablica: ");
            for (int i = 0; i < SIZE; i++) {
                System.out.print(numbers[i]);
                if (i < SIZE - 1) {
                    System.out.print(", ");
                }
            }
            System.out.println();
    
            if (index == SIZE) {
                System.out.println("Nie znaleziono liczby " + value + " w tablicy");
            } else {
                System.out.println("Liczba " + value + " znajduje się pod indeksem " + index);
            }
        }
    }
    Wynik programu po tym kroku
    > java Main
    Podaj liczbę do wyszukania (1-100): 25
    Tablica: 71, 21, 56, 100, 25, 6, 80, 39, 35, 76, 5, 24, 13, 80, 96, 96, 27, 73, 67, 66, 62, 90, 49, 61, 98, 24, 42, 40, 33, 74, 60, 46, 1, 17, 62, 63, 13, 8, 54, 31, 58, 61, 79, 38, 5, 7, 74, 64, 38, 37
    Liczba 25 znajduje się pod indeksem 4
  19. Krok 19: Dokument egzamin

    Kryteria:

    R.4.8 Dokumentacja zawiera: nazwę systemu operacyjnego, nazwy środowisk, nazwy języków programowania, nazwę emulatora systemu mobilnego

    ok. 3 min
    Polecenie z arkusza

    W edytorze tekstu pakietu biurowego utwórz plik z dokumentacją i nazwij go egzamin. Dokument powinien zawierać podpisane zrzuty ekranu oraz zapisane informacje: Nazwę systemu operacyjnego, na którym pracował zdający. Nazwy środowisk programistycznych, z których zdający korzystał na egzaminie. Nazwy języków programowania. Nazwę emulatora systemu mobilnego.

    W Wordzie albo Writerze dokument egzamin w folderze dokumentacja: podpisane zrzuty, system, środowiska, języki i nazwa emulatora (R.4.8).

    egzamin.txt Tekst nowy plik
    Zrzuty ekranu: konsola1, konsola2 - liczba znaleziona i nieznaleziona; mobile1 - stan początkowy; mobile2 - po kliknięciu POLUB
    System operacyjny: Windows 11
    Środowiska programistyczne: IntelliJ IDEA (aplikacja konsolowa), Android Studio (aplikacja mobilna)
    Języki programowania: Java (aplikacja konsolowa i mobilna), XML (układ aplikacji mobilnej)
    Emulator: Pixel 8 (Android 16, API 36) z Android Studio

    Wynik programu bez zmian - taki jak po kroku 18.

  20. Etap 5: Dobre praktyki (poza kluczem)

    Kroki 20-21 · po tym etapie masz 34 z 34 kryteriów (pkt)

    Krok 20: Konsola: odporność na tekst zamiast liczby

    ok. 2 min
    Polecenie z arkusza

    Program powinien podejmować zrozumiałą komunikację z użytkownikiem, dane wprowadzane i wyprowadzane powinny być opatrzone zrozumiałym opisem.

    scanner.nextInt() na słowie „dwadzieścia” rzuca wyjątek InputMismatchException i kończy program. Pętla while (!scanner.hasNextInt()) pomija takie słowo i prosi ponownie.

    Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    konsola/src/Main.java Java zmienione: 4 linie
    import java.util.Scanner;
    import java.util.Random;
    
    public class Main {
        static final int SIZE = 50;
    
        static void fillArray(int[] numbers) {
            Random random = new Random();
            for (int i = 0; i < SIZE; i++) {
                numbers[i] = random.nextInt(100) + 1;
            }
        }
    
        /*
        ******************************************************
          nazwa funkcji: searchWithSentinel
          argumenty:     numbers - tablica liczb z wolną komórką na końcu (pod indeksem SIZE) na wartownika
                         value - szukana liczba
          typ zwracany:  int, indeks pierwszego wystąpienia szukanej liczby albo SIZE, gdy jej nie ma
          informacje:    przeszukiwanie tablicy z wartownikiem - szukana liczba wstawiona za ostatnim
                         elementem zatrzymuje pętlę bez sprawdzania końca tablicy
          autor:         Bartosz Bryniarski
        *****************************************************
        */
        static int searchWithSentinel(int[] numbers, int value) {
            numbers[SIZE] = value;
            int index = 0;
            while (numbers[index] != value) {
                index++;
            }
            return index;
        }
    
        public static void main(String[] args) {
            int[] numbers = new int[SIZE + 1];
            fillArray(numbers);
    
            Scanner scanner = new Scanner(System.in);
            System.out.print("Podaj liczbę do wyszukania (1-100): ");
            while (!scanner.hasNextInt()) {
                scanner.next();   // pomijamy słowo, które nie jest liczbą całkowitą
                System.out.print("To nie jest liczba całkowita. Podaj liczbę: ");
            }
            int value = scanner.nextInt();
            int index = searchWithSentinel(numbers, value);
    
            System.out.print("Tablica: ");
            for (int i = 0; i < SIZE; i++) {
                System.out.print(numbers[i]);
                if (i < SIZE - 1) {
                    System.out.print(", ");
                }
            }
            System.out.println();
    
            if (index == SIZE) {
                System.out.println("Nie znaleziono liczby " + value + " w tablicy");
            } else {
                System.out.println("Liczba " + value + " znajduje się pod indeksem " + index);
            }
        }
    }
    Wynik programu po tym kroku
    > java Main
    Podaj liczbę do wyszukania (1-100): dwadzieścia
    To nie jest liczba całkowita. Podaj liczbę: 25
    Tablica: 36, 48, 28, 21, 74, 64, 72, 87, 47, 95, 37, 35, 65, 77, 49, 65, 90, 63, 53, 26, 26, 36, 34, 26, 1, 6, 27, 57, 97, 23, 45, 98, 5, 59, 45, 74, 80, 75, 90, 9, 91, 71, 100, 8, 73, 85, 77, 68, 89, 74
    Nie znaleziono liczby 25 w tablicy
  21. Krok 21: Android: poprawna odmiana „polubienie / polubienia / polubień”

    ok. 4 min
    Polecenie z arkusza

    Stan licznika jest wyświetlany pod przyciskami, w formie napisu „<x> polubień”, gdzie <x> oznacza aktualną wartość licznika.

    Arkusz wymaga napisu „<x> polubień” i tak zostaje na egzaminie, ale po polsku „1 polubień” i „2 polubień” to błąd. Android ma na to gotowy mechanizm - zasób plurals: w res/values/plurals.xml podajemy formy dla kategorii liczebników języka, a getQuantityString(R.plurals.likes, likes, likes) sam wybiera właściwą (pierwszy likes wybiera formę, drugi trafia w miejsce %d). Dla polskiego: one - 1 polubienie, few - 2, 3, 4, 22... polubienia, many - 0, 5-21, 25... polubień.

    Uwaga: kategorię liczebnika Android wybiera według języka telefonu. Na telefonie ustawionym po polsku działa to jak wyżej (sprawdziliśmy w emulatorze), a na telefonie po angielsku obowiązują angielskie reguły (tylko one i other), więc „2” dostanie formę other. W aplikacji wielojęzycznej polskie teksty trzyma się w res/values-pl, a domyślne - angielskie - w res/values.

    Oba przyciski korzystają teraz z jednej metody showLikes. Sprawdź w podglądzie 1, 2 i 5 polubień. Na egzaminie wystarczy wersja wcześniejsza - klucz sprawdza napis z arkusza.

    Domek/app/src/main/java/com/example/domek/MainActivity.java Java zmienione: 6 linii
    package com.example.domek;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.TextView;
    
    import androidx.activity.EdgeToEdge;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.graphics.Insets;
    import androidx.core.view.ViewCompat;
    import androidx.core.view.WindowInsetsCompat;
    
    public class MainActivity extends AppCompatActivity {
    
        private int likes = 0;
        private TextView likesText;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            EdgeToEdge.enable(this);
            setContentView(R.layout.activity_main);
            int basePaddingTop = findViewById(R.id.main).getPaddingTop();
            ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
                Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
                v.setPadding(systemBars.left, systemBars.top + basePaddingTop, systemBars.right, systemBars.bottom);
                return insets;
            });
    
            likesText = findViewById(R.id.likesText);
        }
    
        public void like(View view) {
            likes++;
            showLikes();
        }
    
        public void removeLike(View view) {
            if (likes > 0) {
                likes--;
            }
            showLikes();
        }
    
        private void showLikes() {
            likesText.setText(getResources().getQuantityString(R.plurals.likes, likes, likes));
        }
    }
    Domek/app/src/main/res/values/plurals.xml XML nowy plik
    <resources>
        <plurals name="likes">
            <item quantity="one">%d polubienie</item>
            <item quantity="few">%d polubienia</item>
            <item quantity="many">%d polubień</item>
            <item quantity="other">%d polubień</item>
        </plurals>
    </resources>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  22. Etap 6: Oddanie pracy

    Krok 22 · po tym etapie masz 34 z 34 kryteriów (pkt)

    Krok 22: Nagranie płyty

    ok. 5 min
    Polecenie z arkusza

    Nagraj płytę z rezultatami pracy. W folderze z numerem zdającego powinny się znajdować podfoldery: konsola, mobilna, dokumentacja.

    Sprawdzamy zawartość przed nagraniem:

    • konsola: konsola.zip (po dopisaniu komentarza), Main.java,
    • mobilna: mobilna.zip, activity_main.xml, MainActivity.java,
    • dokumentacja: konsola1, konsola2, mobile1, mobile2, egzamin.

    Nagrywamy, sprawdzamy odczyt płyty, opisujemy ją numerem zdającego.

    Ekran telefonu bez zmian - taki jak po kroku 21.

Podgląd

To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.

Autor rozwiązania: . Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony). Treść arkusza i klucza oceniania pochodzi z CKE.