V tomto návodu se budeme zabývat způsobem, jak pomocí kódu v Android aplikaci detekovat doteky na obrazovce a skrýt či zobrazit systémové rozhraní. Tento proces zahrnuje manipulaci s různými vlajkami systému a využití gesta k ovládání viditelnosti systémového UI.

Začneme přidáním metody pro skrytí systémového rozhraní. K tomu použijeme následující kód:

java
private void hideSystemUi() { getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); }

Tento kód způsobí, že se systémové rozhraní skryje, čímž aplikace přejde do tzv. „Immersive Mode“, ve kterém nejsou viditelné tlačítka systému ani stavová lišta. Tento režim je velmi užitečný například u multimediálních aplikací nebo hrách, kde je důležité mít co nejvíce prostoru na obrazovce.

Pro zobrazení systému opět použijeme příslušnou metodu:

java
private void showSystemUI() { getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); }

Tato metoda obnoví zobrazení všech systémových prvků, jako je stavová lišta a navigační tlačítka.

Dalším krokem je přidání proměnné pro detekci gest. Vytvoříme proměnnou mGestureDetector a přidáme ji do třídy:

java
private GestureDetectorCompat mGestureDetector;

Pro detekci konkrétních gest vytvoříme třídu GestureListener, která bude reagovat na různé dotyky a pohyby na obrazovce:

java
private class GestureListener extends GestureDetector.SimpleOnGestureListener { @Override public boolean onDown(MotionEvent event) { return true; } @Override
public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
return true; } @Override public boolean onSingleTapUp(MotionEvent e) { if (getSupportActionBar() != null && getSupportActionBar().isShowing()) { hideSystemUi(); } else { showSystemUI(); } return true; } }

Tato třída reaguje na jednoduchý tap (jednoduchý dotek) na obrazovce, který bude buď skrývat, nebo zobrazovat systémové rozhraní v závislosti na jeho aktuálním stavu.

Pokud chcete, aby aplikace reagovala na dotyky na obrazovce, musíte přepsat metodu onTouchEvent, která zprostředkovává detekci pohybu na obrazovce pro náš GestureDetector:

java
public boolean onTouchEvent(MotionEvent event) { mGestureDetector.onTouchEvent(event); return super.onTouchEvent(event); }

Dále je potřeba inicializovat detektor gest ve vaší metodě onCreate() a skrýt systémové UI při spuštění aplikace:

java
mGestureDetector = new GestureDetectorCompat(this, new GestureListener());
hideSystemUi();

Tento kód zajistí, že systémové UI bude skryté ihned po spuštění aplikace. Poté bude možné pomocí gesta na obrazovce přepínat mezi skrytým a zobrazeným systémovým rozhraním.

Sticky Immersion Mode

Pokud si přejete, aby bylo systémové rozhraní skryté po celou dobu, můžete použít jiný přístup – „Sticky Immersion Mode“. Tento režim zajistí, že systémové rozhraní bude skryté dokud uživatel sám neudělá gesto nebo jiný vstup k jeho zobrazení. Pro jeho aktivaci použijte následující vlajku místo SYSTEM_UI_FLAG_IMMERSIVE:

java
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);

Dimming the System UI

Pokud byste rádi pouze ztlumili viditelnost systémového UI (například aby navigační tlačítka byla méně nápadná), můžete použít flag SYSTEM_UI_FLAG_LOW_PROFILE:

java
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);

Tento režim ztmaví systémové tlačítka a stavovou lištu, ale neodstraní je z obrazovky úplně.

Resetování všech vlajek UI

Pokud chcete všechny změny v nastavení systému vrátit na výchozí hodnoty, použijte následující kód pro vymazání všech vlajek:

java
getWindow().getDecorView().setSystemUiVisibility(0);

Skrývání a zobrazování Action Baru

Pokud potřebujete pouze skrýt nebo zobrazit akční lištu (Action Bar), můžete použít jednoduché metody:

java
getActionBar().hide(); getActionBar().show();

