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.

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:
![]()

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

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

·
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>

· Obsługa zdarzenia związane z obiektem RadioButton
activity_main.xml

<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 są uznawane
za takie w kontekście bloku switch w bibliotekach, które nie są
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

<?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

<?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.

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.

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.
