A felhasználói felületek (UI) kezelésére számos különböző megközelítés létezik az Android alkalmazásokban, és a ListView egyik leggyakoribb eszközként említendő. Az alkalmazások többsége, amely nagy mennyiségű adatot jelenít meg, a ListView-t használja, mivel ez rendkívül hatékonyan kezeli a képernyőn való görgetést, különösen kis kijelzők esetében. Ugyanakkor, míg a ListView és a hozzá kapcsolódó adatadapterek rendkívül hasznosak, a sikeres alkalmazásfejlesztéshez nem elég csupán ezen eszközök ismerete; az adattípusok dinamikus kezelése, azok frissítése és a felhasználói interakciók megfelelő kezelése mind-mind kulcsfontosságú tényezők.

A ListView alapvetően egy adatmegjelenítő eszköz, amely képes nagy adatlisták hatékony megjelenítésére. A legegyszerűbb esetekben ez csupán egy gombot jelent, amely minden egyes listaelemhez egy-egy újabb gombot rendel. De mi történik akkor, ha az adatok dinamikusan változnak, vagy ha a felhasználói élmény igényei túlmutatnak az alapvető elvárásokon?

Vegyük például azt az esetet, amikor egy országokat tartalmazó listát kell megjeleníteni a felhasználónak. Alapértelmezés szerint egy LinearLayout-ot hozhatunk létre, amely tartalmaz egy gombot minden egyes ország számára. De mi van akkor, ha a lista nagyobb lesz, vagy ha az új országok hozzáadása valamilyen külső forrásból történik? A válasz egyszerű: a ListView használata. Az Android alkalmazásban egy egyszerű példát hozva, bemutathatjuk, hogyan lehet dinamikusan feltölteni egy ListView-t egy országokból álló tömb segítségével.

A következő kódrészlet egy alap ListView alkalmazás megvalósítását mutatja be, amely az országokat egy tömbből tölti fel:

java
public class MainActivity extends ListActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); String[] countries = new String[]{"China", "France", "Germany", "India", "Russia", "United Kingdom", "United States"}; ListAdapter countryAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, countries); setListAdapter(countryAdapter); getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String s = ((TextView) view).getText() + " " + position; Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT).show(); } }); } }

A fenti kód alapján a ListView egy egyszerű listát hoz létre, amely minden egyes országhoz egy-egy gombot rendel. Az alkalmazás futtatásakor a ListView dinamikusan jeleníti meg az adatokat, és a felhasználó interakcióját követően egy Toast üzenet jelenik meg, amely megmutatja az adott ország nevét és pozícióját a listában.

A ListView és az ArrayAdapter használata az egyik legelterjedtebb módszer az Android alkalmazásokban, azonban az Android rendelkezik más típusú adapterekkel is, mint például a CursorAdapter, amely lehetővé teszi az adatbázisokban tárolt adatok megjelenítését. Ha a beépített adapterek nem felelnek meg az igényeknek, akkor lehetőség van egy egyedi (Custom) adapter létrehozására is.

Ezen kívül a ListView kiválóan támogatja a többes kiválasztás módot is, ami hasznos lehet, ha a felhasználó több elemet szeretne egyszerre kiválasztani. Ehhez elegendő beállítani a setChoiceMode() metódust:

java
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

Ezen kívül, ha az alkalmazásunk tartalma változik, akkor a ListView listaelemei is dinamikusan frissíthetők. A tömb bővítése vagy egy új lista letöltése például egy weboldalról mind-mind lehetséges anélkül, hogy az alkalmazás újraindulna.

Egy másik hasonló megoldás, amely ugyanazt a funkcionalitást kínál, de különböző megjelenítési formátumot biztosít, a GridView. A GridView egy többoszlopos megjelenítést kínál, amely az adatok vizuális megjelenítését képes javítani, különösen, ha a listaelemek képeket tartalmaznak. A GridView használatához szükséges kód egy kicsit bonyolultabb, mivel nem rendelkezik beépített Activity osztállyal, mint a ListView. Az alábbi példa mutatja, hogyan lehet a ListView példát GridView-re módosítani:

