V Android vývoji se často naskytne otázka, jaký typ rozvržení zvolit pro efektivní uspořádání uživatelského rozhraní. Dvě z často porovnávaných možností jsou TableLayout a GridLayout. Na první pohled mohou působit podobně – obě umožňují uspořádat prvky do tabulkového formátu – avšak jejich implementace a možnosti se výrazně liší, což ovlivňuje volbu v konkrétních situacích.

V projektu založeném na GridLayout je možné začít jednoduše tím, že nastavíme GridLayout jako kořenový element v activity_main.xml a definujeme atributy columnCount="3" a rowCount="3". Tím vytvoříme mřížku o třech sloupcích a třech řádcích. Následně přidáme devět prvků TextView – bez nutnosti vkládat je do TableRow, jako je tomu u TableLayout. Tři prvky se umístí do prvního řádku, další tři do druhého a zbytek do třetího. Android automaticky naplní buňky podle pořadí.

Výsledkem je vizuálně podobná tabulka jako při použití TableLayout. Rozdíl spočívá zejména v tom, že v TableLayout explicitně definujeme každý řádek pomocí TableRow a systém určí počet sloupců podle nejdelšího řádku. V jednotlivých řádcích lze vynechat buňky nebo je ponechat prázdné. Umístění konkrétního prvku do určitého sloupce lze specifikovat pomocí atributu android:layoutColumn.

Oproti tomu GridLayout definuje počet sloupců a řádků již při deklaraci. Pokud nespecifikujeme ručně pozice řádku a sloupce pro každý prvek, systém je rozmisťuje automaticky podle pořadí. Toto chování lze přepsat použitím atributů jako android:layout_row="2" a android:layout_column="2". Je důležité mít na paměti, že pokud jeden prvek specifikuje pozici a další nikoliv, může dojít k nečekanému chování, jelikož Android pokračuje v číslování buněk automaticky.

Oba layouty také nabízejí možnosti přizpůsobení šířky sloupců. V TableLayout je možné nastavit atribut android:stretchColumns="1" přímo v deklaraci tabulky, kde číslo označuje index sloupce (počítáno od nuly), který se má roztáhnout podle dostupného prostoru. Podobně lze v GridLayout dosáhnout roztahování sloupce defi

Jak funguje kontextová akční lišta a kontextové nabídky v Androidu?

Android umožňuje uživatelsky přívětivé interakce prostřednictvím kontextových nabídek, které reagují na specifické akce uživatele v rámci rozhraní. Jedním z nejdůležitějších prvků v tomto směru je Contextual Action Bar (CAB), což je dynamická lišta nástrojů zobrazující se při výběru více položek v rámci seznamu (ListView). Nejedná se o klasickou akční lištu, ale o dočasnou variantu, která umožňuje provádět akce nad vybranými prvky. CAB je aktivována dlouhým stiskem nebo – jak si ukážeme – také pouhým kliknutím, pokud tuto logiku vývojář výslovně implementuje.

Základem této funkcionality je správně nakonfigurovaný ListView, který musí být nastaven do režimu CHOICE_MODE_MULTIPLE_MODAL. To znamená, že výběr více položek automaticky vyvolá CAB. Následně se musí zavolat setMultiChoiceModeListener(), který akceptuje instanci MultiChoiceModeListener. Tento listener zároveň implementuje rozhraní ActionMode.Callback, čímž získává schopnost reagovat na jednotlivé fáze kontextového režimu – vytvoření, aktualizace, zničení a kliknutí na položky nabídky.

Konkrétní akce jako „Move“ nebo „Delete“ jsou zpracovány ve switch bloku v metodě onActionItemClicked(). Po provedení akce je CAB ukončen metodou mode.finish(). Z hlediska použitelnosti je důležité zmínit, že CAB lze vyvolat nejen dlouhým kliknutím, ale i běžným výběrem položky – například v metodě onItemClick() je možné volat setItemChecked(position, true), čímž se daný prvek považuje za označený a CAB se aktivuje.

Tato rozšířená interakce zajišťuje, že uživatel nemusí objevovat funkčnost prostřednictvím méně intuitivních gest (jako je dlouhý stisk), ale může se k ní dostat i přirozeným výběrem položky. Pokud by vývojář tuto možnost nezavedl, mnoho uživatelů by o existenci CAB vůbec nemuselo vědět.

CAB je navržen tak, aby se překrýval s existující akční lištou, pokud je aktivní. Pokud výchozí téma aplikace akční lištu neobsahuje, rozvržení se dynamicky upraví tak, aby se CAB zobrazil. Vývojář tak má možnost ovlivnit výsledné chování buď změnou tématu, nebo změnou základní třídy aktivity a ručním nastavením ListView.

Samostatnou, ale příbuznou oblastí jsou vyskakovací nabídky (pop-up menu), které poskytují alternativní kontextové akce bez přímého ovlivnění samotného pohledu (View). Vyskakovací nabídka je obvykle připojena k určitému prvku, jako je například ImageButton, a po jeho stisku se zobrazí nabídka s možnostmi jako „Reply“, „Reply All“, „Forward“. Tato nabídka se vykresluje dynamicky – pokud je pod kotvícím prvkem dostatek místa, zobrazí se pod ním, jinak nad ním. Pop-up menu tedy neslouží k modifikaci samotného pohledu, nýbrž k nabídnutí doplňkových akcí.

Aby bylo možné zobrazit pop-up menu, musí vývojář vytvořit XML soubor nabídky v adresáři res/menu, a následně ve třídě MainActivity zavolat PopupMenu, inflatovat menu a nastavit OnMenuItemClickListener, který obslouží jednotlivé položky.

