2. diel - Vlastné Android komponent - Dokončenie textového poľa
V minulej lekcii, Vlastné Android komponent - Vytvorenie a usadenie do layoutu , sme vytvorenú komponent usadili do layoutu.
V tejto lekcii nadviažeme tým, že si ukážeme použitie atribútov vlastnej textovej komponenty v praxi.
Dokončenie vlastného textového poľa
Budeme pokračovať v našom postupe, čakajú nás parametre komponenty.
Použitia vytvorených parametrov a nastavení komponenty
Najprv poďme dostať parametre z XML rozloženie do triedy reprezentujúci
vlastnej View
.
Načítanie parametrov
V triede CustomInput
sme si zatiaľ ukázali len konštruktory.
Ako už bolo spomenuté, tieto parametre získame v konstruktoru z parametra
attrs
. Teraz si napíšeme metódu, ktorá sa postará o
spracovaní našich vlastných atribútov prevzatých z XML:
String text = null; // Text zadávacího pole String titleText = null; // Text nad zadávacím polem String errText = null; // Text chybové hlášky String requiredText = null; // Textový řetězec, který zadaný text musí obsahovat int requiredNumberOfCharacters = 0; // Minimální počet zadaných znaků private void applyAttributeSet(AttributeSet attrs) { if (attrs == null) return; TypedArray ta = getContext().getTheme().obtainStyledAttributes( attrs, R.styleable.CustomInput, 0, 0); if (ta == null) return; try { text = ta.getString(R.styleable.CustomInput_ciText); titleText = ta.getString(R.styleable.CustomInput_ciTitleText); errText = ta.getString(R.styleable.CustomInput_ciErrText); requiredText = ta.getString(R.styleable.CustomInput_ciRequiredText); requiredNumberOfCharacters = ta.getInteger( R.styleable.CustomInput_ciRequiredNumberOfCharacters, 0); } finally { ta.recycle(); } }
Na začiatku metódy vytvárame inštanciu TypedArray
, z ktorej
následne získavame samotnej atribúty a ukladáme ich do pripravených
premenných. Všimnite si, akým spôsobom získavame jednotlivé parametre -
jedná sa o názov vzniknutý zloženinou dvoch "slov" oddelených
podčiarknikom (napr. CustomInput_ciText
). Tento názov teda
obsahuje:
- Atribút
name
v hlavičke v súboreattrs.xml
(<declare-styleable name="CustomInput">
) - Názov parametra (deklarovaný v
attrs.xml
)
Volanie vytvorené metódy applyAttributeSet(AttributeSet attrs)
pridáme do všetkých konstruktoru, ktoré sú používané pri konfigurácii
objektu v XML rozvrhnutie, teda do všetkých konstruktoru okrem toho prvého a
to takto:
applyAttributeSet(attrs);
Spracovanie parametrov
Parametre máme z XML načítané v triede v premenných, teraz je potreba
pomocou získaných atribútov inicializovať našu komponent. V tejto
súvislosti si napíšeme metódu init()
.
V tejto metóde nastavíme všetkým prvkom požadované parametre.
Nastavíme tak text v hlavičke, text chybové hlášky, prípadne aj
predvolený text komponenty EditText
. Nasleduje nastavenie
Listener
pre EditText
. Listener
bude
strážiť zmeny obsahu EditText
a za behu bude kontrolovať
splnenie zadaných podmienok. Ak Listener
usúdi, že zadaný text
nezodpovedá nastaveným požiadavkám, zobrazí červený text s chybovým
hlásením.
Kód metódy je nasledovné:
View rootView; TextView labelTitleText; TextView labelErrText; EditText etInput; private void init() { // Získání XML rozvržení vlastního View rootView = inflate(getContext(), R.layout.my_input, this); // Proměnné pro objekty vlastního View, se kterému chceme pracovat labelTitleText = rootView.findViewById(R.id.labelTitleText); labelErrText = rootView.findViewById(R.id.labelErrText); etInput = rootView.findViewById(R.id.etInput); if (titleText != null) { labelTitleText.setText(titleText); } else { labelTitleText.setText(""); } if (errText != null) { labelErrText.setText(errText); } else { labelErrText.setText(""); } // "Odposlouchávač" změn textu etInput.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {} @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {} @Override public void afterTextChanged(Editable editable) { String inputText = editable.toString().toLowerCase(); boolean showError = false; if (inputText.equals("")) { hideErrText(); return; } if (requiredText != null) { if (!requiredText.equals("")) { if (!inputText.contains(requiredText)) { showError = true; } } } if (requiredNumberOfCharacters > 0) { if (inputText.length() < requiredNumberOfCharacters) { showError = true; } } if (showError) { showErrText(); } else { hideErrText(); } } }); }
Zavolanie metódy
Volanie metódy init()
takisto vložíme do konstruktoru našej
komponenty. Na rozdiel od predchádzajúcej metódy metóda init()
bude volaná vo všetkých konstruktoru. Poďme si pre úplnosť radšej
ukázať, ako konštruktory vyzerajú:
public CustomInput(Context context) { super(context); init(); } public CustomInput(Context context, @Nullable AttributeSet attrs) { super(context, attrs); applyAttributeSet(attrs); init(); } public CustomInput(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); applyAttributeSet(attrs); init(); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public CustomInput(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); applyAttributeSet(attrs); init(); }
Práca s komponentom
Teraz sa pozrieme na to, ako vyzerá práca s vlastnou komponentom, ktorá bola vložená do XML. Pôjde o prácu z Java kódu aplikácie:
// Získání reference na objekt v XML customInput1 = findViewById(R.id.myCustomInput1); // Programové nastavení atributů. customInput1.setTitleText("Title"); customInput1.setErrText("Error text"); customInput1.setRequiredText("required text");
Vytvorenie komponenty programovo
Ešte si ukážeme, ako náš objekt vytvoriť programovo, teda bez vkladanie do XML aplikácie:
newCustomInput = new CustomInput(context); newCustomInput.setTitleText("Ahoj! Napiš alespoň dva znaky!"); newCustomInput.setErrText("Toto je málo..."); newCustomInput.setRequiredNumberOfCharacters(2); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); params.setMargins(dipToPx(10), dipToPx(10), dipToPx(10), dipToPx(10)); newCustomInput.setLayoutParams(params); layout.addView(newCustomInput);
Pri nastavovaní margine nového objektu sme použili metódu
dipToPx()
. Pretože v triede nášho objektu View
pracujeme so základnou rozmerovú jednotkou (pixel) a v kóde chceme pracovať
s jednotkou dip, je nutné zaistiť prevod hodnoty dip na pixel, čo zaistí
táto metóda:
public int dipToPx(float dpValue) { final float scale = getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); }
Uloženie stavu vlastného
View
Predpokladám, že vám nie je úplne cudzí problematika ukladanie stavu
aplikácie, napríklad, počas otočenie telefónu (tabletu). Ukladanie stavu
vlastného View
je veľmi podobné. Platí pravidlo, že systém
Android automaticky ukladá stav defaultných View
. Ale iba ak
majú nastavené ID. Keď ukážkovej zadávacie pole vložíme do nejakého
projektu, spustíme aplikáciu a zadáme do neho nejaký text, bude si
EditText
, ktorý je súčasťou zadávacieho poľa, obsah pamätať
aj po otočení telefónu. Pokiaľ ale vytvoríme viac inštancií vytvoreného
View
do jedného layoutu, nastane problém.
Tejto problematike budeme venovať samostatný článok, pretože informácií je pomerne veľa. Tu problém otočenie zmieňujem pre tých, ktorí sa hneď pustí do testovania a do popísanej situácie sa dostanú. Nie je to teda chyba:-)
Vysvetlenie nájdete na konci tohto kurzu, v samostatných článkoch, v
ktorých si túto problematiku podrobne vysvetlíme a naučíme sa ovládať
uchovávanie stavu objektov, ktoré sú potomkami triedy View
.
V budúcej lekcii, Spinner - Príprava pre vytvorenie obrázkových položiek , si pripravíme XML a vlastné Java triedu pre Spinner s obrázkami položiek.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 7x (18.05 MB)
Aplikácia je vrátane zdrojových kódov v jazyku Java