java
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
GridView gridView = new GridView(this);
setContentView(gridView); String[] countries =
new String[]{"China", "France", "Germany", "India", "Russia", "United Kingdom", "United States"}; ListAdapter countryAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, countries); gridView.setAdapter(countryAdapter); gridView.setNumColumns(2); gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String s = ((TextView) view).getText() + " " + position; Toast.makeText(getApplicationContext(), s, Toast.LENGTH_SHORT).show(); } }); }

A fő különbség, hogy a GridView több oszlopban jeleníti meg az adatokat, így vizuálisan más élményt nyújt. A GridView beállítása több kódot igényel, de ez az alternatív megoldás különösen hasznos, ha az alkalmazás tartalmát oszlopokban kell elrendezni.

Végül fontos megemlíteni, hogy bár a ListView és a GridView rendkívül hasznos eszközök az adatmegjelenítésben, mindkettő statikus elemeket jelenít meg. Az Android rendszer lehetőséget biztosít arra, hogy az UI elemeket a futásidő alatt is módosítsuk, például a LayoutParams objektum használatával. Ez különösen akkor hasznos, amikor az alkalmazás felhasználói élményét dinamikusan kell alakítani a felhasználói interakciók vagy az adatok változásai alapján. A layout tulajdonságainak módosítása futásidőben lehetőséget biztosít arra, hogy az alkalmazás rugalmasabban reagáljon a felhasználói igényekre, például a margók vagy egyéb elrendezési paraméterek módosításával.

A dinamikus UI kezelés tehát kulcsfontosságú eleme az Android fejlesztésnek, amely lehetővé teszi az alkalmazások számára, hogy rugalmasan alkalmazkodjanak a változó adatstruktúrákhoz és felhasználói igényekhez, anélkül hogy a felhasználói élményt hátrányosan befolyásolná.

Hogyan kezeljük az orientációt és forgatást az Android alkalmazásokban?

Az Android rendszeren az alkalmazásokban gyakran előfordul, hogy az eszköz orientációját figyelembe kell venni. Legyen szó akár a felhasználói élmény javításáról, akár egy adott funkcionalitás megvalósításáról, az orientációval való munka alapvető ismereteket igényel. A következő szakaszokban bemutatjuk, hogyan kezelhetjük az eszköz orientációját és forgatását, valamint hogyan hozhatunk létre animációkat, amelyek az eszköz állapotától függenek.

Az Android platform automatikusan kezeli az orientáció változását, például a képernyő elforgatása esetén újra betölti az alkalmazás elrendezését. Azonban számos olyan helyzet van, amikor ezt a viselkedést szeretnénk megakadályozni. Ebben az esetben az Android Manifest fájlban a következő attribútumot kell hozzáadni az Activity-hez:
android:configChanges="keyboardHidden|orientation|screenSize".

Ez a beállítás biztosítja, hogy az orientáció vagy a képernyőméret változása esetén a rendszer nem tölti újra automatikusan az elrendezést, hanem értesíti az alkalmazást az onConfigurationChanged() metóduson keresztül. Az orientáció változása tehát kézben tartható, és lehetőség van az alkalmazás viselkedésének szabályozására.

A konfigurációs változások figyelése, például a billentyűzet elrejtése, az orientáció vagy a képernyő méretének változása, nem helyettesíti a megfelelő állapotkezelést. Mivel az alkalmazás bármikor megszakítható vagy teljesen leállítható, fontos, hogy az alkalmazás állapotát megfelelően mentsük el. Ezzel kapcsolatban az első fejezetben, az Activities szakaszban részletesebben is szó esik a megfelelő állapotkezelésről.

Az aktuális orientáció lekérése

A legegyszerűbb módja annak, hogy meghatározzuk az eszköz aktuális orientációját, az alábbi kód használata:

java
int orientation = getResources().getConfiguration().orientation;

Ez a kód visszaad egy egész számot, amely az orientációt jelzi. Három lehetséges értéket kaphatunk:

  • Configuration.ORIENTATION_LANDSCAPE (vízszintes tájolás),

  • Configuration.ORIENTATION_PORTRAIT (függőleges tájolás),

  • Configuration.ORIENTATION_UNDEFINED (meghatározatlan orientáció).

