Vyvíjíme pro Android: Bližší pohled na pohledy – 1. díl

Jak bychom mohli vyvíjet aplikace pro Android, kdybychom neuměli používat vestavěná View? Jak bychom tvořili uživatelské rozhraní, kdybychom neuměli pracovat s Layouty? V dnešním dvojčlánku si všechny důležité představíme a povíme si něco o jejich atributech a metodách.
Seriál: Vyvíjíme pro Android (14 dílů)
- Vyvíjíme pro Android: Začínáme 15. 6. 2012
- Vyvíjíme pro Android: První krůčky 22. 6. 2012
- Vyvíjíme pro Android: Suroviny, Intenty a jednotky 29. 6. 2012
- Vyvíjíme pro Android: Bližší pohled na pohledy – 1. díl 13. 7. 2012
- Vyvíjíme pro Android: Bližší pohled na pohledy – 2. díl 13. 7. 2012
- Vyvíjíme pro Android: Fragmenty a SQLite databáze 20. 7. 2012
- Vyvíjíme pro Android: Preference, menu a vlastní Adapter 27. 7. 2012
- Vyvíjíme pro Android: Intenty, intent filtry a permissions 3. 8. 2012
- Vyvíjíme pro Android: Content providery 10. 8. 2012
- Vyvíjíme pro Android: Dialogy a activity 17. 8. 2012
- Vyvíjíme pro Android: Stylování a design 24. 8. 2012
- Vyvíjíme pro Android: Notifikace, broadcast receivery a Internet 31. 8. 2012
- Vyvíjíme pro Android: Nahraváme aplikaci na Google Play Store 7. 9. 2012
- Vyvíjíme pro Android: Epilog 14. 9. 2012
Nálepky:
V článku Vyvíjíme pro Android: Suroviny, Intenty a jednotky jsme pochopili, jak fungují resources, co jsou to modifikátory, zjistili jsme, co to je jednotka dp
, naučili jsme se ukládat řetězce jako suroviny, seznámili jsme se s Intenty, upravovali jsme různá View za běhu; stručně řečeno, bylo toho hodně. Dnes si od úplně nových konceptů dáme téměř oddych a budeme si rozšiřovat znalosti věcí, o kterých již víme, že existují. Představíme si jednotlivá view.
Protože byl minulý týden svátek a žádný nový díl nevyšel, dnes jsem si pro vás připravil hned dvojdíl.
Jak vlastně view fungují?
Abychom je mohli používat, musíme vědět, co to ta View
jsou, jak se liší od svého potomka ViewGroup
, jaké mají tyto třídy metody a jak je používat.
View je základní stavební jednotkou uživatelského rozhraní. Textový popisek je view, stejně tak jako tlačítko, rozbalovací seznam anebo LinearLayout
, který už známe a který určuje, jako budou jednotlivá view uspořádána. ViewGroup
je velmi důležitá dceřiná třída View
, která může obalovat jedno nebo více View (tedy i ViewGroup) a má na starosti jejich rozmístění a vykreslení. Jak může takový jednoduchý layoutový strom vypadat, je ukázáno v dokumentaci.
Stromy mohou být mnohem složitější, ale snažte se vždy o co největší jednoduchost, jakmile se začne struktura komplikovat, měli byste se zamyslet, zdali to nelze udělat jinak, zdali neexistuje nějaké už hotové view, které daný problém řeší elegantněji případně zdali si takové view nevytvořit. Také se snažte jednotlivé celistvé bloky uživatelského rozhraní vytvářet jako fragmenty.
Na následujících řádcích budu probírat jednotlivé potomky třídy View
, ukážeme si, jak vypadají, popíšeme si důležité atributy a důležité funkce.
Ve druhém dílu jsem mluvil o konvencích, co se velikosti písmen, uzavírání do <code>
týče atpod. Rozhodl jsem se to změnit. Do <code>
budu uzavírat jen tehdy, když mluvím o konkrétní třídě, například že má nějaké metody nebo potomky ( View
). Když mluvím o jejích instancích anebo potomcích, použiji variantu s velkým písmenem, ale ne strojopisem (View), a když mluvím o obecném vzoru, použiji malé počáteční písmeno (view). Není nijak důležité si to pamatovat, jen obhajuji, že ten zdánlivý chaos má (většinou) určitý řád.
View
Třída View
je rodičem všech dalších tříd, o nichž si budeme dnes povídat. Implementuje všechny základní metody a atributy, a to jak „technické“ (jak se view vykreslí), tak „vzhledové“, tedy různé manipulace s tím daným view, měnění jeho atributů a tak dále. My se budeme věnovat jen „vzhledovým“ metodám.
Každé view je v podstatě jenom obdélník. View
jako obdélník opravdu vypadá, ostatní třídy mohou vypadat lépe, ale to je zásluha šikovných tvůrců – kreslířů.
Jméno atributu | Hodnoty | Odpovídající funkce | Popis |
---|---|---|---|
android:alpha | Floatové číslo v rozmezí <0;1> . |
setAlpha , getAlpha |
0 znamená úplnou průhlednost, jednička znamená neprůhlednost. Zadáte-li v Javě desetinné číslo, bere se jakou double , které se nenechá implicitně přetypovat na float. Je proto potřeba hodnoty alphy zapisovat s příponou f (např. 0.7f ). |
android:background | Odkaz na jakoukoli drawable surovinu, color surovinu nebo hexadecimální zápis barvy ve formátu #rgb , #argb , #rrggbb , #aarrggbb , kde a je volitelná alpha. |
setBackgroundResource , setBackgroundColor a odpovídající gettery |
Použijete-li jako hodnotu barvu, doporučuji umístit ji do /res/values/colors.xml a jako id ji dát její název. Ohromně to usnadní zachovávání barevné konzistence napříč projektem, když chcete trochu změnit odstín červené, uděláte to jen jednou. Navíc jsou i hodnoty atributů popisnější, místo #80000080 tam bude @color/half_opaque_dark_red . |
android:id | Buď existující id ( @id/foo ), anebo nově vytvořené ( @+id/bar ). |
setId a odpovídající getter. |
Id nemusí být unikátní, je však vhodné, je-li unikátní alespoň v rámci podstromu, v němž budete vyhledávat metodou View.findViewById() či Activity.findViewById() . Doporučuji, aby se v každém layoutovém XML souboru vyskytlo každé id maximálně jednou. Pokud by se totiž uvnitř jednoho RelativeLayoutu (povíme si o kousek níže) sešlo více stejných id a shodou okolností by měl některý prvek pozici závislou na prvku s nejedinečným id, došlo by k problémům. Když není id unikátní, měl by se vrátit první nález. |
android:padding | Jakákoli délková jednotka | setPadding ,getPaddingLeft ,getPaddingTop ,getPaddingRight a getPaddingBottom |
Nastavuje vnitřní okraje daného view. To tedy zabere tak velký obdélník, jaký specifikujeme rozměrovými atributy android:layout_height resp. android:layout_width , ale případný obsah daného view (třeba text u EditTextu) bude „odsazený” o daný padding. V případě atributu android:padding je padding ze všech čtyř stran stejný, chcete-li nastavit různé hodnoty, použijte android:paddingLeft a analogicky i android:paddingTop atd. |
android:visibility | visible ,invisible ,gone |
setVisibility , getVisibility |
Atribut android:visibility funguje úplně stejně jako visibility v CSS. visible je analogické s visibility:visible , view je vidět. invisible je to stejné jako visibility:hidden , kdy view sice není vidět, ale zabírá místo, které by zabíralo, kdyby vidět bylo. gone je to samé jako display:none , view není vidět a ani nezabírá žádné místo. Hodí se ještě upozornit, že příslušné metody přijímají resp. vracejí číslo z množiny {0, 4, 8}, které odpovídá konstantám View.VISIBLE , View.INVISIBLE a View.GONE . Pozn.: trochu zmatečné je, že samotné hodnoty atributu android:visibility se při kompilaci také překládají na čísla, ale na 0, 1 a 2. To nás však trápit nemusí. |
Pokud není řečeno jinak, atributy, stejně tak jako později metody a vlastnosti, jsou v Androidu od API 4 nebo dříve. Atributy jsou seřazeny abecedně. Zde jsem vybral jen ty zajímavé či důležité, pro další vás odkážu na seznam všech atributů.
Metoda | Popis |
---|---|
View findViewById(int id) | Tuto metodu jsme si už představili a několikrát použili, dnes jsem o tom psal už u android:id . Nemá ji samozřejmě valný smysl volat na ne-potomcích ViewGroup (tehdy vrátí vždy null ), ale pro zjednodušení je definována na View |
View findViewWithTag(Object tag) | Funguje stejně jako findViewById , až na to, že místo id hledá podle tagu. Hledá pouze tagy bez klíče (viz setTag). |
Context getContext() | Vrátí objekt Context , v rámci nějž dané view existuje. Hodí se ve všech případech, kdy máte pouze view, ale potřebujete použít metodu, jež vyžaduje Context . |
View getRootView() | Vrátí kořenové view. V případě, že dané view žádného rodiče nemá, tedy je buď samo kořenovým view, anebo bylo například právě vytvořeno a ještě jsme ho nikam neumístili, vrátí samo sebe. |
Object setTag(int key, Object tag) | Vždy, když potřebujete k view nějakým způsobem „připíchnout” nějaká další data, použijte tuto metodu. Jen upozorňuji, že klíčem musí být nějaké id specifikované v resources (viz Resources – IDs). Uložený objekt potom získáte pomocí Object getTag(int key) . Metoda Object setTag(int key, Object tag) má i variantu bez klíče, Object setTag(Object tag) . Ta danému view nastaví „hlavní” tag, pomocí něhož a metody findViewWithTag lze potom to view i nalézt. Existuje i xml atribut android:tag , který je analogický k tagovým metodám bez klíče, ale v přehledu atributů jsem ho neuváděl, neboť jsem se zatím nedostal do situace, kdy by se hodil. Chcete-li v XML označit view, aby se s ním později v kódu dalo pracovat, použijte určitě radši id. |
Zde jsem uvedl jen pár metod. Pro seznam všech vás odkážu na dokumentaci.
V přehledu metod jsem nezmínil jednu rodinu velmi důležitých metod, a to ty, které nastavují posluchače událostí. Všechny mají signaturu typu setOnFooListener(View.OnFooListener)
, kde si za foo dosaďte například click nebo drag. Každá přebírá jako parametr objekt implementující dané rozhraní, které obsahuje jednu metodu. Ta metoda má jako parametr určitě View
, na němž daná událost proběhla, a v případech, kdy je to smysluplné, nějaká další data. Základní události definuje přímo View
, další události si mohou definovat jeho potomci. U View
si ukážeme, jak pracovat s nejjednodušší událostí, tedy tapnutím, ostatní důležité události jen zmíním.
Metoda setOnClickListener(View.OnClickListener l)
nastaví objektu listener pro klepnutí, tapnutí nebo jak to chcete nazývat. Rozhraní View.OnClickListener
má jednu metodu, a to onClick(View v)
, kde View v
je to view, na které uživatel klepnul.
Teď vám ještě nabídnu tabulku dalších důležitých událostí, potom si některé metody a atributy vyzkoušíme v praxi a tím budeme mít View
probrané.
Setter | Metody rozhraní | Popis |
---|---|---|
setOnClickListener( |
onClick(View v) |
Tato událost je zavolána při klepnutí na view. Parametr metody onClick je to view, na které bylo klepnuto. |
setOnDragListener( |
boolean onDrag(View v, DragEvent event) |
Tato metoda je součástí Drag and Drop API, které je v Androidu až od API 11. Mně drag and drop na Androidu přijde jako nepříliš příjemné, myslím si, že se vždy dá nahradit přirozenějším Action Barem. Drag and dropu se věnovat neplánuji, o Action Baru uvažuji. Vraťte true , pakliže jste danou událost zpracovali, jinak false . |
setOnKeyListener( |
boolean onKey(View v, int keyCode, KeyEvent event) |
Dokumentace tvrdí, že je to metoda hlavně pro hardwarové klávesnice, že u softwarových nelze s jistotou říci, zda tuto událost spustí, nicméně například u EditTextu to funguje bezpečně. keyCode obsahuje kód klávesy. Ten se dá získat i z objektu KeyEvent , který navíc obsahuje i informaci o tom, jestli byla klávesa stisknuta či uvolněna. Také jsou v něm definovány konstanty pro jednotlivé klávesy, takže i při práci s keyCode nemusíte do kódu zanášet nicneříkající čísla. onKey musí vrátit boolean, zda danou událost „zkonzumovala”, či nikoli. Za zmínku ještě stojí, že při implementaci Activity můžete vytvořit metody onKeyDown , onKeyUp atp., které fungují velmi podobně jako OnKeyListener . Díky nim můžete navíc implementovat například vlastní posluchač stisknutí tlačítka zpět (například hra se při stisknutí tlačítka zpět pozastaví a uživateli nabídne nějaké menu). Nezneužívejte to však, tlačítko home takto stejně přepsat nejde; akorát naštvete uživatele. |
setOnLongClickListener( |
boolean onLongClick(View v) |
Totéž jako onClickListener, akorát se volá tehdy, když uživatel dané view chvíli podrží. Vraťte true , pakliže jste danou událost zpracovali, jinak false . |
A co nějaký kód?
Do /res/values/colors.xml
jsme přidali následující řádky (poté, co jsme klikli pravým tlačítkem na složku values
a potom vybrali New → Other... → Android → Android XML Values File
):
<color name="green">#0f0</color> <color name="blue">#00f</color>
/res/layout/view.xml
potom vypadá stejně, jako následující řádky. Se znalostmi z tohoto a předchozích dílů byste jim měli bez problému porozumět, a tak je záměrně nechám bez komentáře.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <View android:id="@+id/red_view" android:tag="first_view" android:background="#f00" android:layout_width="match_parent" android:layout_height="50dp" android:onClick="hideView" /> <View android:background="@color/green" android:layout_width="match_parent" android:layout_height="50dp" android:paddingLeft="15dp" android:paddingBottom="30dp" /> <View android:id="@+id/blue_view" android:background="@color/blue" android:layout_width="match_parent" android:layout_height="50dp" /> </LinearLayout>
Ani ViewActivity.java
není s dnes načerpanými znalostmi nijak složitá na pochopení, nicméně nějaké komentáře jsem pro jistotu přidal.
public class ViewActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.view); View v = new View(this); // Vytvoření View v kódu View red = findViewById(R.id.red_view); View blue = findViewById(R.id.blue_view); blue.setOnClickListener(new OnClickListener() { public void onClick(View v) { // Nepříjímá argument double, tak pomocí přípony f řekneme, že // číslo je float v.setAlpha(0.5f); } }); blue.setTag(red); // Nastavení nějakého objektu (zde View) jako tagu View root = blue.getRootView(); Toast.makeText(this, String.valueOf(blue == root.findViewWithTag(red)), Toast.LENGTH_SHORT).show(); // true Toast.makeText(this, String.valueOf(red == root.findViewWithTag("first_view")), Toast.LENGTH_SHORT).show(); // true } public void hideView(View v) { v.setVisibility(View.GONE); } }
TextView
TextView
, přímý potomek View
, slouží k zobrazování textu. Samo o sobě umí „jen” zobrazit text, ale mezi jeho potomky patří mnoho dalších důležitých view, jako například EditText
či Button
. U TextView
ukážu jen opravdu základní metody a atributy, nebudu se věnovat ani těm, které z něj mohou udělat EditText
, ani těm, které jsou sice zajímavé, ale ne kriticky důležité (např. android:ellipsize
či android:ems
), abych vás zbytečně nezahltil. V případě potřeby je určitě najdete v dokumentaci. Některé atributy a metody TextView
uvedu až u EditTextu
, přestože tam ve skutečnosti nepatří, ale rámcově se tam hodí víc a budete je používat téměř pouze právě s ním.
Jméno atributu | Hodnoty | Odpovídající funkce | Popis |
---|---|---|---|
android:autoLink | none ,web ,email ,phone ,map ,all ,či kombinace oddělené svislítkem (|) |
setAutoLinkMask(int mask) |
Stejně jako u visibility jsou jednotlivé konstanty překládány na čísla (ale tentokrát mají konstanty pro metodu stejné hodnoty jako konstanty pro atribut, viz odkázaná dokumentace). Svislítko je bitová operace nebo a hodnota all je vlastně zkratka pro web|email|phone|map . Map by mělo zvýrazňovat adresy a nabídnout odkaz na nějakou mapu, nikdy jsem to nepoužil a nejsem si jist, jak to funguje v českém prostředí. Ostatní tři hodnoty jsou ale velmi šikovné. Každý, koho napadla otázka „A jak to funguje pro EditText?” je správně zvídavý. Díky zkoušení různých neobvyklých kombinací se člověk často dostane k věcem, které mu potom budou každou chvíli usnadňovat život. A i kdyby ne, procvičí se v programování. |
android:gravity | left ,right ,center_horizontal a mnoho dalších. Možno kombinovat svislítkem. |
setGravity(int mask) |
Podobné, jako CSS text-align (nastaví zarovnání textu doleva, na střed či doprava), nicméně android:gravity má mnohem více množných hodnot. Zde jsem uvedl jen ty základní, které podlě mě použijete v naprosté většině případů. Jen upozorním, že použijete-li například center_horizontal , centrujete text v rámci TextView , takže jestli nastavíte šířku na wrap_content , žádnou změnu gravitace nezpozorujete. |
android:lines | Číslo či odkaz na číslo v resources | setLines |
Abyste nemuseli složitě počítat přesnou výšku TextView tak, aby za dané velikosti textu (a danými vzdálenostmi mezi řádky, které se mimochodem dají také nastavit) odpovídala n řádkům, můžete použít atribut android:lines , jehož hodnota je přesná výška v řádcích. Asi vás nepřekvapí, že existuje i android:maxLines a android:minLines . Abychom předešli špatně odhalitelným problémům s kombinací android:lines a android:layout_height , řekneme si rovnou, že lines nastavují velikost TextView, zatímco layout_height nastavuje velikost obdélníku, do kterého se TextView vykreslí. Pokud layout_height nastavíte na wrap_content , není problém. Pokud ho ale nastavíte na nějakou fixní hodnotu (včetně match_parent ), jakmile výška v řádcích přesáhne layout_height , TextView se ořízne. |
android:text | Řetězec (fůůj) anebo identifikátor řetězcové suroviny | setText (má mnoho různých signatur) |
Tady není moc co říkat, atribut android:text prostě nastaví obsah TextView. |
android:textAppearance | Odkaz na style resource anebo theme atribut | Tohle je trochu složitější a plně si to vysvětlíme ve článku o stylování. Kvůli komplikovanosti jsem i vynechal analogickou metodu. Prozatím budeme používat pouze theme atributy, což jsou také jakési identifikátory, akorát místo zavináčem začínají otazníkem a odkazují na skupinu vzhledových vlastností nastavenou v aktivním motivu (theme). Při použití analogie s webovým vývojem se dá říci, že motiv je něco jako CSS stylopis a theme atribut je něco jako třída. Samotný Android framework nabízí několik motivů, díky nimž můžete jedním řádkem nastavit, jak bude aplikace vypadat, zda bude mít bílý text na černém pozadí, černý text na bílém pozadí atp. A tyto motivy definují i theme atributy, tedy jakési třídy vlastností, které spolu nějak souvisí. Pro zjednodušení si teď ukážeme jen tři, a to ?android:attr/textAppearanceSmall , ?android:attr/textAppearanceMedium a ?android:attr/textAppearanceLarge . Upřímně řečeno, zatím jsem snad nikdy ani nepotřeboval nic jiného. |
|
android:textColor | To samé co do android:background atributu |
setTextColor |
Nastavení barvy textu. |

První TextView ukazuje možnosti autoLink
, druhý má velký text a je zarovnán doleva, třetí má prostřední text a zarovnán na střed a čtvrtý má malý text a je zarovnán vpravo.
Signatura | Popis |
---|---|
int getLineCount() | Vrátí počet řádků, které zabírá text v daném TextView. Musí se ale zavolat až poté, co to TextView získá layout – hodně zjednodušeně poté, co je vykresleno. Zavoláte-li tuto metodu třeba v onCreate , s nejvyšší pravděpodobností vrátí vždycky 0 , protože view ještě úplně vykreslena nebyla. |
CharSequence getText() | Vrátí text. Na String ho převedete zavoláním metody toString() . |
int length() | Vrátí délku textu ve znacích. |
void setError(CharSequence popupText) | Vpravo vedle TextView se zobrazí obrázek naznačující chybu. Pozor na to, že text předaný této metodě se nenastaví jako text, ale měl by se zobrazit tehdy, když TextView obdrží focus. Vzhledem k tomu, že s tím to je poměrně komplikované a je rozdíl, jestli má telefon hardwarové ovládání, anebo ne, nedoporučuju se na tenhle text spoléhat. Pokud jako parametr předáte null , ikonka zmizí. |

Takhle nějak se na Androidu ICS zobrazí TextView po zavolánísetError
.
Pro mnoho dalších atributů a metod TextView
se podívejte do jeho dokumentace. Jen pozor na to, abyste kvůli tomu všemu nezapomněli, že existují speciální třídy, mnohem vhodnější pro některé úkony, jako například EditText
, Button
, CheckBox
nebo RadioButton
. My si z nich povíme něco jen o EditText
u, Button
nemá oproti TextView
nic navíc, takže s ním vlastě už umíme, a ty ostatní dvě jsou také už velmi jednoduchá, takže si je, až je budete potřebovat, můžete nastudovat bez problému sami. Pěkně jsou různá formulářová view rozebrána v Input Controls.
Programujeme
Všimněte si, že jsem u <TextView>
s id large_text
nastavil nejen atribut android:onClick
(abych mohl ukázat, že metoda getLines
vrací správné výsledky), ale musel jsem mu nastavit i android:clickable
, aby se na něj dalo tapnout. View
má ve výchozím stavu clickable="true"
, ale u TextView
tomu tak není.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:autoLink="all" android:text="@string/auto_link" /> <TextView android:id="@+id/large_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="true" android:gravity="left" android:onClick="compareLineCount" android:text="@string/seo_text" android:textAppearance="?android:attr/textAppearanceLarge" /> <TextView android:id="@+id/medium_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="@string/seo_text" android:textAppearance="?android:attr/textAppearanceMedium" /> <TextView android:id="@+id/small_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="right" android:text="@string/seo_text" android:textAppearance="?android:attr/textAppearanceSmall" /> <TextView android:id="@+id/error" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/error" /> </LinearLayout>
K TextViewActivity.java
nic dodávat nemusím.
public class TextViewActivity extends Activity { TextView large; TextView medium; TextView small; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.text_view); ((TextView) findViewById(R.id.error)).setError("Někde se stala chyba."); large = (TextView) findViewById(R.id.large_text); medium = (TextView) findViewById(R.id.medium_text); small = (TextView) findViewById(R.id.small_text); Toast.makeText( // true, všechny tři mají stejný text this, String.valueOf(large.length() == medium.length() && large.length() == small.length()), Toast.LENGTH_SHORT).show(); } public void compareLineCount(View v){ Toast.makeText( // skoro určitě false, ale na širokých displejích možná i true this, String.valueOf(large.getLineCount() == small.getLineCount()), Toast.LENGTH_SHORT).show(); } }
EditText
EditText
je asi nejčastěji používaným formulářovým view na Androidu. Jako u všech ostatních view si i u něj představíme některé atributy a metody, nicméně v tomto případě jsou všechny bez výjimky ve skutečnosti definované už na TextView
, ale používat je budeme na EditTextech, a tak mi přijde logičtější zařadit je sem. Ještě než začnu, upozorním na jednu zajímavou podtřídu EditText
u, a to AutoCompleteTextView
, což je EditText s funkcí autocomplete.
Jméno atributu | Hodnoty | Odpovídající funkce | Popis |
---|---|---|---|
android:capitalize | none ,sentences ,words ,characters |
Určuje, která písmena (v závislosti na postavení v textu) se mají automaticky převádět na velká. Výchozí je none , které nepřevádí níc. sentences zvětšuje první písmena vět, words první písmeno každého slovo a characters zvětší každý znak. Já osobně nedoporučuji používat nic kromě characters (pokud máte důvod, že chcete mít celý text velkými písmeny), neboť jednak klávesnice automatické opravy a zvětšování písmen mívají (a uživatel je může vypnout) a jednak nemůže být algoritmus přesný, takže občas uživatele strašně otráví (velké písmeno po každé tečce, nemožnost napsat John von Neumann apod.).) |
|
android:hint | Řetězcová surovina nebo řetězec | setHint |
Nastaví řetězec, který se na daném EditTextu bude zobrazovat tehdy, když v něm není nic napsaného. Obdoba placeholderu z HTML5, až na to, že narozdíl od některých (všech?) implementací HTML5, v Androidu zůstane i poté, co EditText získá focus, ale nic v něm ještě není napsáno (což je určitě uživatelsky příjemnější chování). Nastavením hint u nikdy nic nezkazíte. |
android:inputType | none ,text ,textEmailAddress ,textPassword ,number ,phone a mnoho dalších.Možno kombinovat svislítkem (|). |
setRawInputType(int type) |
Tohle je ohromně důležitý atribut. Nejenže validuje zadaná data, ale navíc se mu umí přizpůsobit softwarové klávesnice. Pokud například nastavíte textEmailAddress , mohou místo například čárky zobrazit zavináč. Pokud nastavíte number , klávesnice zobrazí číselník. Pokud je typem vstupu textPassword či numericPassword , místo znaků se budou zobrazovat hvězdičky. Atribut android:inputType se objevil až v API 3, předtím měla TextView mnoho různých pravdivostních atributů typu android:numeric , android:password atp. Ty jsou teď deprecated. |
android:enabled | true ,false |
setEnabled |
Tento atribut specifikuje, zda jsou povoleny interakce s view, v případě EditTextu určuje, jestli se do něj dá psát. Asi jste si všimli, že atribut android:enabled (mimochodem definovaný pro všechny potomky TextView ) není odkazem. Je to proto, že se o něm API reference vůbec nezmiňuje. Když ho použijete v Eclipse, tvrdí vám, že je deprecated a že máte použít state_enabled, který neexistuje. Proč se o něm API reference nezmiňuje, to nevím, ale chyba v Eclipse je dána chybou v androidích zdrojácích. Podíváte-li se na {vaše složka s ADK}/platforms/android-15/data/res/values/attrs.xml najdete tam řádek, který je potomkem definice atributů pro TextView , který zmiňuje android:enabled , ale tvrdí, že je deprecated ve prospěch neexistujícího atributu. Myslím si, že tato chyba bude opravena a že atribut enabled bude vzat na milost. Do té doby se buď smiřte s tím, že používáte něco, co formálně neexistuje, anebo použijte příslušnou metodu. |
Metody žádné zmiňovat nebudu, takže si můžeme ukázat nějaký kód.
Ukázka kódu
Tentokrát jen layoutový XML soubor, Activity spočívá v tom, že nastaví správně contentView
. Popisky a text jsem ošklivě napral přímo do příslušných atributů, neboť vysvětlují, co který EditText umí.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:enabled="false" android:text="Zakázaný vstup" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Sem vepište jakýkoliv text" android:inputType="text" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Kterékoli reálné číslo" android:inputType="numberSigned|numberDecimal" /> <!-- Samozřejmě jako desetinný rozvoj. --> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Textové heslo" android:inputType="textPassword" /> </LinearLayout>
ImageView
ImageView
, jak název napovídá, dokáže zobrazit obrázek. Protože není tak důležité, pouze se zmíním, že existuje, ukážu úplný základ a zájemce odkážu na Working With Images In Android, což je článek, který opravdu polopaticky vysvětluje práci s ImageView
o něco více do hloubky. Obrázky se však na telefonech zase tak moc nepoužívají (a tam, kde ano, obvykle nabízí Android jednodušší řešení) a pro většinu výjimek vám bude stačit to, co teď ukážu.
Dá se říci, že na displejích mdpi
velmi zhruba jeden reálný pixel odpovídá (tzn. s odchylkou do asi 20 %) jednomu dp
. Z toho můžete vycházet v tom, jak veliký obrázek pro mdpi
displej vyrobíte. Potom ho musíte ještě samozřejmě velikostně předělat pro ostatní hustoty, viz kapitola Jednotky v minulém článku. Když máte v /res/drawable-ldpi
, /res/drawable-mdpi
, /res/drawable-hdpi
a /res/drawable-xhdpi
stejně pojmenované obrázky lišící se pouze velikostí, je potom už jednoduché ImageView použít:
<ImageView android:src="@drawable/image" android:layout_width="wrap_content" android:layout_height="wrap_content" />
ProgressBar
ProgressBar
je nástroj, kterým dáme uživateli vědět, že se něco děje, přestože to nevidí. Je to taková obdoba technologické přestávky na silnicích. Atributy tentokráte neseřadím podle abecedy, ale přirozeněji, od jednodušších ke složitějším (respektive od základních ke specifičtějším).
Jméno atributu | Hodnoty | Odpovídající funkce | Popis |
---|---|---|---|
android:indeterminate | pravdivostní hodnota | setIndeterminate |
Nastavuje, zda je progressbar konečný, či nekonečný. Jak později zjistíme, až budeme kódovat, tento atribut má smysl pouze u (vestavěného) horizontálního ProgressBar, kolečko se jako nekonečné chová vždy. Takže pro úplně nejjednodušší případ stačí nakódit element <ProgressBar> , nastavit mu layout_width , layout_height a tím máme vystaráno. |
android:progress | Přirozené číslo nebo nula (ne vyšší než maximální nastavená hodnota, viz o dva řádky tabulky níže). | setProgress |
Počáteční pokrok. Není-li nastaven, má hodnotu 0. Má smysl jen tehdy, umí-li ProgressBar nějaký pokrok zobrazit, tedy u android:indeterminate="false" na horizontálním ProgressBaru. |
style | Odkaz na style resource | style je úplně zvláštní atribut, mimojiné tím, že se před něj nepíše namespace android . Pořádně si o něm povíme, až budeme mluvit o stylování, proteď nám stačí jen si říct, jakých hodnot může v tomto případě nabývat. @android:style/Widget.ProgressBar je výchozí vzhled ProgressBaru, ostatní ( @android:style/Widget.ProgressBar ,@android:style/Widget.ProgressBar.Horizontal ,@android:style/Widget.ProgressBar.Small ,@android:style/Widget.ProgressBar.Large ) mluví za sebe. Jednu věc si ale už zmínit neodpustím, a to je to android: bezprostředně za zavináčem. Ve skutečnosti mají i zdroje namespace, a to je právě ta část hned za zavináčem, od zbytku oddělená dvojtečkou. Pokud ho neuvedete, automaticky se berou suroviny té které aplikace. Ale často budete používat právě namespace android , který združuje všechny vestavěné suroviny. Budete ho používat právě při stylování (budete dědit od vestavěných stylů). Aby správně fungovaly některé věci, budete muset svému view nastavit id specifikované už v Android frameworku. A tak dále. |
|
android:max | Jakékoli přirozené číslo | setMax |
Potřebujete konečný progressbar? A nevyhovuje vám rozsah 0– max ? Tímto atributem si můžete nastavit vlastní maximální hodnotu. Například když zobrazujete postup stahování souboru, jako max můžete nastavit jeho velikost. |
Vedle výše jmenovaných nás zajímá už jen jedna metoda, a to incrementProgressBy(int diff)
, která místo nastavení nové hodnoty progressu jeho hodnotu zvýší o diff
.
Kdyby někdo chtěl vyzkoušet zvyšovat hodnotu progressu postupně, předpokládám, že by začal tak, že by do onCreate
přidal nějaké takové řádky:
ProgressBar pb = (ProgressBar)findViewById(R.id.determinate_progressbar); for(int i = 0;i<=100;i++){ pb.setProgress(i); try { Thread.sleep(100); } catch (InterruptedException e) { } }
Tehdy by zjistil, že se mu jeho activity spouští dlouho, a když se spustí, je progressbar už plný. Tak by to vylepšil a zkusil by to odložit a spustit až po klepnutí na nějaké tlačítko s android:onClick="startPretendingWork"
:
public void startPretendingWork(View v){ final ProgressBar pb = (ProgressBar)findViewById(R.id.determinate_progressbar); for(int i = 0;i<=100;i++){ pb.setProgress(i); // Jako pb.incrementProgressBy(1), je-li předtím progress 0 try { Thread.sleep(100); } catch (InterruptedException e) { } } }
Po kliknutí na tlačítko by se activity zasekla, a tak by zkusil spustit nové vlákno a uspávat to:
public void startPretendingWork(View v) { final ProgressBar pb = (ProgressBar)findViewById(R.id.determinate_progressbar); new Thread(new Runnable() { public void run() { for (int i = 0; i <= 100; i++) { pb.setProgress(i); try { Thread.sleep(100); } catch (InterruptedException e) { } } } }).start(); }
A to by fungovalo, on by si to zapamatoval a příště, když by chtěl třeba zobrazit nějaký text získaný z webu, by se divil, proč to nefunguje, a hledal by chyby všude možně, jen ne tam, kde chyba opravdu je.
V Androidu totiž existují dva typy vláken: Takzvané UI vlákno a pak vlánka ostatní. V UI vlákně běží celé uživatelské rozhraní, spouštějí se tam activity a tak dále. A má dvě pravidla:
- Nikdy neblokuj UI vlákno.
- Nikdy nepřistupuj k prvkům uživatelského rozhraní odjinud, než z UI vlákna.
Je tomu tak proto, že androidí UI není thread-safe. Některé metody třídy ProgressBar
jsou výjimkou, o čemž napovídá to, že jsou deklarovány jako synchronized
. Pokud byste ale stejným způsobem třeba měnili text nějakého TextView
, obdrželi byste android.view.ViewRoot$CalledFromWrongThreadException
. Jak pracovat ve vláknech si určitě někdy povíme, pokud to potřebujete hned, projděte si Processes and Threads.
Jak se tedy takový progressbar tvoří?
Opět vynecháme activity, která sestává jen z nastavení správného contentView, a podíváme se jen na layoutový XML soubor. Ten není totožný s tím, který bude v ukázkových zdrojácích a ze kterého pochází screenshot – zde jsem pro stručnost nahradil všechna TextView komentářem:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <!-- Nejjednodušší případ --> <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" /> <!-- Výchozí, nekonečný --> <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:indeterminate="true" /> <!-- Horizontální nekonečný --> <ProgressBar style="@android:style/Widget.ProgressBar.Horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:indeterminate="true" /> <!-- Malý, nekonečný --> <ProgressBar style="@android:style/Widget.ProgressBar.Small" android:layout_width="wrap_content" android:layout_height="wrap_content" android:indeterminate="true" /> <!-- Velký, nekonečný --> <ProgressBar style="@android:style/Widget.ProgressBar.Large" android:layout_width="wrap_content" android:layout_height="wrap_content" android:indeterminate="true" /> <!-- Výchozí, konečný --> <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:indeterminate="false" android:progress="45" /> <!-- Horizontální, konečný --> <ProgressBar android:id="@+id/determinate_progressbar" style="@android:style/Widget.ProgressBar.Horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:indeterminate="false" android:progress="79" /> </LinearLayout>
Text opět nesprávně předávám hodnotou, ale i v tomto případě plní text popisku dokumentační funkci. Na následujícím obrázku si jistě všimnete, že nejjednodušší, výchozí-nekonečný a výchozí-konečný vypadají stejně.
Tím jsme sice zdaleka neskončili, ale máme za sebou všechny potomky View
a zároveň ne-potomky ViewGroup
, které si dnes ukážeme. View
má samozřejmě mnohem více potomků, stačí se podívat do dokumentace, kde jsou vypsáni všichni přímí i nepřímí potomci zobrazit.
A protože jsme probrali všechny ne-potomky ViewGroup
, myslím, že můžeme říci, že jsme dokončili kapitolu. Článek pokračuje ve Vyvíjíme pro Android: Bližší pohled na pohledy – 2. díl.
Dobrý den,
děkuji za sepsání tutoriálů ohledně programování pro Androida. Bohužel, když jsem já programoval, java ani nebyla. Proto bude možná následovat hloupá otázka.
Zasekl jsem se u článku „Vyvíjíme pro Android: Bližší pohled na pohledy – 1.díl.“
Ve View.Activity.java (obsah překopírován ctrl ins / shift ins) mám chybovou hlášku na řádku 13 u funkce/metody/procedury či jak se to dnes budeme nazývat. Přikládám prtscreen. Jsem naprostý začátečník a tutoriál čtu slovo po slovu. Nerad bych pokračoval bez vyřešení. Téma je staré tři měsíce, přesto pokud by někdo věděl…
http://s9.postimage.org/kklf5of2n/chyba.png
Děkuji
Kuba
U Vás je problém s tím, že jste importoval špatné rozhraní – místo
View.OnClickListener
používáteDialogInterface.OnClickListener
.Děkuji mnohokrát. Samozřejmě jsem zapátral a chybu si opravil ihned poté, co jsem zmáčknul na odeslat(klasika, bez registrace nelze mazat příspěvek). Každopádně jsem si koupil knihu základů a jdu krůček po krůčku. Tím nechci říct, že Vaše články jsou špatné. Naopak, ale vy toho bohužel umíte evidentně tolik, že neptřebujete zmínit věci samozřejmé. Samozřejmé -> pro začátečníka zásadní.
Až nastuduji, vrátím se!
Kuba
Dobrý den,
vytvořil jsem celou aplikaci dle vašich poznámek, ale když jí chci vložit do emulátoru, či mého mobilního zařízení, vždy aplikace spadne.. Všechny chyby, které mi to hlásilo při startování aplikace jsem odstranil, ale stále se nenačte a spadne.. Nevíte kde bych mohl mít chybu.
Děkuji za radu.
Dobrý den,
omlouvám se, ale z daných informací nedokážu ani odhadnout, co je za problém. Mohl byste, prosím, zkusit nějak nahrát alespoň text výjimky, jíž to vyhodí, když program spadne? Nebo to už žádnou chybu nehlásí?
Matěj
Dobrý den,
mám otázku k vytovořenému View v = new View(this); programově. Toto view se námá zobrazit?
Jedná se jen o view vytvořené v paměti? Pokud bych jej chtěl zobrazit je možné jej vložit porgramově do layotu?
A potom ještě jeden dotaz: public void hideView(View v) tato procedura se nidky nezavola. Tedy aspon v prikladu nikde volana neni.
Predem dekuji za odpovedi.
Dobrý den,
druhý dotaz z předchzího komentáře beru zpět, procedura je volána. Jen jsem byl nepozorný. Omlouvám se.
Zdravím, v textu s přehledem základních vlastností View je uvedeno, že vše je pro level API 4, pokud není řečeno jinak. Ovšem metoda setAlpha je až od API 11. Eclipse mi začal kvůli tomu řvát a co jsem kouknul do dokumentace, tak je tomu skutečně tak.
Eclipse mi nabídl jako řešení přidat nějaké anotace, vybral jsem @TargetApi(Build.VERSION_CODES.HONEYCOMB)
před onClick metodu.
Seriál je už tedy trochu starší, ale kdyby to autor četl, mohl by prosím připsat k tomuto problému nějaký komentář přímo do článku? Případně tam dopsat, že setAlpha je až od API 11?
Taky jsem měl podobný problém. Aby odstranit tuto chybu, v AndroidManifest.xml musíme nastavit android:minSdkVersion=“11″. Ted‘ tam máte pravděpodobně 4.