Tento přístup je však problematický, protože každé volání těchto metod způsobí přeformátování rozložení. Místo toho je lepší použít možnosti nastavení pro vytvoření efektu překrytí systémového UI. Můžete upravit téma aplikace takto:

xml
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowTranslucentStatus">true</item>

Tento přístup umožňuje, aby systémové prvky, jako je stavová lišta a navigační panel, byly průhledné a aplikace se mohla přes ně zobrazovat jako překrytí.

Translucent System Bars

Pokud chcete, aby systémové lišty byly průhledné, můžete použít následující téma:

xml
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>

Tento přístup je užitečný pro aplikace, které chtějí využít celé dostupné místo na obrazovce, ale zároveň zachovat přítomnost systémového UI.

Závěr

Tato metoda práce se systémovým rozhraním poskytuje silné nástroje pro ovládání uživatelského zážitku v Android aplikacích. Je důležité pochopit, jak různé vlajky a gesta mohou ovlivnit interakci s aplikací. Pomocí správného nastavení Immersive Mode nebo Sticky Immersive můžete zajistit, že vaše aplikace bude plynule fungovat bez rušivých systémových prvků, a přitom umožnit snadný přístup k těmto prvkům, pokud je to potřeba.

Jak správně implementovat přehrávání zvuků v Android aplikacích pomocí SoundPool a MediaPlayer

Při práci s multimediálními funkcemi v Android aplikacích se častým úkolem stává přehrávání zvukových efektů. V tomto kontextu se velmi často používají dvě hlavní třídy: SoundPool a MediaPlayer. Každá z těchto tříd je vhodná pro různé scénáře. SoundPool je ideální pro přehrávání krátkých zvuků, například efektů, zatímco MediaPlayer se hodí pro přehrávání delších zvukových souborů, jako jsou hudba nebo zvukové klipy. V této kapitole se zaměříme na implementaci obou metod v praxi.

Prvním krokem je vytvoření aplikace, která bude schopná přehrávat zvuky pomocí třídy SoundPool. Tento proces začíná definováním potřebných globálních proměnných. Jakmile přidáme proměnné HashMap a SoundPool, musíme v metodě onCreate() vytvořit odpovídající instanci SoundPool. Důležitý krok je detekce verze operačního systému, protože v API verze 21 (Lollipop) byl změněn způsob, jakým je SoundPool vytvářen. Starý způsob používání SoundPool byl zastaralý a nahradil ho SoundPool.Builder().

java
@TargetApi(Build.VERSION_CODES.LOLLIPOP) private void createSoundPoolNew() {
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA) .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .build(); mSoundPool =
new SoundPool.Builder() .setAudioAttributes(audioAttributes) .setMaxStreams(2) .build(); }

Pokud je verze systému nižší než Lollipop, použije se starší metoda SoundPool(int, int, int), která je stále funkční, i když již označena jako zastaralá. Tato zpětná kompatibilita je důležitá pro aplikace, které běží na starších verzích Androidu.

Dále je třeba implementovat metody pro přehrávání zvuků. Tyto metody spustí zvuk podle předchozích konfigurací, přičemž při přehrávání je možné nastavovat hlasitost pro levý a pravý kanál, počet opakování a rychlost přehrávání. Zvuky jsou nahrány do HashMap, což umožňuje jejich efektivní správu a přístup.

java
public void playSound1(View view) {
mSoundPool.play(mHashMap.get(1), 0.1f, 0.1f, 1, 0, 1.0f); } public void playSound2(View view) {
mSoundPool.play(mHashMap.get(2), 0.9f, 0.9f, 1, 1, 1.0f);
}

V případě, že aplikace používá více než jeden zvuk, je možné přehrávat je současně, což poskytuje větší flexibilitu při vytváření zvukových efektů. Po přehrání je důležité správně uvolnit prostředky, například ve metodě onStop().

java
protected void onStop() { super.onStop(); mSoundPool.release(); }

