Keys, azaz Kulcsok alatt nem lakás- vagy slusszkulcsot értek, hanem azokat a paramétereket, tulajdonságokat, amiket a Flutterben használunk.
Ilyen például a konstruktorokban is a {super.key}, vagy akár a Dismissable widget posztban levő kulcsok is.
Kulcsok nélkül
A Widget- és az Element Tree koncepciójából kiindulva világos, hogy minden widgethez tartozik egy elem (element) az Element fán.
Tegyük fel, hogy van egy listánk, aminek a sorrendjét megváltoztatjuk:
Fontos, hogy ez most egy StatelessWidget belsejében van!
A Flutter a hatékony működés érdekében, amikor a képernyőt frissíti, akkor nem hozza létre újra az egyes elemeket, hanem felhasználja, a már létezőket. Ez a működés elég logikus, hiszen valóban nincs szó új elemekről, a képernyőn csak a sorrendjüket kell megváltoztatni. Amit viszont a Flutternek észben kell tartania, hogy az Element fán melyik elemhez melyik widget tartozik. A Flutter a háttérben csak az elemek hivatkozásait frissíti. Ami azt is jelenti, hogy az elemek sorrendje nem változik meg ugyanúgy az Element fán, mint ahogy a widgeteké a Widget fán!
A könnyebb megértés kedvéért itt van a kódja egyetlen sorocskának:
Row(
children: [
Icon(icon),
const SizedBox(width: 12),
Text(text),
],
),
A Row widgeten belül van egy Icon widget, egy Text widget, valamint a kettő között egy SizedBox widget a két widget távolságának beállítása miatt.
Tehát amikor a sorok sorrendjét változtatjuk, akkor a Flutternek ezt a három összetartozó widgetet (amit a Row fog egy csoportba), együttesen kell tudnia mozgatni.
És ezzel semmi gond nincs, mert a Flutter mindent kézben tart.
Miért kellenek a kulcsok?
Más lesz azonban a helyzet, ha a játékba bevonunk egy jelölőnégyzetet (checkbox) is, illetve azt is kiemelném, hogy ezúttal StatefulWidget-et használtunk:
Amikor sorrendet változtatunk, akkor a checkbox marad a helyén, de az elemek sorrendje változik. Olyan, mintha a checkbox nem tudná, hogy melyik sorhoz tartozik.
Az ok, hogy a state-ek kezelése másképpen történik:
A state-ek a helyükön maradtak. Na, de miért?
Az egyes widgetekhez (sorokhoz) tartozó state objektumok, független objektumokként vannak kezelve, amik nem a widgethez vannak kötve a háttérben, hanem az Element fán lógó elemekhez. Ezt a függőséget mutatják a nyilak is a fenti ábrán.
Tehát a state nem mozog együtt a widgettel a fán belül. És akkor most jöhetnek a kulcsok (keys), amik megoldják a fenti problámát. Ugyanis, amikor kulcsokat adunk a lista elemekhez a widgeten belül, akkor ezek a kulcsok hozzáadódnak az element fán is a widgethez tartozó elemhez:
A Key segítségével a Flutter tudni fogja, hogy melyik state melyik widgethez tartozik (mivel a key megjelenik az element fán a widgethez tartozó elemnél is).
Kulcsok a kódban
Amikor a lista elemeket ciklussal feldolgozzuk, akkor adjuk hozzá a key paramétert is:
Column(
children: [
// for (final todo in _orderedTodos) TodoItem(todo.text, todo.priority),
for (final todo in _orderedTodos)
CheckableTodoItem(
key:
todo.text,
todo.priority,
),
],
),
Két fajta kulcsot szoktunk tipikusan használni.
- Az egyik a ValueKey(). A Dismissible widget posztban volt róla már szó. A ValueKey egy bármilyen típusú értéket vár. Ezért dinamikus típussal rendelkezik. Ezt a Flutter belsőleg használja azonosításra. A fontos természetesen az, hogy egy listán belül egyedi legyen a kulcs minden listaelemre nézve. Most például lehet használni ezt is:
key: ValueKey(todo.text)
Mert ez esetben a szöveg egyedinek számít.
- Másik alternatívaként tudunk használni kulcsként egy objektum kulcsot is az ObjectKey-el, ami a teljes objektumot várja kulcsként:
key: ObjectKey(todo)
Persze ebből talán azt is sejthető, hogy teljesítmény szempontjából az Objectkey használata „megterhelőbb” a rendszernek, hiszen kulcsként az egész objektumot használjuk. Tehát emiatt inkább a ValueKey használata javasolt.
Mégegyszer, ami fontos, hogy a kulcsok egyediek legyenek és kapcsolódjanak az objektumhoz (lista elemhez). Ne legyen például valamilyen véletlenszám a kulcs. Általában a listaelemek, mint objektumok mindig rendelkeznek valamilyen ID nevezetű mezővel. Erre persze tervezési időben kell odafigyelni, ez tehát a mi felelősségünk.
A kulcsok bevetésével már a State-ek is mozognak és a checkboxok is jó helyre kerülnek: