Obraz zawierający tekst, Czcionka, Grafika

Opis wygenerowany automatycznie 

Kierunek Informatyka

 

Instrukcja do ćwiczeń laboratoryjnych nr:

3

Nazwa przedmiotu:
Programowanie aplikacji mobilnych

Temat: Interfejs użytkownika – LinearLayout, motywy, jednostki, context, komponenty CheckBox oraz RadioButton

Tryb studiów: stacjonarne

Czas trwanie ćw.

2x45 min

Autor materiałów: dr Marcin Skuba

1. Treści:

Motywy – użycie oraz modyfikacja. Tworzenie nowego widoku z siatką LinearLayout. Podstawowe parametry layout-u. Przypisywanie nowego widoku do aktywności.

 

2. Cel zajęć:

Celem zajęć jest opanowanie umiejętności tworzenia interfejsu użytkownika w siatce LinearLayout. Używanie i zmiana motywów domyślnych, zrozumienie jednostek miary, zrozumienie pojęcia context oraz wykorzystania obiektów RadioButton

 

3. Materiały dydaktyczne

 

·      Jednostki miary:

 

px - piksele, najbardziej znana jednostka miary wyświetlaczy. Jednostka ta nie jest zalecana na urządzenia mobilne, ponieważ mają one różne rozdzielczości przy tej samej przekątnej ekranu.

in – cale, również niezalecane.

pt – punkty, ten sam problem co z powyższymi jednostkami  (pt to 1/72 część cala).

dp (dip) – Density-independent Pixels - jednostka niezależna od gęstości pikseli. Najbardziej abstrakcyjna jednostka, która uniezależnia element layoutu od rozdzielczości oraz wielkości wyświetlacza. Dzięki temu też jest to najbardziej polecana jednostka do projektowania wyglądu aplikacji mobilnych. Jednostka ta bazuje na wyświetlaczu 160dpi (160punktów na cal). Dzięki temu 1dp jest odpowiednikiem 1 piksela przy gęstości 160dpi. Oczywiście stosunek piksel-dp jest zmieniany wraz ze zmianą gęstości wyświetlacza.

sp - Scale-independent Pixels. Jednostka o działaniu podobnym do dp, z tą różnicą, że podczas skalowania pod uwagę brane są również ustawienia użytkownika. Dokładnie, jednostka ta jest zależna od wartości Settings.System.FONT_SCALE. Dlatego też sp powinniśmy stosować do definiowania wielkości czcionek oraz wszystkich wymiarów z nimi związanych.

 

        Obraz zawierający tekst, zrzut ekranu, Wielobarwność, diagram

Zawartość wygenerowana przez AI może być niepoprawna.

        Rysunek przedstawia proporcje wielkości jednostki od gęstości ekranu

 

·      Chmurka - Toast:

 

Toast – „chmurka” wyświetlająca niewielką porcję informacji.

 

String text = "Przykładowy tekst komunikatu";
Toast toast = Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT);
toast.show();

Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
// wywołanie bez tworzenia obiektu

 

 

·      Context

 

W dużym skrócie:

Context to obiekt, który daje dostęp do zasobów i środowiska aplikacji.

Możesz o nim myśleć jako o „uchwycie” (handle) do wszystkiego, co związane z aplikacją — systemem Android, plikami, zasobami (strings.xml, colors.xml), bazami danych, itp.

 

Context umożliwia:

 

 

Tutaj this oznacza Context — w tym przypadku aktywność (Activity).
Metoda makeText() potrzebuje Context, żeby wiedzieć, w jakiej aplikacji i na jakim ekranie wyświetlić komunikat.

 

Typ Contextu

Gdzie używany

Co oznacza

Activity context (this lub MainActivity.this)

wewnątrz aktywności

Odnosi się do konkretnego ekranu (aktywności)

Application context (getApplicationContext())

w całej aplikacji

Globalny kontekst aplikacji (nie zależy od aktywności)

Service context

wewnątrz usługi (Service)

Kontekst komponentu działającego w tle

 

Różnica między this a getApplicationContext()

 

 

 

Różnica:

 

Użycie getApplicationContext() jest konieczne i preferowane, gdy musisz użyć kontekstu poza cyklem życia Aktywności i nie chcesz, aby Twój kod utrzymywał jej referencję (aby uniknąć wycieków pamięci). Dotyczy to sytuacji, gdy:

 

