Vyvíjíme pro Android: Stylování a design

Android logo

Dnes se naučíme, jak změnit vzhled jednotlivých view anebo celé aplikace pomocí stylů a motivů. Krátce se také zmíníme o Design Guidelines.

Seriál: Vyvíjíme pro Android (14 dílů)

  1. Vyvíjíme pro Android: Začínáme 15.6.2012
  2. Vyvíjíme pro Android: První krůčky 22.6.2012
  3. Vyvíjíme pro Android: Suroviny, Intenty a jednotky 29.6.2012
  4. Vyvíjíme pro Android: Bližší pohled na pohledy – 1. díl 13.7.2012
  5. Vyvíjíme pro Android: Bližší pohled na pohledy – 2. díl 13.7.2012
  6. Vyvíjíme pro Android: Fragmenty a SQLite databáze 20.7.2012
  7. Vyvíjíme pro Android: Preference, menu a vlastní Adapter 27.7.2012
  8. Vyvíjíme pro Android: Intenty, intent filtry a permissions 3.8.2012
  9. Vyvíjíme pro Android: Content providery 10.8.2012
  10. Vyvíjíme pro Android: Dialogy a activity 17.8.2012
  11. Vyvíjíme pro Android: Stylování a design 24.8.2012
  12. Vyvíjíme pro Android: Notifikace, broadcast receivery a Internet 31.8.2012
  13. Vyvíjíme pro Android: Nahraváme aplikaci na Google Play Store 7.9.2012
  14. Vyvíjíme pro Android: Epilog 14.9.2012

Před týdnem jsme se naučili pracovat s dialogy a také konečně umíme pracovat s životním cyklem activit a fragmentů. Dnes vám nejprve velmi stručně představím některé androidí designové zásady a potom si ukážeme, jak technicky nastylovat aplikaci.

Design Guidelines

Každá mobilní platforma má nějaké designové zásady (design guidelines). Je to příručka pro vývojáře a designery, aby vytvářeli aplikace, které vizuálně zapadnou do platformy.

Já bohužel nejsem obdařen nějakým zvláště vyvinutým estetickým cítěním a necítím se být ten nejlepší člověk na obsáhlé povídání o tom, jak má co vypadat a jak se to má chovat (možná je mezi čtenáři někdo kompetentnější? Článek o tom, jak se zásady uplatňují v praxi, bych si přečetl moc rád), takže se omezím na několik krátkých zásad, kterými se řídím sám, a odkazy.

Když jsme ještě u těch design guidelines, ty androidí jsou dostupné na adrese http://developer.android.com/design a jsou v porovnání se zásadami pro iOS nebo Windows Phone zdaleka nejlépe zpracované po vizuální stránce (je potěšení je číst) a myslím, že jsou nejlepší i obsahově.

Mé zásady

Guidelines se také dost detailně zmiňují o velikosti dotykových komponent. Já po zimě strávené s Androidem došel k následující poučce, kterou bych také uvedl, kdyby se mě někdo zeptal, jak bych všechny zásady shrnul do jedné věty:

Udělej aplikaci tak, aby se dala ovládat nosem.

Představte si, že je zima, máte rukavice a sněží vám na telefon. Dokážete potřebnou akci provést nosem a dostatečně rychle, bez přemýšlení nad tím, kam klepnout, abyste vy ani telefon nezmrzli? Pak je aplikace dostatečně v pořádku.

Moc hezkou přednášku nazvanou Advanced Design for Engineers měli na letošním Google I/O Alex Faaborg a Christian Robertson. Oba jsou mimo jiné spoluautoři Android Design Guidelines a v odkazované přednášce se snaží technicky zaměřeným lidem jako já ukázat, jak je design důležitý a jak ho dělat (jednoduše).

Další videa o designu pro Android z I/O 2012 jsou také v Guidelines v sekci Videos.

Samozřejmě berte Guidelines i mé rady s rezervou. Nejsou to pravidla, ale jen rady. Například hry rozhodně nerespektují celistvost platformy – a nikomu to nevadí. Pokud programujete klávesnici, asi se bude těžko ovládat nosem. Většinou však ony rady fungují dobře.