Klíčovým aspektem správné implementace obou typů nabídek – CAB i pop-up – je porozumění tomu, kdy a kde má být určitý typ nabídky použit. Kontextové akční lišty jsou vhodné pro hromadné operace s více prvky, zatímco pop-up menu představuje způsob, jak uživateli nabídnout relevantní, ale doplňkové možnosti vázané na konkrétní vizuální komponentu.

Důležité je si uvědomit, že CAB není vázána na přítomnost běžné akční lišty. Může se zobrazit nezávisle na ní a v mnoha případech je žádoucí, aby se CAB překrývala s původní lištou – poskytuje tak konzistentní a efektivní uživatelský zážitek bez vizuální fragmentace rozhraní. Správné využití CAB a pop-up menu vede nejen ke kvalitnějšímu UX, ale zároveň snižuje kognitivní nároky na uživatele, kteří mohou rychleji pochopit funkce aplikace díky přirozenému a intuitivnímu návrhu interakce.

Na závěr je vhodné připomenout, že vývojář musí dbát na konzistenci v rámci celého uživatelského rozhraní aplikace. Použití správného typu nabídky ve správný čas je otázkou nejen technického provedení, ale i designové citlivosti. Kontextové akce by měly být vždy relevantní k danému výběru a neměly by zahlcovat uživatele nadbytečnými možnostmi. Rovněž by měly být jednoznačně rozpoznatelné a snadno aktivovatelné bez potřeby skrytých gest nebo experimentování. Kontextová nabídka má být mostem mezi úmyslem uživatele a cílem aplikace – ne překážkou.

Jak získat a číst data ze senzorů v Androidu pomocí SensorManageru a SensorEventListeneru?

Pro práci se senzory v Androidu slouží Android Sensor Framework, který poskytuje jednotný způsob, jak získat seznam dostupných senzorů a číst z nich data. Začíná to získáním instance SensorManageru prostřednictvím metody getSystemService() s parametrem Context.SENSOR_SERVICE. Pomocí SensorManageru lze pak získat seznam všech dostupných senzorů voláním getSensorList(Sensor.TYPE_ALL) nebo konkrétního typu senzoru pomocí jedné z předdefinovaných konstant, například Sensor.TYPE_ACCELEROMETER. Výsledkem je seznam objektů typu Sensor, které reprezentují jednotlivé senzory přítomné v zařízení.

Pro zobrazení seznamu senzorů je vhodné použít ListView, do kterého lze vložit názvy senzorů získané pomocí metody getName() u každého Sensor objektu. Tento jednoduchý seznam pak uživatelům ukáže, jaké senzory jsou v zařízení k dispozici.

Čtení dat ze senzoru se provádí prostřednictvím rozhraní SensorEventListener, které obsahuje dvě metody: onSensorChanged() a onAccuracyChanged(). Když dojde ke změně hodnoty senzoru, je zavolána metoda onSensorChanged(), která přijímá objekt SensorEvent obsahující aktuální data senzoru. Tyto hodnoty lze poté zpracovat nebo zobrazit například v TextView. Pro registraci a odregistrování posluchače změn senzorů slouží metody registerListener() a unregisterListener(), obvykle volané v rámci životního cyklu aktivity (v onResume() a onPause()) kvůli optimalizaci spotřeby baterie.

Pro demonstraci lze použít například světelný senzor (Sensor.TYPE_LIGHT), který vrací jednorozměrnou hodnotu intenzity osvětlení. Senzory lze rozdělit do tří hlavních kategorií: environmentální (vlhkost, světlo, tlak, teplota), poziční (geomagnetické pole, proximity) a pohybové (akcelerometr, gyroskop, gravitace, lineární zrychlení, rotační vektor). Každá kategorie vrací data v mírně odlišném formátu – environmentální senzory obvykle jeden prvek, poziční a pohybové senzory zpravidla tři nebo více hodnot.

Důležitou vlastností frameworku je, že všechny senzory pracují v jednotném režimu přes SensorEventListener, což umožňuje snadné přepínání mezi různými senzory bez nutnosti zásadních úprav kódu. Je ale nezbytné chápat, že interpretace dat a jejich další využití se liší podle typu senzoru a kontextu aplikace. Například zatímco environmentální senzory poskytují přímé měření jedné veličiny, pohybové senzory často vyžadují složitější matematické zpracování a kalibraci.

Správné použití SensorManageru znamená nejen načtení dat, ale také efektivní správu zdrojů – senzory by měly být aktivní jen tehdy, když je to nutné, aby nedocházelo ke zbytečné spotřebě baterie. Proto se registrace listeneru obvykle provádí v onResume(), a naopak odregistrování v onPause().

Kromě základního čtení senzorů je důležité také rozumět možným přesnostem a kalibraci, protože některé senzory mohou vracet nepřesná data nebo vyžadovat kompenzaci chyb. Vývojář by měl být obeznámen s možnostmi SensorManageru, jako je nastavení rychlosti čtení dat (např. SENSOR_DELAY_NORMAL) a také s tím, jak zpracovávat různé typy senzorových událostí.

Celý framework je navržen tak, aby byl flexibilní a umožňoval práci se širokou škálou hardwarových senzorů, ať už jde o jednoduché environmentální senzory, nebo komplexní pohybové senzory využívané v herním a AR prostředí. To umožňuje vývojářům vytvářet aplikace reagující na okolní svět v reálném čase a zlepšovat uživatelský zážitek díky interaktivním a adaptivním funkcím.