A következő egyszerű alkalmazás segít a felhasználóknak ellenőrizni az orientációt egy gombnyomás segítségével. A MainActivity-ben hozzáadunk egy gombot, amely megjeleníti az aktuális orientációt:

java
public void checkOrientation(View view) {
int orientation = getResources().getConfiguration().orientation; switch (orientation) { case Configuration.ORIENTATION_LANDSCAPE: Toast.makeText(MainActivity.this, "ORIENTATION_LANDSCAPE", Toast.LENGTH_SHORT).show(); break; case Configuration.ORIENTATION_PORTRAIT: Toast.makeText(MainActivity.this, "ORIENTATION_PORTRAIT", Toast.LENGTH_SHORT).show(); break; case Configuration.ORIENTATION_UNDEFINED: Toast.makeText(MainActivity.this, "ORIENTATION_UNDEFINED", Toast.LENGTH_SHORT).show(); break; } }

Ez a kód egyszerűen beállítja a kívánt orientációt, és értesíti a felhasználót egy Toast üzenet segítségével. A programot futtatva, az orientáció változtatása az emulátorban (Ctrl + F11) az alkalmazás válaszként jelezni fogja az aktuális orientációt.

A forgatás lekérése

Amikor az eszköz orientációjával dolgozunk, egy másik fontos tényező a képek és videók rögzítése. A felvett képek gyakran elforgatásra kerülnek az eszköz orientációja vagy a fényképezési mód alapján. Ebben az esetben más módszert alkalmazhatunk a forgatás meghatározására:

java
int rotation = getWindowManager().getDefaultDisplay().getRotation();

A rotation értéke az alábbiak szerint alakulhat:

  • Surface.ROTATION_0,

  • Surface.ROTATION_90,

  • Surface.ROTATION_180,

  • Surface.ROTATION_270.

Ez a forgatási érték az eszköz normál orientációjától függ. Ha például egy táblagépen portré módban készítünk fényképet, akkor a forgatás értéke ROTATION_90 vagy ROTATION_270 lesz.

Animációk és az orientáció

A grafikai animációk és az orientáció kombinálása szoros kapcsolatban áll a felhasználói élmény javításával. Az Android platformon számos animációs rendszert használhatunk. A View Animation az eredeti animációs rendszer, amely egyszerűbb kódot igényel, de korlátozott animációs lehetőségekkel rendelkezik. Ezzel szemben a Property Animation sokkal rugalmasabb, mivel bármely objektum tulajdonságát animálhatjuk.

Az animációk használatakor fontos figyelembe venni a képernyő orientációját. Például, ha egy gombnyomásra animációt alkalmazunk, érdemes figyelni az orientáció változásait, hogy az animáció megfelelően jelenjen meg az eszköz képernyőjén. Az alábbi példa bemutatja, hogyan lehet egy egyszerű animációt létrehozni, amely "villant" egy nézetet:

java
Animation blink = AnimationUtils.loadAnimation(this, R.anim.blink); view.startAnimation(blink);

A blink.xml fájl a következő tartalommal rendelkezik:

xml
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500" android:fromAlpha="0.0" android:toAlpha="1.0" android:repeatCount="infinite" android:repeatMode="reverse"/>

Ez a kód egyszerű "villogó" animációt hoz létre, amely alkalmas arra, hogy interakcióra ösztönözze a felhasználót, például egy gombnyomásra.

A különböző animációs típusok, mint a Drawable Animation vagy az újabb Property Animation, biztosítják a szükséges rugalmasságot, hogy az alkalmazásunk vizuálisan vonzó legyen, miközben az orientációra és a forgatásra is figyelmet fordítunk. Az Android rendszerben minden animációnak saját sebességét és dinamikáját meghatározhatjuk az úgynevezett interpolátorok segítségével, amelyek a változás ütemét szabályozzák. Az interpolátorok segítenek abban, hogy az animáció természetesebbnek tűnjön, és jobban illeszkedjen a felhasználói élményhez.