IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 7 - Vlastní Android komponenta - Vytvoření a usazení do layoutu

V předchozím kvízu, Kvíz - Tvorba vlastního Spinneru v Androidu, jsme si ověřili nabyté zkušenosti z předchozích lekcí.

V dnešní lekci započneme vytváření vlastních komponent pro naše Android aplikace v Javě.

Motivace

Android poskytuje sadu obecných komponent, se kterými si, většinou, ve svých projektech vystačíme. Button, EditText, TextView, ProgressBar, ... Občas by se nám ale jistě hodilo, aby nějaká komponenta měla něco navíc - jiný vzhled nebo jiné chování. Například TextView s vlastním fontem, nebo nějaké speciální tlačítko. A nebo dokonce budeme potřebovat nějakou speciální komponentu, která není ve standardní nabídce a ani se jí žádná standardní komponenta nepodobá. Může to být například ovládací prvek v přehrávači médií, nějaký graf atd.

Potřebu použít vlastní komponentu lze samozřejmě vyřešit i jinak, než vytvořením nového vlastního objektu, ale bude to pravděpodobně znamenat psaní velkého množství kódu. To je nevhodné hlavně když takovou komponentu budeme chtít v rozsáhlejším projektu použít vícekrát.

Vytvoření vlastní komponenty

Existují dva základní způsoby, jak vytvořit vlastní komponentu:

  • Objekt je přímý potomek třídy View (např. public class MyView extends View {})
  • Objekt je potomkem již existující třídy (např. public class MyView extends TextView {})

Vše si budeme ukazovat na konkrétních příkladech. Postupovat budeme následovně:

  • Vytvoříme XML návrh komponenty
  • Vytvoříme třídu dědící od třídy View nebo nějakého jejího potomka
  • Definujeme parametry pro nastavení komponenty
  • Vložíme vytvořený XML návrh do layoutu
  • Použijeme vytvořené parametry a nastavení komponenty
  • S kódem budeme pracovat v MainActivity.java

Vlastní textové pole

Začneme vytvořením vlastního pole pro zadávání textu. Postupně se dostaneme i ke složitějším příkladům. Na následujícím obrázku je vidět cíl našeho snažení:

Vlastní textové pole pro Android v Javě - Vlastní vzhled Android komponent

Hlavní součástí budoucí komponenty bude EditText, jehož obsah bude aplikace při psaní textu průběžně kontrolovat a zjišťovat, zda zadaný text odpovídá nastaveným kritériím. Můžeme kontrolovat například počet zadaných znaků nebo přítomnost předem definovaného textového řetězce. Pokud zadaný text nebude splňovat stanovené požadavky, bude v pravém dolním rohu komponenty zobrazen červený varovný text. Obsah tohoto textu bude též možné nastavit, stejně tak i text v hlavičce komponenty.

Jdeme tedy na to a v Android Studiu založíme nový projekt, který pojmenujeme CustomInput. Jako první vytvoříme XML návrh komponenty.

XML návrh komponenty

V následující ukázce kódu je XML rozvržení budoucího objektu vlastního zadávacího pole. Ve složce projektu res/layout/ vytvoříme nový XML soubor pojmenovaný 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á nastaveno pozadí pomocí odkazu na soubor XML android:background="@drawable/my_input_background". Ten vytvoříme ve složce projektu res/drawable/. Soubor s pozadím pojmenujeme my_input_background.xml a vložíme do něj 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>

Třída dědící od třídy View

Základem každé vlastní komponenty je třída, která je odvozena, ať už přímo nebo nepřímo, od třídy View. Naše ukázkové zadávací pole bude dědit od třídy LinearLayout, což znamená, že nepřímo dědíme od třídy View. Celá hierarchie dědění vypadá takto: Object -> View -> ViewGroup -> LinearLayout. Třídu nové komponenty pojmenujeme CustomInput a vytvoříme jí v hlavní složce projektu java/com.example.custominput/. Základem každé třídy, která je potomkem třídy View, jsou čtyři přetížení 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);
    }
}

První konstruktor je používán k vytvoření instance objektu pomocí kódu. Ostatní konstruktory jsou zde pro objekt konfigurovaný v XML rozvržení.

Budete-li pracovat na projektu, který bude určen pro velký rozsah verzí systému Android, bude pravděpodobně nutné ke čtvrtému konstruktoru přidat anotaci např. @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP). Tato anotace označuje konstruktor použitelný pouze na dané úrovni API nebo vyšší.