Jak řekl Christian Robertson: „Neznovuvynalézejte seznam, pokud si nejste stoprocentně jisti, že potřebujete znovuvynalézt seznam.” (Hodně volně přeloženo.)

Na závěr bych si dovolil odkázat na must-read článek, ať už jste designer androidí aplikace, anebo její programátor. Sebastiaan de With ve článku Awakenings: An Android Design Process píše o tom, jak navrhoval design aplikace DoubleTwist Alarm Clock, a zmiňuje se o všech problémech, na něž narazili. A myslím si, že článek dobře ilustruje, že pokud se rozhodnete porušit některá pravidla, je potřeba hodně úsilí, aby to dopadlo dobře.

Styly a motivy

Znáte takový ten pocit, kdy máte čtyři TextView pod sebou, každé z nich má nastavených plno atributů, vesměs stejných, a pro vás je to až bytostně nepříjemná redundance?

<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="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/background_dark"
        android:fontFamily="monospace"
        android:gravity="center_horizontal"
        android:text="@string/hello_world"
        android:color="@android:color/primary_text_light" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/background_dark"
        android:fontFamily="monospace"
        android:gravity="center_horizontal"
        android:text="@string/my_name"
        android:color="@android:color/primary_text_light" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/background_dark"
        android:fontFamily="monospace"
        android:gravity="center_horizontal"
        android:text="@string/astar"
        android:color="@android:color/primary_text_light" />

</LinearLayout>

Naše TextView se liší pouze obsahem, přesto má každé nastaveno plno stejných atributů. Díky stylům může náš layout vypadat i takto:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <!-- atribut style je opravdu bez namespace android. -->
    <TextView
        style="@style/MyText"
        android:text="@string/hello_world" />

    <TextView
        style="@style/MyText"
        android:text="@string/my_name" />

    <TextView
        style="@style/MyText"
        android:text="@string/astar" />

</LinearLayout>

Pomocí stylů můžeme vytvářet znovupoužitelné sady atributů a také oddělit formu od struktury.

Pokud jsem vás už dostatečně navnadil, můžeme pomalu přejít k pořádnému vysvětlení. Ale než se tak stane, chtěl bych podotknout, že Styly a motivy jsou v oficiální dokumentaci doslova odfláklé, a tak vám kromě dnešního článku nezbude nic jiného než prohledat internet, někdy dobře poradí StactOverflow, a někdy se dokonce musíte podívat na zdrojáky (složka  {složka adk}/platforms/android-{verze}/data/res).

V tomto článku se budu snažit postupovat od nejjednodušších věcí, které by měl určitě znát každý, k těm složitějším, které asi potřebovat nebudete, ale mně pomohly se s celou problematikou smířit.

Dnes také nebudeme vytvářet žádnou ukázkovou aplikaci, všechny potřebné zdrojáky ukážu, a protože stylování je statická věc, budou stačit screenshoty.

Kam ten styl zapsat?

V díle o surovinách jsme zmínili složku values, a dokonce jsme řekli, že v ní mohou být styly. Je konvencí, že se pro styly používá soubor styles.xml, ale pokud chcete, můžete je dát klidně i do strings.xml, fungovat to bude. Kořenovým elementem XML souboru ve složve values je vždy <resources>. Samotný styl (může jich samozřejmě být více) je reprezentován elementem <style>, který má atribut name, jež specifikuje jméno stylu. Je konvencí, že jméno stylu je psáno pomocí PascalCase. A máme-li styl se jménem MyText, můžeme k němu přistupovat pomocí identifikátoru R.style.MyText resp.  @style/MyText.

Potomky elementu <style> jsou elementy <item>, jejichž jediným atributem je opět name, to však tentokrát obsahuje název nějakého atributu, jehož hodnota je pak obsahem  <item>-u.

Pokud se vrátíme k naší ukázce se styly, musíme, aby fungovala, vytvořit soubor /res/values/styles.xml (ve skutečnosti je, pokud používáte nejnovější ADT plugin, vytvořený, jeho obsah probereme později) a do něj vložit (kořenový element <resources> už ve vytvořeném souboru je, pokud jste soubor vytvářeli ručně, musíte přidat ještě ten) následující kód:

<style name="MyText">
    <item name="android:layout_width">match_parent</item>
    <item name="android:layout_height">wrap_content</item>
    <item name="android:gravity">center_horizontal</item>
    <item name="android:color">@android:color/primary_text_light</item>
    <item name="android:fontFamily">monospace</item>
    <item name="android:background">@android:color/background_dark</item>
</style>

Layout vypadá stejně i s použitím stylu.

  

V podstatě vám už tohle může docela stačit.

Barevné suroviny

Stejně jako všechny řetězce by měly být v surovinách, měly by tam být i všechny barvy. Pro ně je soubor /res/values/colors.xml, který je téměř stejný jako strings.xml, až na to, že používáme elementy <color>, jejichž hodnotou může být hexadecimální zápis barvy ve formátu #rgb, #argb, #rrggbb či #aarrggbb. Barvy, které používá přímo Android, můžete najít v android.R.color  a díky nim můžete vaši aplikaci ještě více sjednotit se systémem. Na to jsou ale mnohem lepší tzv. style attributes, o nichž se zmíním později.

Na barvu odkazuje R.color.name resp. @color/name.

Rozměrové suroviny

S barevnými surovinami jsme dokonce i pracovali, ale rozměrové suroviny (dimension resources) pro vás mohou být novinkou, ačkoli je to opět jen omílání řetězců, barev a dalších. Soubor se tentokrát podle konvence nazývá dimens.xml, elementem je <dimen>, jeho hodnotou může být nějaké číslo s jednotkou ( 16dp, 22sp, 156px, …).

Přistoupíte k nim pomocí R.dimen.name resp. @dimen/name.

U barev má smysl použít surovinu vždy. Jednak to plní dokumentační funkci, jednak to umožňuje lépe udržet konzistenci barev v rámci projektu (podíváte se, které barvy už existují, a teprve, pokud vám žádná nevyhovuje, začněte vymýšlet novou) a v neposlední řadě stačí změnit barvu na jednom místě a změní se všechny její použití.

U rozměrů je to trochu složitější. Někdy to rozhodně smysl má (aplikace vypadá lépe, když její prvky používají stejný padding, a ne pixel sem, pixel tam), ale někdy je to asi zbytečná práce. Záleží na vás a také samozřejmě na velikosti projektu.

Motivy

Motivy (themes) jsou vlastně jen jiným využitím stylů. Takže nebojte, nebudete se muset učit ještě další elementy. Zatímco styl je aplikován na jedno View (i kdyby to View bylo GroupView a mělo potomky, jich se už ten styl absolutně netýká), motiv je aplikován na všechna View v rámci nějaké Activity nebo celé aplikace.

„A jak to dělaji, že vytvořím styl dohromady pro EditText a ListView, když každý má dost jiné atributy?” Výborná otázka, dělají to stejně, jako CSS – každé View si ze všech možných nastavených atributů vybere jen ty, které potřebuje.

Takže bychom mohli dál vylepšit naši „aplikaci”. Místo toho, abychom třikrát opakovali style="@style/MyText", můžeme celé Activity nebo dokonce celé aplikaci nastavit MyText jako motiv. Jak se to dělá? V manifestu na to existuje atribut android:theme, jehož hodnotou je identifikátor motivu. V našem případě přidáme elementu <application> nebo <activity> takovýhle atribut: android:theme="@style/MyText". A je to!

 

Moment, není, vždyť ten obrázek nevypadá stejně jako předchozí (ačkoli tedy vypadá lépe). Máte pravdu. Předchozí příklad totiž používal vestavěný motiv Theme.Holo.Light.DarkActionBar, který se nastavil automaticky při vytvoření projektu ADT pluginem v20, zatímco v tomto příkladu jsme původní motiv přepsali (ať už jsme doslova v kódu, anebo obrazně tím, že jsme nastavili motiv Activity) naším MyText. Jak to vyřešit? Za chvilku se k tomu dostaneme, ale nejdřív vám povím něco o dědičnosti stylů.