1Singleton jest jednym z najpopularniejszych wzorców projektowych (ang. Design Patterns), należącym do kategorii wzorców kreacyjnych. Jego podstawowym celem jest zagwarantowanie, że dana klasa ma tylko jedną instancję (jeden obiekt) w całej aplikacji i zapewnienie globalnego punktu dostępu do tej instancji.

                                

 

·      Motywy

 

Motyw (theme) to zestaw ustawień wizualnych, które definiują jak wygląda cała aplikacja lub jej poszczególne elementy (np. kolory, czcionki, tła, style przycisków, pól tekstowych itd.).

Można powiedzieć, że motyw to "ubranie" aplikacji – decyduje o jej stylu graficznym.
Motyw ustala np.:

 

 

Co definiuje motyw

Przykład

Kolor tła aplikacji

colorBackground

Kolor główny (akcentowy)

colorPrimary

Kolor przycisków

colorPrimaryContainer, colorButtonNormal

Kolor tekstu

colorOnPrimary, android:textColor

Czcionki

fontFamily, textAppearance

Styl okien i pasków

windowActionBar, statusBarColor

Zachowanie w trybie dzień/noc

Theme.Material3.DayNight

 

Każda aplikacja Android ma przypisany główny motyw, zwykle w pliku:

 

Obraz zawierający Czcionka, Grafika, tekst, zrzut ekranu

Zawartość wygenerowana przez AI może być niepoprawna.

 

Obraz zawierający tekst, zrzut ekranu, Czcionka

Zawartość wygenerowana przez AI może być niepoprawna.

 

·       name="Theme.MyApplication" — nazwa Twojego motywu,

·       parent="Theme.Material3.DayNight.NoActionBar" — motyw bazowy (czyli styl z biblioteki Google Material Design),

·       wewnątrz <item> ustawiasz konkretne kolory, czcionki i inne cechy.

 

Motyw dzienny i nocny (DayNight)

Android pozwala tworzyć dwa warianty motywu:

System automatycznie wybiera odpowiedni zestaw kolorów w zależności od trybu urządzenia (dzień/noc).

Przykład:

 

res/values/themes.xml (jasny)

 

Obraz zawierający tekst, zrzut ekranu, Czcionka

Zawartość wygenerowana przez AI może być niepoprawna.

 

res/values-night/themes.xml (ciemny)

 

Obraz zawierający zrzut ekranu, tekst, Czcionka, Grafika

Zawartość wygenerowana przez AI może być niepoprawna.

 

 

·      Szablon rozmieszczenia obiektów - LinearLayout

 

LinearLayout to jeden z podstawowych układów (layoutów) w Androidzie.
Umożliwia ustawianie elementów jeden za drugim — w pionie lub poziomie.

 

 Najważniejsze cechy:

 

 

Atrybut

Opis

android:padding

Ustawia margines wewnętrzny elementu — odstęp między krawędzią a jego zawartością.

android:gravity

Określa wyrównanie zawartości wewnątrz elementu (np. tekstu w TextView).

android:layout_gravity="center"

Określa pozycję elementu względem rodzica (np. wyśrodkowanie przycisku w układzie).

android:orientation="vertical"

Ustawia układ pionowy elementów w LinearLayout — jeden pod drugim.

android:orientation="horizontal"

Ustawia układ poziomy elementów w LinearLayout — obok siebie.

android:layout_weight

Określa proporcję zajmowanego miejsca przez element w LinearLayout (np. dwa przyciski z wagą „1” zajmą po 50%).

wrap_content

Element dopasowuje rozmiar do swojej zawartości (np. długości tekstu).

match_parent

Element zajmuje całą dostępną przestrzeń rodzica (100% szerokości lub wysokości).

 

 

Przykład wykorzystania siatki LinearLayout:

W przykładnie wykorzystano jeden główny LinearLayout w orientacji pionowej (vertical) oraz trzy LinearLayouty w orientacji poziomej (horizontal).

W pierwszym wstawiono przyciski 1,2,3 gdzie ich szerokość określona jest przez wagę layout_weight.

Przycisk nr 4 umieszczono jako osobny obiekt należący do głównej siatki z szerokością ustawioną jako match_parent (rozciągnięty do szerokości rodzica, czyli głównej siatki LinearLayout).

Przyciski 5,6,7 rozmieszczono w osobnym LinearLayout z orientacją poziomą (horizontal) z szerokością wrap_content (zawartość obiektu), wyrównane jako zawartość LinearLayoutu do środka (android:gravity="center").

 Przyciski 8,9 to przykład orientacji poziomej, gdzie pierwszy ma szerokość wrap_content, a drugi match_parent.