Konstruktory určené pro konfiguraci v XML obsahují parametr AttributeSet attrs. Zjednodušeně řečeno se jedná o kolekci atributů, které byly nalezeny u objektu v XML rozvržení a jsou v parametru attrs předávány do třídy objektu, kde s nimi můžeme dále pracovat.

V okamžiku, kdy při psaní vlastní třídy v hlavičce třídy doplníme extends LinearLayout, nás Android Studio upozorní na nutnost přidání konstruktorů a samo nám nabídne jejich vygenerování.

Parametry pro nastavení komponenty

Budeme-li chtít, aby bylo možné našemu objektu nastavovat nějaké vlastnosti, musíme tyto vlastnosti reprezentovat nějakými atributy a definovat je. Nyní si ukážeme, jak na to. Nejprve je nutné v resources projektu vytvořit soubor attrs.xml, jehož umístění je patrné z obrázku:

Vytvoření resources v Android Studio - Vlastní vzhled Android komponent

A zde je příklad obsahu souboru attrs.xml pro zmíněné zadávací 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 řádku <declare-styleable name="CustomInput"> je důležitý atribut name. Ten totiž hraje roli v "pojmenovávání" parametrů ve třídě naší komponenty při jejich získávání z XML - za chvíli si to ukážeme.

Pojďme se seznámit s právě definovanými atributy v attrs.xml:

  • ciText - nastavení výchozího textu pole pro zadávání textu
  • ciTitleText - nastavení textu v hlavičce komponenty
  • ciErrText - nastavení textu červené chybové zprávy
  • ciRequiredText - znak nebo textový řetězec, který musí zadaný text obsahovat
  • ciRequiredNumberOfCharacters - minimální požadovaný počet znaků v zadaném textu

První čtyři parametry jsou typu string, poslední je typu integer. Samozřejmě existuje více datových typů, které je možné v jiných případech použít. Zde je stručný přehled použitelných typů parametrů:

Parametr Datový 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
reference @AnyRes* int
reference CharSequence[]
reference ColorStateList
reference Drawable
reference Typeface
string CharSequence
string String
string Typeface

*lze použít libovolnou anotaci @...Res

Definované atributy později (po "rebuildu" projektu) naleznete mezi defaultními parametry při konfiguraci zadávacího pole v XML v Android Studiu, viz. následující obrázek:

Atributy v Android Studio - Vlastní vzhled Android komponent

Naše nové atributy začínají na ci. A to jen kvůli přehlednosti - abychom je mezi ostatními defaultními parametry nalezli všechny na jednom místě. V Android Studiu jsou totiž atributy řazeny podle abecedy.

Vložení vytvořeného XML návrhu do layoutu

Vlastní atributy použijeme v souborech XML rozvržení stejně jako ty defaultní. Jediným rozdílem je, že naše atributy patří do jiné skupiny. Namísto toho, aby patřily do http://schemas.android.com/apk/res/android, patří do http://schemas.android.com/apk/res/[náš_název_balíčku]. V Android Studiu to znamená to, že do nadřazeného (nebo do hlavního) layoutu v XML vložíme řádek xmlns:app="http://schemas.android.com/apk/res-auto". Pokud na to zapomenete, Android Studio vás na to upozorní.

Náš vlastní atribut potom nebude vložen stylem android: ... ale app: .... Všimněte si i názvu naší komponenty v XML - není to nic moc hezkého, ale má to logiku :-) Následuje XML kód layoutu aplikace, ve kterém je vložena 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ávací pole tedy bude požadovat zadání minimálně deseti znaků a zároveň, aby vložený text obsahoval řetězec "pes". Dokud nebudou obě tyto podmínky splněny, bude zobrazena červená hláška v pravé spodní části komponenty. Text této chybové hlášky je také nastaven v XML. Jen poznamenám, že chybová hláška nebude zobrazena v případě, že textové pole nebude obsahovat žádný text.

Proměnné pro parametry

Na závěr této části si ve vytvořené třídě CustomInput deklarujeme proměnné a metody, kterými později komponentu nastavíme programově v kódu:

// 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;
}

Příště, v lekci Vlastní Android komponenta - Dokončení textového pole, si ukážeme, jak vytvořené atributy použít ;-)


 

Předchozí článek
Kvíz - Tvorba vlastního Spinneru v Androidu
Všechny články v sekci
Vlastní vzhled Android komponent
Přeskočit článek
(nedoporučujeme)
Vlastní Android komponenta - Dokončení textového pole
Článek pro vás napsal Pavel
Avatar
Uživatelské hodnocení:
4 hlasů
Autor se věnuje programování v Javě, hlavně pro Android. Mezi jeho další zájmy patří Arduino, Minecraft.
Aktivity