Dědičnost stylů

Zatímco v CSS může několik různých bloků cílit na stejný element, který potom všechny jejich styly zkombinuje, Android žádné kaskády neumí, a každé View tak může mít jen jeden styl. Přesto se v něm ale dá vyřešit problém, kdy potřebuji, aby měly všechny EditTexty v aplikaci stejný vzhled, až na to, že polovina bude mít tučné písmo a polovina ne. S tím, co známe doposud, bychom skončili buď u dvou duplikujících se stylů, až na to, že jeden má navíc android:textStyle="bold", anebo u jednoho stylopisu a ručně přidaného atributu android:textStyle="bold" každému EditTextu, který má být tučný.

Tvrzení, že každé View může mít jen jeden styl je sice pravdivé, ale ne úplně přesné. Může mít jen jeden atribut style. Ale atributy, které nejsou nastavené v předaném stylu, se vezmou z motivu dané Activity (či aplikace, pokud Activity vlastní motiv nastavený nemá), a pokud potřebné atributy nejsou ani v motivu, použijí se výchozí.

Tím, že od sebe styly mohou dědit, můžeme vytvořit styl MyEditText, kde definujeme všechno pro netučné EditTexty, tedy všechno, co mají společné, a potom styl  MyEditText.Bold, který bude dědit od MyEditText a přidá jen tučný text.

Samotný fakt, že nějaký styl dědí od jiného, můžete deklarovat dvěma způsoby.

Dědit od nějakého stylu můžete pomocí atributu parent elementu <style>, jehož hodnotou je odkaz na style surovinu – rodiče.

Nenašel jsem to nikde dokumentované, nicméně hodnotou parent může být i samotný název stylu, případně s namespace (třeba android:Theme.Holo.Light). To mimochodem používá právě ADT plugin v20.

Druhou možností jak dědit, ale to lze pouze od vlastních stylů, nikoli od androidích, je pomocí tečky. Pokud máte vytvořený styl MyEditText, od nějž chcete dědit a přidat tučné písmo, stačí nový styl pojmenovat MyEditText.Bold (za tečkou místo Bold může být cokoli). Android už pozná, že chcete dědit.

Následující tři elementy <style> dělají to samé (přičemž poslední dodržuje pojmenovávací konvence a celkově ho považuji za nejlepší):

<style name="MyBoldStyle" parent="MyStyle">
    <item name="android:textStyle">bold</item>
</style>

<style name="MyBoldStyle" parent="@style/MyStyle">
    <item name="android:textStyle">bold</item>
</style>

<style name="MyStyle.Bold">
    <item name="android:textStyle">bold</item>
</style>

Vestavěné motivy

Do Gingerbreadu (Android 2.3) bylo všechno jednoduché. Ale pak přišel Honeycomb (3.0) s novým holografickým stylem a věci zkomplikoval. No a aby toho nebylo málo, Ice Cream Sandwich (4.0) přidal ještě další motivy (ačkoli tam není změna tak markantní).

Všechny možné motivy naleznete v souboru {složka adk}/platforms/android-{verze}/data/res/values/themes.xml a v případě ICS a výše ještě {složka adk}/platforms/android-{verze}/data/res/values/themes_device_defaults.xml, my si ukážeme ty základní důležité:

Vestavěné motivy
Název Od verze API @style android.R
Theme 1 @android:style/Theme android.R.style.Theme
Theme.Light 1 @android:style/Theme.Light android.R.style.Theme_Light
Theme.Black 1 @android:style/Theme.Black android.R.style.Theme_Black
Holo 11 @android:style/Theme.Holo android.R.style.Theme_Holo
Holo.Light 11 @android:style/Theme.Holo.Light android.R.style.Theme_Holo_Light
Holo.Light.DarkActionBar 14 @android:style/Theme.Holo.Light.DarkActionBar android.R.style.Theme_Holo_Light_DarkActionBar
DeviceDefault 14 @android:style/Theme.DeviceDefault android.R.style.Theme_DeviceDefault
DeviceDefault.Light 14 @android:style/Theme.DeviceDefault.Light android.R.style.Theme_DeviceDefault_Light
DeviceDefault.Light.DarkActionBar 14 @android:style/Theme.DeviceDefault.Light.DarkActionBar android.R.style.Theme_DeviceDefault_Light_DarkActionBar