Dalším důležitým nástrojem pro práci se zvukem je třída MediaPlayer. Tento přehrávač je navržen pro přehrávání dlouhých zvukových souborů, jako jsou MP3 nebo WAV. V aplikaci může být spuštěn, pozastaven nebo zastaven pomocí několika jednoduchých metod. Pro správu zvukového souboru musíme vytvořit instanci MediaPlayer a připojit ji k souboru v projektu. Následně definujeme metody pro přehrávání, pozastavení a zastavení zvuku.

java
public void buttonPlay(View view) {
if (mMediaPlayer == null) { mMediaPlayer = MediaPlayer.create(this, R.raw.sound_1); mMediaPlayer.setLooping(true); mMediaPlayer.start(); } else { mMediaPlayer.start(); } }

Pokud je soubor již načten, může být zvuk jednoduše znovu spuštěn bez nutnosti opětovného načítání. Pro pozastavení nebo zastavení přehrávání lze použít následující metody:

java
public void buttonPause(View view) { if (mMediaPlayer != null && mMediaPlayer.isPlaying()) { mMediaPlayer.pause(); } } public void buttonStop(View view) { if (mMediaPlayer != null) { mMediaPlayer.stop(); mMediaPlayer.release(); mMediaPlayer = null; } }

Při implementaci MediaPlayeru je také kladeno důraz na správu životního cyklu aplikace. V metodě onStop() se doporučuje uvolnit prostředky a nastavit proměnnou mMediaPlayer na null, což zabraňuje únikům paměti a zajišťuje hladký běh aplikace.

java
protected void onStop() { super.onStop(); if (mMediaPlayer != null) { mMediaPlayer.release(); mMediaPlayer = null; } }

Ve chvíli, kdy aplikace přehrává delší zvukový soubor, jako je například zvuk vody, je důležité dbát na to, aby zvuk byl smíšený do pozadí a nezpůsoboval rušení jiných aplikací nebo systémových zvuků.

Pokud však potřebujete pouze jednoduchý zvukový efekt, například kliknutí, můžete využít jednodušší metodu AudioManager.playSoundEffect(). Tato metoda umožňuje přehrávání standardních zvuků definovaných ve třídě SoundEffectConstants, ale neumožňuje použití vlastních zvukových souborů. Tato metoda je velmi efektivní pro jednoduché efekty, jako jsou upozornění nebo potvrzení uživatelské akce.

Kromě uvedených metod je v současnosti velmi důležité zaměřit se na efektivní správu paměti a prostředků, protože zvukové soubory mohou být velmi náročné na systémové prostředky, zvláště na starších zařízeních. Při práci s SoundPool a MediaPlayer je nezbytné zajistit, že zvukové soubory budou správně uvolněny po jejich přehrání, aby nedocházelo k únikům paměti.

Jak efektivně používat různé typy rozložení v Androidu: LinearLayout a TableLayout

V aplikacích pro Android je správné uspořádání komponent klíčové pro vytvoření přehledného a funkčního uživatelského rozhraní. K tomu slouží různé typy rozložení (layouts), přičemž dvě z nejběžněji používaných jsou LinearLayout a TableLayout. Každý z těchto layoutů má specifické výhody a je vhodný pro různé případy užití.

LinearLayout a jeho využití

LinearLayout je rozložení, které umožňuje uspořádat všechny jeho potomky v jedné řadě – buď vertikálně, nebo horizontálně. Pokud není orientace výslovně specifikována, výchozí hodnotou je vertikální orientace, což znamená, že všechny prvky jsou seřazeny do sloupce. Tato jednoduchost a přehlednost dává vývojářům flexibilitu při návrhu základních uživatelských rozhraní, kde komponenty mají být umístěny jedna pod druhou nebo vedle sebe.

Jedním z významných atributů LinearLayout je layout_weight. Tento atribut umožňuje specifikovat, jak má každá komponenta reagovat na dostupný prostor. Například pokud máme více komponent, můžeme použít layout_weight, abychom určili, jakým způsobem se budou dělit zbylé místo v layoutu. Komponenty s vyšší hodnotou layout_weight zabírají více místa, zatímco ty s nižší hodnotou mají menší podíl na dostupném prostoru.