Ostatni przykład przycisku nr 10 pokazuje wyrównanie obiektu szerokości wrap_content jako całości do środka obiektu „matki” (android:layout_gravity="center").

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
   
android:orientation="vertical"
   
android:layout_width="match_parent"
   
android:layout_height="match_parent"
   
android:gravity="center">


    <LinearLayout
       
android:layout_width="match_parent"
       
android:layout_height="wrap_content"
       
android:orientation="horizontal">
        <Button
           
android:layout_width="0dp"
           
android:layout_height="wrap_content"
           
android:text="1"
           
android:layout_weight="1"/>
        <Button
           
android:layout_width="0dp"
           
android:layout_height="wrap_content"
           
android:text="2"
           
android:layout_weight="2"/>
        <Button
            
android:layout_width="0dp"
           
android:layout_height="wrap_content"
           
android:text="3"
           
android:layout_weight="1"/>
    </LinearLayout>

    <Button
       
android:layout_width="match_parent"
       
android:layout_height="wrap_content"
       
android:text="4"
       
/>
    <LinearLayout
       
android:layout_width="match_parent"
       
android:layout_height="wrap_content"
       
android:orientation="horizontal"
       
android:gravity="center">
        <Button
           
android:layout_width="wrap_content"
           
android:layout_height="wrap_content"
           
android:text="5"
           
/>
        <Button
           
android:layout_width="wrap_content"
           
android:layout_height="wrap_content"
           
android:text="6"
           
/>
        <Button
           
android:layout_width="wrap_content"
           
android:layout_height="wrap_content"
           
android:text="7"
           
/>
    </LinearLayout>


    <LinearLayout
       
android:layout_width="match_parent"
       
android:layout_height="wrap_content"
       
android:orientation="horizontal"
       
android:gravity="center">
        <Button
           
android:layout_width="wrap_content"
           
android:layout_height="wrap_content"
           
android:text="8"
           
/>

        <Button
           
android:layout_width="match_parent"
           
android:layout_height="wrap_content"
           
android:text="9"
           
/>
    </LinearLayout>

    <Button
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:text="10"
       
android:layout_gravity="center"/>

</LinearLayout>

 

Obraz zawierający zrzut ekranu, Prostokąt, linia, design

Zawartość wygenerowana przez AI może być niepoprawna.

 

 

·      Obsługa zdarzenia związane z obiektem RadioButton

 

 activity_main.xml

 

Obraz zawierający zieleń, zrzut ekranu, Grafika, Wielobarwność

Zawartość wygenerowana przez AI może być niepoprawna.

 

 

<RadioGroup
   
android:layout_width="match_parent"
   
android:layout_height="wrap_content"
   
android:orientation="vertical">

<RadioButton
   
android:layout_width="wrap_content"
   
android:layout_height="wrap_content"
   
android:text="Czerwony"
   
android:onClick="actionRed"/>
<RadioButton
   
android:layout_width="wrap_content"
   
android:layout_height="wrap_content"
   
android:onClick="actionGreen"
   
android:text="zielony"/>
</RadioGroup>

 

MainActivity.java

 

public class MainActivity extends AppCompatActivity {
    LinearLayout
linearLayout;

   
@Override
   
protected void onCreate(Bundle savedInstanceState) {
       
super.onCreate(savedInstanceState);
       
setContentView(R.layout.activity_main);
       
linearLayout = (LinearLayout)findViewById(R.id.linearLayoutGeneral);
   
}

   
public void actionRed(View view) {
       
linearLayout.setBackgroundColor(Color.RED);
   
}

   
public void actionGreen(View view) {
       
linearLayout.setBackgroundColor(Color.GREEN);
   
}
}

 

Przykład 2

activity_main.xml

 

<RadioGroup
   
android:id="@+id/radioGroup"
   
android:layout_width="match_parent"
   
android:layout_height="wrap_content"
   
android:orientation="vertical">

    <RadioButton
       
android:id="@+id/radio_czerwony"
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:text="Czerwony"/>

    <RadioButton
       
android:id="@+id/radio_zielony"
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:text="Zielony"/>
</RadioGroup>

 

MainActivity.java

 

binding.radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
   
@Override
   