Theme

 

Výchozí motiv na Androidu < 3.0. Můžete předpokládat, že budete pracovat s tmavým pozadím a světlým textem navrchu. Viz  R.style.Theme.

Theme.Light

 

Víceméně inverzní k Theme. Viz R.style.Theme_Light.

Theme.Black

 

Motiv, jehož pozadí je úplně černé (já nevidím rozdíl oproti Theme). Viz  R.style.Theme_Black.

Holo

 

Výchozí, tmavý holografický motiv na Androidu 3.x. Viz  R.style.Theme_Holo.

Holo.Light

 

Světlá verze Holo. Viz R.style.Theme_Holo_Light.

Holo.Light.DarkActionBar

S API 14 přišla ještě jedna varianta holografického motivu, a to světlý s tmavým Action Barem. Viz  R.style.Theme_Holo_Light_DarkActionBar.

DeviceDefault

 

Výchozí na ICS a výše.

Asi jste si všimli, že je tento vzhled totožný s Holo. Řeší totiž problém, kdy výrobci zařízení upravovali Holo tak, aby zapadlo do jejich UI nadstaveb. A to přinášelo problémy. Na zařízeních od ICS výše, na nichž je Play Store, Google garantuje, že Holo bude vždycky přesně Holo, zatímco DeviceDefault si mohou výrobci upravovat dle libosti. Na zařízeních z rodiny Nexus, emulátorech a telefonech bez nadstaveb je DeviceDefault v podstatě jen alias příslušného holografického motivu. Proto už u zbylých dvou DeviceDefault motivů screenshoty vynechám, dokážete si je jistě domyslet. (Zdroj: Holo everywhere)

Viz R.style.Theme_DeviceDefault.

DeviceDefault.Light

Viz Holo.Light.

DeviceDefault.Light.DarkActionBar

Viz Holo.Light.DarkActionBar.

Když mluvím o tom, že je něco výchozího od, ve skutečnosti mám na mysli, že se to použije, když je targetSdkVersion nastaveno alespoň na odpovídající verzi API a telefon alespoň tak vysokou verzi API má.

Použil/a jsem DeviceDefault.Light, ale na Androidu 2.3 mi aplikace padá.

To je proto, že na Androidu 2.3 žádné DeviceDefault.Light není. Jak to ale vyřešit, pokud chci, aby má aplikace používala světlý motiv, a to ten nejnovější dostupný?

Článek Suroviny, Intenty, jednotky se mimo jiné věnoval modifikátorům. A modifikátor verze je přesně to, co potřebujeme. Do složky /res/values/styles.xml vložíme něco takového:

<style name="MyBaseTheme" parent="android:Theme.Light" />

Do složky /res/values-v11/styles.xml dáme následující řádek:

<style name="MyBaseTheme" parent="android:Theme.Holo.Light" />

A do třetice všeho dobrého, pokud netrváme na tom, že musíme mít neupravený holografický motiv, do /res/values-v14/styles.xml půjde tohle:

<style name="MyBaseTheme" parent="android:Theme.DeviceDefault.Light" />

MyBaseTheme potom buď nastavíme jako motiv aplikace či Activity, nebo od ní necháme v /res/values/styles.xml  dědit dejme tomu MyTheme, v níž nastavíme všechny atributy, které chceme, aby se změnily, nehledě na verzi Androidu (pokud chcete něco nastavit třeba jen u Theme.Light, můžete deklaraci MyBaseTheme v příslušné složce samozřejmě obohatit i nějakými  <item>-y):

<style name="MyTheme" parent="MyBaseTheme">
    <item name="android:padding">@dimen/padding</item>
</style>

Pozitivní je, že práci s vytvářením složek a souborů pro moderní, ale kompatibilní motivy za nás udělal ADT plugin v20 sám, takže je potřeba akorát případně změnit jednotlivé rodičovské motivy.