Příklad použití atributu layout_weight ukazuje, jak jednoduše můžeme nastavit různé editovatelné textové pole (EditText), kde jedno z nich zabere více místa než ostatní. Tato dynamická velikost komponent umožňuje efektivně pracovat s různými velikostmi obrazovek, což je pro moderní mobilní aplikace velmi důležité.

Pokud používáte LinearLayout v horizontální orientaci, je třeba nastavit výšku komponent na hodnotu "0dp" a místo toho použít layout_weight pro určení šířky. Tato flexibilita může výrazně usnadnit návrh rozhraní, které má reagovat na různé velikosti obrazovek.

TableLayout pro strukturovaná rozložení

Pro aplikace, které vyžadují rozložení ve formě tabulek, nabízí Android dva typy layoutů – TableLayout a GridLayout. Oba tyto layouty mohou vypadat podobně, ale rozdíl je v přístupu, jakým se vytváří a organizuje tabulka.

TableLayout je vhodný pro dynamické přidávání řádků a sloupců. Každý řádek je definován jako TableRow, který obsahuje několik komponent, např. textových polí nebo tlačítek. Tento přístup je ideální pro situace, kdy není dopředu jasné, kolik řádků a sloupců bude aplikace potřebovat. Naopak GridLayout je statičtější, protože počet řádků a sloupců musí být definován při vytváření layoutu. GridLayout je ideální pro aplikace, kde je potřeba mít pevně stanovený počet řádků a sloupců, například v aplikacích pro kalkulačky nebo hry.

Při použití TableLayout se řádky a sloupce vytvářejí dynamicky, což znamená, že se mohou přidávat podle potřeby. Tento flexibilní přístup je ideální pro aplikace, které vyžadují změny v tabulkách na základě uživatelského vstupu nebo jiných faktorů. Na druhé straně GridLayout je lepší, když máte pevně danou strukturu, která nebude měnit svůj počet sloupců a řádků během používání aplikace.

Různé způsoby zarovnání komponent

Android umožňuje kombinovat různé možnosti pro zarovnání komponent. V případě LinearLayout je možné využít atribut android:gravity, který určuje, jak bude text nebo obsah zarovnán uvnitř komponenty. Například android:gravity="top" způsobí, že text se zarovná na horní část komponenty. Tento atribut je zásadní, pokud chcete mít pod kontrolou, jak bude obsah uvnitř komponenty zobrazen.

Další užitečný atribut je android:layout_gravity, který určuje, jak bude komponenta umístěna v rámci svého rodičovského layoutu. Tento atribut je velmi užitečný při práci s různými rozloženími, jako jsou LinearLayout nebo RelativeLayout, kde potřebujete specifikovat pozici komponenty v rámci jejího rodiče.

Je důležité si uvědomit, že gravity se vztahuje na obsah komponenty, zatímco layout_gravity se používá pro určení pozice samotné komponenty v rámci jejího rodiče. Míchat tyto dva pojmy může vést k nejasnostem a nesprávnému zobrazení uživatelského rozhraní.

Optimalizace rozložení pro výkon

Při vytváření aplikací je také klíčové dbát na výkon. Nadměrné vnořování layoutů (kdy jeden layout obsahuje další layouty) může mít negativní vliv na výkon aplikace, zejména při opakovaném vykreslování rozhraní (například v případě ListView nebo RecyclerView). Je dobré se vyhnout zbytečnému vnořování, protože každé další vnoření znamená větší nároky na vykreslování a výpočty.

V tomto ohledu je dobré využívat nástroj Hierarchy Viewer, který pomáhá vizualizovat a optimalizovat strukturu layoutů. Tento nástroj ukazuje, jak jsou jednotlivé komponenty vnořeny, což umožňuje identifikovat případné problémy s výkonem a optimalizovat návrh uživatelského rozhraní.

Ve světě mobilních aplikací je výkon kritický, a tak je vždy nutné přemýšlet o tom, jaké layouty použít a zda neexistují efektivnější způsoby organizace komponent.