public void onCheckedChanged(@NonNull RadioGroup radioGroup, int i) {

       
if (i == R.id.radio_czerwony) {
            Toast.makeText(MainActivity.this,
"Wybrano: Czerwony", Toast.LENGTH_SHORT).show();
        }
else if (i == R.id.radio_zielony) {
            Toast.makeText(MainActivity.this,
"Wybrano: Zielony", Toast.LENGTH_SHORT).show();
        }
    }
});

 

 

Obsługę zdarzeń można rówież zrobić poprzez implementację interfejsu RadioGroup.OnCheckedChangeListener();

 

public class MainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener{
    ActivityMainBinding
binding;

   
@Override
   
protected void onCreate(Bundle savedInstanceState) {
       
super.onCreate(savedInstanceState);

       
binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(
binding.getRoot());
       
binding.radioGroup.setOnCheckedChangeListener(this);
    }

   
@Override
   
public void onCheckedChanged(@NonNull RadioGroup radioGroup, int i) {
       
if (i == R.id.radio_czerwony) {
            Toast.makeText(MainActivity.this,
"Wybrano: Czerwony", Toast.LENGTH_SHORT).show();
        }
else if (i == R.id.radio_zielony) {
            Toast.makeText(MainActivity.this,
"Wybrano: Zielony", Toast.LENGTH_SHORT).show();
        }
    }
}

 

 

Częsty błąd podczas używania instrukcji switch z identyfikatorami zasobów (resource IDs) w Androidzie. Błąd constant expression required pojawia się, ponieważ wartości w case muszą być stałymi znanymi w czasie kompilacji, a identyfikatory zasobów, takie jak R.id.radio_czerwony, nie uznawane za takie w kontekście bloku switch w bibliotekach, które nie finalne. Aby to naprawić, powinieneś zastąpić instrukcję switch serią instrukcji if-else if-else.

 

switch (i) {
   
case R.id.radio_czerwony ->
            Toast.makeText(MainActivity.this,
"Wybrano: Czerwony", Toast.LENGTH_SHORT).show();

   
case R.id.radio_zielony ->
            Toast.makeText(MainActivity.this,
"Wybrano: Zielony", Toast.LENGTH_SHORT).show();

   
default ->
            Toast.makeText(MainActivity.this,
"Nie wybrano nic", Toast.LENGTH_SHORT).show();
}

 

 

·      Pobranie stanu z obiektu Radiobutton

 

Obraz zawierający tekst, zrzut ekranu, Czcionka, logo

Zawartość wygenerowana przez AI może być niepoprawna.

 

<?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:orientation="vertical"
   
android:layout_height="match_parent"
   
android:background="#673AB7"
   
android:padding="40dp"
   
tools:context=".MainActivity">

    <RadioGroup
       
android:id="@+id/radioGroup"
       
android:layout_width="match_parent"
       
android:layout_height="wrap_content"
       
android:orientation="vertical">

        <RadioButton
           
android:id="@+id/radio_czerwony"
           
android:layout_width="wrap_content"
           
android:layout_height="wrap_content"
           
android:text="Czerwony"/>

        <RadioButton
           
android:id="@+id/radio_zielony"
           
android:layout_width="wrap_content"
           
android:layout_height="wrap_content"
           
android:text="Zielony"/>
    </RadioGroup>

    <Button
       
android:id="@+id/button"
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:text="Sprawdz kolor"
       
/>

</LinearLayout>

 

 

binding.button.setOnClickListener(new View.OnClickListener() {
   
@Override
   
public void onClick(View view) {
       
if (binding.radioGroup.getCheckedRadioButtonId() == R.id.radio_czerwony) {
            Toast.makeText(MainActivity.this,
"Kolor czerwony", Toast.LENGTH_SHORT).show();
        }
else if (binding.radioGroup.getCheckedRadioButtonId() == R.id.radio_zielony){
            Toast.makeText(MainActivity.this,
"Kolor zielony", Toast.LENGTH_SHORT).show();
        }
else {
            Toast.makeText(MainActivity.this,
"Nie wybrano koloru", Toast.LENGTH_SHORT).show();
        }
    }
});

 

lub

 

setContentView(binding.getRoot());

binding.button.setOnClickListener(new View.OnClickListener() {
   
@Override
   
public void onClick(View view) {
       
if (binding.radioCzerwony.isChecked()){
            Toast.makeText(MainActivity.this,
"Czerwony", Toast.LENGTH_SHORT).show();
        }
else if (binding.radioZielony.isChecked()){
            Toast.makeText(MainActivity.this,
"Zielony", Toast.LENGTH_SHORT).show();
        }
else {
            Toast.makeText(MainActivity.this,
"Nie wybrano koloru", Toast.LENGTH_SHORT).show();
        }
    }
});

 