Tím jsme mimochodem vyřešili i problém, kdy se nám po aplikování motivu MyText změnil vzhled aplikace. Stačilo by, aby MyText dědil od nějakého vestavěného motivu (v našem případě by to u API >= 14 bylo  Theme.DeviceDefault.Light.DarkActionBar.

To, co jsem zde vyjmenoval, nejsou všechny možnosti. Například lze nastavit, aby se jako pozadí použilo to, které má uživatel nastavené na domovské obrazovce. Takové motivy mají koncovku .Wallpaper (takže například  Theme.DeviceDefault.Wallpaper).

Proč mají některé motivy přípony typu NoActionBar?

Trochu jsem vám totiž lhal, když jsem tvrdil, že mezi kódem motivu a stylu není žádný rozdíl. Motiv může narozdíl od stylu obsahovat i tzv. okenní atributy, které se netýkají žádného View, ale celého okna. Pomocí nich můžete skrýt ActionBar, udělat Activity průhlednou, nastavit wallpaper jako pozadí nebo celou Activity skrýt. Všechny okenní atributy najdete v R.attr  počínaje R.attr.windowActionBar (všechny začínají na  window).

Část okenních atributů se prolíná se schopnostmi metody  requestWindowFeature().

R.attr

Přemýšlíte, které atributy můžete ve stylech použít? Odpovědí je třída R.attr. A protože se s atributy dá dělat plno zajímavých věcí, budeme se jim teď chvilku věnovat.

Než ale začneme, musíte na chvíli přestat považovat slovo atribut za něco, co přímo souvisí s XML (layouty). Někdy ano, někdy ne.

Atributy jsou totiž mimojiné velmi šikovný způsob, jak v rámci svých stylů nebo v rámci View použít části motivů. Vzpomeňte si kupříkladu, jak jsem úplně na začátku pro barvu textu použil @android:color/primary_text_light a pro pozadí @android:color/background_dark. Už tehdy výsledek nevypadal dvakrát hezky, příliš neladil s motivem. Ale co je horší, při změně motivu tyhle barvy zůstávaly stejné. A to my přece rozhodně nechceme.

Díky atributům může uživatel ve svém kódu použít části motivu. Například právě barvy. Text bude mít určitě jinou barvu ve světlém motivu a jinou ve tmavém. Pozadí jakbysmet.

Já atributy použil už při vytváření screenshotů pro jednotlivé motivy, jen jsem vám to zatajil. Bez atributů by to však vypadalo divně. A ptáte se, jak vypadal kód třeba prvního TextView?

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:textAppearance="?android:attr/textAppearanceLarge"
    android:color="?android:attr/textColorPrimary"
    android:text="@string/title" />

Jak vidíte, v atributu android:color jsem použil atribut R.attr.textColorPrimary. Ale nachází se tam ještě jeden atribut, který nám už je vlastně dlouho známý! Samozřejmě i u vzhledu textu se hodí, když ho může motiv nastavit.

Některé atributy si tedy přivlastňují různá View, zatímco jiné slouží pouze pro definování balíčku vzhledových dat, která může pak uživatel někde použít.

Pokud si vytváříte vlastní motiv, můžete atribut android:textColorPrimary nastavit na nějakou vlastní barvu. Já třeba mohu udělat toto (pokud předpokládám, že AppTheme je motiv automaticky vygenerovaný ADT Pluginem a snaží se používat vždy ten nejmodernější vestavěný motiv). Pomiňme, prosím, že tam mám barvu vepsanou přímo a nikoli jako surovinu.

<style name="MyTheme" parent="AppTheme">
    <item name="android:textColorPrimary">#f00</item>
</style>

A když ještě nastavím MyTheme jako motiv v manifestu…

…text je najednou červený!

 

Na atributech je také zajímavé, že mohou obsahovat řetězec, barvu, číslo, může to být enum, jejich hodnotou mohou být flagy spojené bitovým OR, dokonce může být jejich hodnotou i celý styl (to je právě případ textApperanceLarge atp.)! Věnovat se tomu nebudeme, odkážu vás na StackOverflow, kde Qberticus poskytl opravdu vynikající odpověď, případně na soubor attrs.xml ve složce  {složka adk}/platforms/android-{verze}/data/res/values.

R.styleable

Třída R.styleable je odpovědí na nevyřčenou otázku „Jak poznám, které (nejen) View přijímá které atributy?” Více se jí věnovat nebudeme, pokud vás to zajímá, opět vizte výše odkazanou otázku na StackOverflow případně zdrojáky ( styleable.xml). Tak se můžete i naučit, jak vytvářet vlastní atributy pro vlastní View.

Jak nastavit motiv v kódu?

Není to úplně jednoduché a doporučuju se tomu vyhnout, může to být zdrojem chyb. V případě Activit lze použít metodu setTheme(), ale ta musí být zavolána před tím, než se začne vytvářet nějaký layout (tzn. v praxi prostě před  setContentView()).

DialogFragment na to má také metodu, setStyle(), která kromě nastavení motivu (pravděpodobně budete chtít použít nějaký s příponou .Dialog, bez toho se může stát, že se dialog zobrazí přes celé okno. Opět musíte volat před tím, než se nějaké UI vytvoří, v praxi v  onCreate() .

U Fragmentů je to docela složité. Abychom to pochopili, musíme si vysvětlit, jak to s těmi motivy vlastně je.

Informace o motivu je totiž uložena v Contextu. A podle toho, jakýContext použije LayoutInflater vytvářející vaše View (šikovná může být metoda cloneInContext()), takový motiv budou View mít.

Pokud chcete použít stejný motiv, jako obsahující Activity, je to jednoduché – LayoutInflater je už nasatven. Pokud chcete vlastní, musíte si vytvořit kontext s příslušným motivem a s ním naklonovat inflater.

Zajímavé následky to může mít i u Adapterů. Těm totiž také předáváte kontext, mimojiné aby si mohly vytvořit LayoutInflater. A pokud máte na <activity> nastavený jiný motiv než na <application>, je rozdíl jestli Adapteru jako Context předáte samotnou Activity, anebo objet vrácený metodou  getApplicationContext().

Závěr

Dnes jsme si prošli stylování od úplně začátečnických věcí až po poměrně pokročilé, které ani nejsou v oficiální dokumentaci (na tom by mohli soudruzi zapracovat…). Doufám, že jsem na nic důležitého nezapomněl, ačkoli vím, že jsem toho plno nestihl. Například takový color state list je rozhodně zajímavý, a navíc nepostradatelný, když chcete třeba změnit barvu položky ListView, která je právě stisknutá (viz android:listSelector). Nezmínil jsem se o 9-patchi a celkově jsem vůbec nepovídat o různých drawable surovinách, což vůbec nejsou jen nudné obrázky!

Doufám, že se vám dnešní článek líbil a že pro vás byl užitečný. Příště se budeme věnovat práci s internetem, broadcast receiverům, tomu, jak opakovaně provádět nějakou akci v určitý čas a možná se dostane i na notifikace.

Tip na konec

Chcete vyzkoušet, jak vaše aplikace funguje na telefonu bez hardwarových tlačítek? Stačí jako hardware property přidat Hardware Back/Home keys a její hodnotu nastavit na no. Pak se můžete třeba podívat, jak se chová naše aplikace z dílu Preference, menu a vlastní Adapter.

Tip na konec 2

Eclipse umí v náhledu layoutu vyzkoušet plno věcí, včetně jednotlivých motivů, a to i vašich vlastních.

Mimochodem, ironií osudu se stalo, že jsem dostal nabídku přednášet o Androidu na konferenci pořadané společností EurOpen.cz. Pokud si mě chcete poslechnout, bude to 17. října ve Vílanci u Jihlavy.

Matěj začal programovat ve třinácti v PHP, pak v JavaScriptu a Lispu. Nakonec si koupil Androida, a tak programuje hlavně pro něj.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Zdroj: http://www.zdrojak.cz/?p=3701