1. diel - Vlastné Android komponent - Vytvorenie a usadenie do layoutu
V minulej lekcii, Spinner - Vytvorenie základného roletového menu , sme začali pracovať na projekte ukážkové aplikácie s tromi spinnery. Prvé, používajúci len základné nastavenie, sme zároveň dokončili.
Vitajte u kurzu, v ktorom sa naučíte vytvárať vlastné komponenty pre vaše Android aplikácie v Jave.
Motivácia
Android poskytuje sadu všeobecných komponentov, s ktorými si, väčšinou,
vo svojich projektoch vystačíme. Button
, EditText
,
TextView
, ProgressBar
, ... Občas by sa nám ale iste
hodilo, aby nejaká komponenta mala niečo navyše - iný vzhľad alebo iné
správanie. Napríklad TextView
s vlastným fontom, alebo nejaké
špeciálne tlačidlo. A alebo dokonca budeme potrebovať nejakú špeciálnu
komponent, ktorá nie je v štandardnej ponuke a ani sa jej žiadna štandardná
komponenta nepodobá. Môže to byť napríklad ovládací prvok v prehrávači
médií, nejaký graf atď.
Potrebu použiť vlastné komponentu je možné samozrejme vyriešiť aj inak, než vytvorením nového vlastného objektu, ale bude to pravdepodobne znamenať písanie veľkého množstva kódu. To je nevhodné hlavne keď takú komponent budeme chcieť v rozsiahlejšom projekte použiť viackrát.
Vytvorenie vlastnej komponenty
Existujú dva základné spôsoby, ako vytvoriť vlastné komponent:
- Objekt je priamy potomok triedy
View
(napr.public class MyView extends View {}
) - Objekt je potomkom už existujúce triedy (napr.
public class MyView extends TextView {}
)
Všetko si budeme ukazovať na konkrétnych príkladoch. Postupovať budeme nasledovne:
- Vytvoríme XML návrh komponenty
- Vytvoríme triedu Dedič od triedy
View
alebo nejakého jej potomka - Definujeme parametre pre nastavenie komponenty
- Vložíme vytvorený XML návrh do layoutu
- Použijeme vytvorené parametre a nastavení komponenty
- S kódom budeme pracovať v
MainActivity.java
Vlastné textové pole
Začneme vytvorením vlastného poľa pre zadávanie textu. Postupne sa dostaneme aj k zložitejším príkladom. Na nasledujúcom obrázku je vidieť cieľ nášho snaženia:
Hlavnou súčasťou budúcej komponenty bude EditText
, ktorého
obsah bude aplikácia pri písaní textu priebežne kontrolovať a zisťovať,
či zadaný text zodpovedá nastaveným kritériám. Môžeme kontrolovať
napríklad počet zadaných znakov alebo prítomnosť preddefinovaného
textového reťazca. Pokiaľ zadaný text nebude spĺňať stanovené
požiadavky, bude v pravom dolnom rohu komponenty zobrazený červený varovný
text. Obsah tohto textu bude tiež možné nastaviť, rovnako tak i text v
hlavičke komponenty.
Ideme teda na to a v Android Štúdiu založíme nový projekt, ktorý
pomenujeme CustomInput
. Ako prvý vytvoríme XML návrh
komponenty.
Xml návrh komponenty
V nasledujúcej ukážke kódu je XML rozvrhnutie budúceho objektu
vlastného zadávacieho poľa. V priečinku projektu res/layout/
vytvoríme nový XML súbor pomenovaný my_input.xml
:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/my_input_background" android:orientation="vertical" android:paddingStart="10dp" android:paddingLeft="10dp" android:paddingTop="10dp" android:paddingEnd="10dp" android:paddingRight="10dp" android:paddingBottom="3dp"> <TextView android:id="@+id/labelTitleText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Text v záhlaví komponenty" > </TextView> <EditText android:id="@+id/etInput" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="text" /> <TextView android:id="@+id/labelErrText" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="right" android:text="Chybová zpráva" android:textColor="#C50000" android:textSize="12sp" android:visibility="invisible" /> </LinearLayout>
Hlavný layout komponenty má nastavené pozadie pomocou odkazu na súbor XML
android:background="@drawable/my_input_background"
. Ten vytvoríme
v priečinku projektu res/drawable/
. Súbor s pozadím pomenujeme
my_input_background.xml
a vložíme do neho tento kód:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <solid android:color="#ECECEC" /> <stroke android:width="1dp" android:color="#000000"/> <corners android:radius="2dp"/> </shape>
Trieda Dedič od triedy
View
Základom každej vlastné komponenty je trieda, ktorá je odvodená, či už
priamo alebo nepriamo, od triedy View
. Naše ukážkovej zadávacie
pole bude dediť od triedy LinearLayout
, čo znamená, že nepriamo
dedíme od triedy View
. Celá hierarchia dedenie vyzerá takto:
Object
-> View
-> ViewGroup
->
LinearLayout
. Triedu nové komponenty pomenujeme
CustomInput
a vytvoríme jej v hlavnej zložke projekte
java/com.example.custominput/
. Základom každej triedy, ktorá je
potomkom triedy View
, sú štyri preťaženia konstruktoru:
public class CustomInput extends LinearLayout { public CustomInput(Context context) { super(context); } public CustomInput(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public CustomInput(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public CustomInput(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } }
Prvý konštruktor je používaný na vytvorenie inštancie objektu pomocou kódu. Ostatné konštruktory sú tu pre objekt konfigurovaný v XML rozvrhnutie.
Ak budete pracovať na projekte, ktorý bude určený pre
veľký rozsah verzií systému Android, bude pravdepodobne potrebné k
štvrtému konstruktoru pridať anotáciu napr.
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
. Táto anotácia
označuje konštruktor použiteľný iba na danej úrovni API alebo
vyššej.
Konštruktory určené pre konfiguráciu v XML obsahujú parameter
AttributeSet attrs
. Zjednodušene povedané sa jedná o kolekciu
atribútov, ktoré boli nájdené pri objekte v XML rozvrhnutie a sú v
parametri attrs
odovzdávané do triedy objektu, kde s nimi
môžeme ďalej pracovať.
V okamihu, keď pri písaní vlastnej triedy v hlavičke triedy doplníme
extends LinearLayout
, nás Android Studio upozorní na nutnosť
pridanie konštruktory a samo nám ponúkne ich vygenerovanie.
Parametre pre nastavenie komponenty
Ak budeme chcieť, aby bolo možné nášmu objektu nastavovať nejaké
vlastnosti, musíme tieto vlastnosti reprezentovať nejakými atribúty a
definovať ich. Teraz si ukážeme, ako na to. Najprv je nutné v
resources
projekte vytvoriť súbor attrs.xml
,
ktorého umiestnenie je zrejmé z obrázku:
A tu je príklad obsahu súboru attrs.xml
pre spomínané
zadávacie pole:
<resources> <declare-styleable name="CustomInput"> <attr name="ciText" format="string" /> <attr name="ciTitleText" format="string" /> <attr name="ciErrText" format="string" /> <attr name="ciRequiredText" format="string" /> <attr name="ciRequiredNumberOfCharacters" format="integer" /> </declare-styleable> </resources>
V riadku <declare-styleable name="CustomInput">
je
dôležitý atribút name
. Ten totiž hrá úlohu v
"pomenovávaní" parametrov v triede našej komponenty pri ich získavaní z XML
- za chvíľu si to ukážeme.
Poďme sa zoznámiť s práve definovanými atribúty v
attrs.xml
:
ciText
- nastavenie východiskového textu pole pre zadávanie textuciTitleText
- nastavenie textu v hlavičke komponentyciErrText
- nastavenie textu červené chybové správyciRequiredText
- znak alebo textový reťazec, ktorý musí zadaný text obsahovaťciRequiredNumberOfCharacters
- minimálny požadovaný počet znakov v zadanom texte
Prvé štyri parametre sú typu string
, posledný je typu
integer
. Samozrejme existuje viac dátových typov, ktoré je
možné v iných prípadoch použiť. Tu je stručný prehľad použiteľných
typov parametrov:
parameter | dátový typ |
---|---|
boolean | boolean |
color | @ColorInt int |
dimension | @LayoutDimension int |
dimension | @Px int |
enum | int |
flag | int |
float | float |
fraction | @Fraction (base =?, Pbase =?) Float |
integer | int |
referencie | @ AnyRes * int |
referencie | CharSequence [] |
referencie | ColorStateList |
referencie | Drawable |
referencie | Typeface |
string | CharSequence |
string | string |
string | Typeface |
- možno použiť ľubovoľnú anotáciu
@...Res
Definované atribúty neskôr (po "Rebuild" projektu) nájdete medzi defaultným parametrami pri konfigurácii zadávacieho poľa v XML v Android Studiu, viď. nasledujúci obrázok:
Naše nové atribúty začínajú na ci
. A to len kvôli
prehľadnosti - aby sme ich medzi ostatnými defaultným parametre našli
všetky na jednom mieste. V Android Štúdiu sú totiž atribúty zoradené
podľa abecedy.
Vloženie vytvoreného XML návrhu do layoutu
Vlastné atribúty použijeme v súboroch XML rozvrhnutie rovnako ako tie
defaultný. Jediným rozdielom je, že naše atribúty patrí do inej skupiny.
Namiesto toho, aby patrili do
http://schemas.android.com/apk/res/android
, patrí do
http://schemas.android.com/apk/res/[náš_název_balíčku ]
.
V Android Štúdiu to znamená to, že do nadradeného (alebo do hlavného)
layoutu v XML vložíme riadok
xmlns:app="http://schemas.android.com/apk/res-auto"
. Ak na to
zabudnete, Android Studio vás na to upozorní.
Náš vlastný atribút potom nebude vložený štýlom
android: ...
ale app: ...
. Všimnite si aj názvu
našej komponenty v XML - nie je to nič moc pekného, ale má to logiku:-)
Nasleduje XML kód layoutu aplikácie, v ktorom je vložená nová
komponenta:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.example.custominput.CustomInput android:id="@+id/myCustomInput1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" app:ciErrText="Text neobsahuje slovo PES nebo je kratší než 10 znaků!" app:ciRequiredNumberOfCharacters="10" app:ciRequiredText="pes" app:ciTitleText="Zadej text obsahjící slovo PES. Text musí obsahovat minimálně 10 znaků"> </com.example.custominput.CustomInput> </LinearLayout>
Takto použité zadávacie pole teda bude požadovať zadanie minimálne desiatich znakov a zároveň, aby vložený text obsahoval reťazec "pes". Kým nebudú obe tieto podmienky splnené, bude zobrazená červená hláška v pravej spodnej časti komponenty. Text tejto chybové hlášky je tiež nastavený v XML. Len poznamenám, že chybová hláška nebude zobrazená v prípade, že textové pole nebude obsahovať žiadny text.
Premenné pre parametre
Na záver tejto časti si vo vytvorenej triede CustomInput
deklarujeme premenné a metódy, ktorými neskôr komponentu nastavíme
programovo v kóde:
// Proměnné pro reference na jednotlivé komponenty našeho View v XML TextView labelTitleText; // Text nad textovým polem TextView labelErrText; // Chybová hláška pod textovým polem EditText etInput; // Pole pro zadání textu public void setTitleText(String titleText) { this.titleText = titleText; this.labelTitleText.setText(titleText); } public void setErrText(String errText) { this.errText = errText; this.labelErrText.setText(errText); } public void setRequiredText(String requiredText) { this.requiredText = requiredText; }
V budúcej lekcii, Spinner - Vlastné TextView položky - Java kód , doplníme projekt ukážkové aplikácie o Java kód druhého Spinner, ktorý sa od toho prvého bude líšiť nielen vzhľadom, ale i spôsobom práce s dátami.