·      Pobranie stanu z obiektu CheckBox

 

Obraz zawierający tekst, zrzut ekranu, Czcionka, Jaskrawoniebieski

Zawartość wygenerowana przez AI może być niepoprawna.

 

<?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:orientation="vertical"
   
android:layout_height="match_parent"
   
android:background="#673AB7"
   
android:padding="40dp"
   
tools:context=".MainActivity">

        <CheckBox
           
android:id="@+id/checkbox_czerwony"
           
android:layout_width="wrap_content"
           
android:layout_height="wrap_content"
           
android:text="Czerwony"/>

        <CheckBox
           
android:id="@+id/checkbox_zielony"
           
android:layout_width="wrap_content"
           
android:layout_height="wrap_content"
           
android:text="Zielony"/>

    <Button
       
android:id="@+id/button"
       
android:layout_width="wrap_content"
       
android:layout_height="wrap_content"
       
android:text="Sprawdz kolor"
       
/>

</LinearLayout>

 

 

binding.button.setOnClickListener(new View.OnClickListener() {
   
@Override
   
public void onClick(View view) {
        String message=
"";
       
if (binding.checkboxCzerwony.isChecked()){
            message+=
binding.checkboxCzerwony.getText().toString();
        }
       
if (binding.checkboxZielony.isChecked()) {
            message+=
binding.checkboxZielony.getText().toString();
        }
       
if (message.equals(""))
            message=
"nie wybrano żadnego koloru";
        Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
    }
});

 

Do obsługi zdarzenia związanego z wyborem opcji checkBox można użyć interfejsu jak w przypadku obiektu RadioBatton CompoundButton.OnCheckedChangeListener

 

 

---------------------------------------------------------------------------------------------------------------------

4. Zadania

 

Zadanie 1.

Utwórz interfejs użytkownika używając siatki rozmieszczenia obiektów LinearLayout, jak na rysunku obok. Widok utwórz w kodzie XML. Po naciśnięciu przycisku w chmurce (obiekt Toast) powinny pojawić się wszystkie informacje zapisane w polach tekstowych oraz obiekcie RadioButton.

 

Obraz zawierający tekst, zrzut ekranu, oprogramowanie, System operacyjny

Zawartość wygenerowana przez AI może być niepoprawna.

 

Zadanie 2.

Zmodyfikuj kod programu z przykładu z instrukcji powyżej zmieniając jego główny motyw:

- motyw dzienny: kolor przycisków granatowy, kolor tekstu czerwony i kolor tła żółty.

- motyw nocny:  kolor przycisków zielony, kolor tła granatowy, kolor tekstu czarny.

 

Obraz zawierający zrzut ekranu, Prostokąt, linia, design

Zawartość wygenerowana przez AI może być niepoprawna.  Obraz zawierający zrzut ekranu, żółty, Prostokąt, design

Zawartość wygenerowana przez AI może być niepoprawna.  Obraz zawierający zrzut ekranu, tekst, Wielobarwność, linia

Zawartość wygenerowana przez AI może być niepoprawna.

 

Zadanie 3.

Napisz program, w którym ułóż komponenty widoku, jak na zdjęciu poniżej.

Po naciśnięciu przycisku generowany jest kolor pobrany wg opcji wyboru z chcekBox-ów. Pomocna może okazać się konstrukcja:

 

String kolor="#"+sCzerwony+sZielony+sniebieski;
binding.main.setBackgroundColor(Color.parseColor(kolor));

 

Kolory dostępne w obiektach RadioButton ustawiają kolor tekstu „KOLOR” bezpośrednio po wybraniu jednej z dostępnych opcji koloru.

 

Obraz zawierający tekst, zrzut ekranu, Czcionka, Jaskrawoniebieski

Zawartość wygenerowana przez AI może być niepoprawna. Obraz zawierający tekst, zrzut ekranu, żółty, Czcionka

Zawartość wygenerowana przez AI może być niepoprawna. Obraz zawierający tekst, zrzut ekranu, Czcionka, projekt graficzny

Zawartość wygenerowana przez AI może być niepoprawna. Obraz zawierający tekst, zrzut ekranu, Czcionka, projekt graficzny

Zawartość wygenerowana przez AI może być niepoprawna.