Flutter: open-source nástroj na tvorbu UI a testovanie

Flutter patrí medzi najrýchlejšie rastúce frameworky, ktoré spájajú kreativitu vývojárov s efektivitou a moderným UI. Predstav si, že namiesto piatich rôznych tímov a jazykov ti stačí jeden – a výsledok beží na mobile, webe aj desktope. Zisti, prečo je Flutter taký populárny, ako funguje jeho architektúra a čo prináša do testovania aplikácií.

Flutter: open-source nástroj na tvorbu UI a testovanie
Flutter: open-source nástroj na tvorbu UI a testovanie

V článku sa dozvieš:

    Čo je Flutter a ako funguje?

    Flutter je open-source framework, s ktorým vytvoríš používateľské rozhranie pre mobily, web aj desktop – všetko z jednej kódovej bázy. Používa jazyk Dart a vlastný grafický engine napísaný v C++. Namiesto toho, aby využíval natívne komponenty operačných systémov, kreslí všetko sám cez knižnice Skia a Impeller. Výhodou je, že vďaka nemu obídeš množstvo problémov so štýlmi, správaním alebo výkonovými rozdielmi medzi Androidom, iOS alebo webom. Výsledkom je potom rýchla a konzistentná appka. Všetko beží v jednom procese bez sprostredkovania cez pomalý JS most.

    Predstav si, že máš vyvíjať novú funkciu v mobilnej appke a zároveň ju musíš dostať aj do webovej verzie, na macOS, Windows a časom dokonca napríklad aj do auta. Tradične na takúto úlohu treba viacero rôznych tímov – jeden pre Kotlin, druhý pre Swift, ďalší pre web – a skôr či neskôr sa objavia rozdiely medzi implementáciami či neustále rozchádzanie logiky. Práve kvôli takýmto problémom vznikol Flutter ako reakcia Googlu na roztrieštený vývoj pre rôzne platformy.

    Dve aplikácie, dvojnásobné starosti

    V praxi sa často stávalo, že firmy museli udržiavať dve natívne aplikácie – jednu pre Android a druhú pre iOS. Čo bolo samozrejme finančne aj organizačne náročné. Staršie hybridné riešenia ako Cordova síce umožnili zdieľať HTML a CSS, no výkon a prístup k platformovým funkciám dosť zaostával. Flutter to vyriešil celkom elegantne. Vlastný engine znamená nezávislosť od systému a „hot reload“ v rámci jazyka Dart umožňuje okamžite vidieť zmeny v kóde bez potreby reštartovať appku.

    Raketový rast a aktívna komunita

    Od svojho oficiálneho spustenia v roku 2018 Flutter výrazne narástol. Dnes má viac než 170 000 hviezdičiek na GitHub (stav máj 2025), predbehol React Native a Xamarin medzi najpoužívanejšími frameworkmi a pravidelne sa objavuje v prezentáciách na Google I/O. Komunita je tiež veľmi aktívna – na pub.dev nájdeš viac než 30 000 balíkov, pravidelne sa organizujú stretnutia a vývojári komunikujú tiež cez Slack či Discord.

    Flutter nie je len „populárny“, ale aj reálne používaný vo veľkých firmách v zahraničí i na Slovensku. Google Ads, Reflectly, BMW (v aplikácii My BMW), eBay Motors či Alibaba ho už nasadili do produkcie. Tieto firmy si vybrali Flutter najmä preto, že umožňuje zjednotiť vývoj – jeden tím, jeden jazyk, jedno UI, rovnaké animácie a žiadne duplicity.

    Pre teba to znamená, že ak sa rozhodneš naučiť Flutter, investuješ do technológie podporovanej Googlom, ktorá funguje na všetkých hlavných platformách – od Androidu a iOS až po Windows, macOS, Linux aj web. A vďaka vlastnému vykresľovaniu si nemusíš lámať hlavu s tým, či systém podporuje nový komponent. Flutter si ju nakreslí sám.

    Flutter nevznikol náhodou. Je odpoveďou na zložité vývojárske prostredie. Dnes je z neho plnohodnotná multiplatformová technológia, ktorá má čo ponúknuť aj v roku 2025.

    Základy frameworku a architektúra

    Základy frameworku a architektúra

    Ak chceš pochopiť, prečo Flutter vykresľuje používateľské rozhranie tak rýchlo a plynulo, musíš sa pozrieť na to, ako je v prvom rade navrhnutý. Flutter je rozdelený na 3 vrstvy, ktoré spolupracujú tak, aby výsledok vyzeral dobre a fungoval rýchlo bez ohľadu na platformu:

    • Na úplnom začiatku je engine (jadro systému), ktorý je napísaný v jazyku C++. Obsahuje grafickú knižnicu Skia (stará sa o kreslenie), nový vykresľovač Impeller (využíva moderné grafické rozhrania ako Vulkan alebo Metal) a runtime (spúšťa Dart kód). Engine sa snaží zabezpečiť, aby sa každý snímok vykreslil do 16 milisekúnd – inak by si si všimol „trhanie“.
    • O úroveň vyššie je samotný framework napísaný v programovacom jazyku Dart. V ňom sa nachádzajú všetky základné stavebné prvky. Či už ide o widgety, animácie, gestá, logika a ďalšie.
    • Najvyššiu vrstvu si tvoríš už ty. Každý komponent v rozhraní je widget, ktorý Flutter spracuje, zaradí do „stromu“ a prepočíta jeho umiestnenie a veľkosť.

    To všetko funguje deklaratívne. Ty len povieš, ako má výsledok vyzerať a nie, ako sa k nemu má Flutter dostať. Keď sa niečo v aplikácii zmení (napr. stav), Flutter vytvorí nový strom widgetov, porovná ho s predchádzajúcim a prekreslí iba to, čo sa zmenilo. Namiesto ručného hľadania elementov v DOM alebo natívnej architektúre funguje všetko automaticky, bez medzičlánkov.

    Flutter si navyše kreslí všetko sám, text, ikony a aj tiene. Nie je odkázaný na to, kedy Apple alebo Google pridajú nový komponent do svojich SDK. Vďaka tomu môžeš mať rovnaký dizajn na všetkých platformách – od Androidu až po iOS.

    Dart a jeho režimy

    Dart, teda jazyk, v ktorom sa Flutter píše, funguje v dvoch režimoch. Počas vývoja používa tzv. JIT režim (just-in-time), ktorý ti umožňuje už vyššie spomínaný „hot reload“,  teda vidieť zmeny v aplikácii okamžite, bez jej reštartovania. Keď však buduješ produkčnú verziu, kód sa prepočíta do natívneho strojového kódu (ARM64 alebo x86_64), takže spustenie je rýchle a všetko beží bez potreby JavaScript mosta. Dart má aj silné typovanie, bezpečnosť pred nulovými hodnotami a podporuje asynchrónne operácie cez „async/await“.

    Ako Flutter vykresľuje aplikácie?

    Renderovanie beží v dvoch vláknach – jedno vlákno vykonáva logiku jazyka Dart a vytvára tzv. strom vrstiev (LayerTree), druhé vlákno sa stará o samotné vykreslenie cez GPU. Vďaka tomu ťa ani zvýšená záťaž v appke nepripraví o plynulé animácie. Flutter dokonca umožňuje zložité výpočty presunúť do samostatných izolovaných procesov (tzv. izoláty), aby neblokovali hlavné vlákno.

    Na Androide využíva buď „FlutterSurfaceView“ alebo „FlutterTextureView“. Na iOS zase „FlutterViewController“, teda vytvorí si vlastné okno, do ktorého kreslí všetko sám. Natívne systémové prvky ako status bar alebo navigačné gestá sa riešia cez tzv. „platform channels“, teda komunikačné mosty medzi frameworkom Flutter a natívnym kódom. Keďže má Flutter svoj engine, vie bežať aj ako webová aplikácia, kde grafické príkazy premapuje na WebAssembly a kreslí cez HTML5.

    Môžeš v ňom vytvárať veľmi plynulé animácie, efekty a vrstvy, a to bez obmedzovania tým, čo ti povolí systém. Nevýhodou je, že výsledná appka je trochu väčšia. Dokonca aj jednoduché „Ahoj“ zaberie okolo 6 MB, pretože so sebou nesie celý runtime. Google však pracuje na mechanizme, ktorý umožní tento engine zdieľať medzi viacerými aplikáciami. Na úrovni API Flutter používa tzv. „composables“ – každý widget implementuje metódu „build()“, v ktorej vracia ďalšie widgety a z nich sa skladá celé UI.

    Príklad:

    // Ukážka vlastného renderovania: červený kruh meniteľný cez setState 
    class PulseDot extends LeafRenderObjectWidget { 
         final double radius; 
         const PulseDot({super.key, required this.radius});
         @override 
         RenderObject createRenderObject(BuildContext ctx) => 
    _RenderPulseDot(radius);
         @override 
         void updateRenderObject(BuildContext ctx, covariant _RenderPulseDot r) =>
         r.radius = radius; 
    }
    class _RenderPulseDot extends RenderBox { 
         double _radius; 
         _RenderPulseDot(this._radius);
         set radius(double v) { _radius = v; markNeedsPaint(); }
         @override 
         void performLayout() => 
              size = constraints.constrain(Size.square(_radius * 2));
         @override 
         void paint(PaintingContext c, Offset o) {
         final paint = Paint()..color = Colors.red; 
         c.canvas.drawCircle(o + Offset(_radius, _radius), _radius, paint); 
         } 
    }
    

    Vysvetlenie:

    „PulseDot“ je najnižší typ widgetu – LeafRenderObjectWidget. Vytvára _RenderPulseDot, ktorý dedí z RenderBox. V performLayout si sám určí veľkosť podľa polomeru a v paint priamo kreslí kruh na Canvas. Nevyužíva žiadny natívny komponent. Flutter engine prenesie inštrukciu do Skie a kruh sa objaví rovnako na Androide, iOS aj na webe. Keď vo widgete zmeníš radius cez setState, setter vytvorí markNeedsPaint() a framework prekreslí len dotknutú oblasť, čo ukazuje celý widget.

    Ako vyzerá vývoj v praxi?

    Pozrime sa krok za krokom na to, ako Flutter štartuje aplikáciu a ako sa skladá jej používateľské rozhranie.

    Spustenie aplikácie

    V rámci frameworku Flutter sa všetko točí okolo funkcie main(). Spúšťa sa pri štarte a ty v nej zavoláš runApp(). Tento príkaz zaregistruje koreňový widget a odovzdá ho renderovaciemu stromu. Od tej chvíle je celá obrazovka „výsledkom“ stromu, ktorý deklaratívne opisuješ v jazyku Dart. Namiesto klasického prístupu založeného na príkazoch typu „otvor aktivitu, nájdi view, zmeň text“ tu len skladáš widgety. Flutter vyhodnotí, ako sa má UI prekresliť.

    Koreňový widget a navigácia

    Najvyššiu úroveň tvorí koreňový widget (root), ktorý väčšinou dedí zo StatelessWidget alebo StatefulWidget.

    • StatelessWidget použiješ, keď sa hodnota vstupov nemení – typické sú ikonky, separátory či statické texty.
    • StatefulWidget nasadíš, ak komponent reaguje na interakciu alebo prichádzajúce dáta.

    Rozdiel je v tom, že StatefulWidget drží stav v triede „State“, ktorú môžeš meniť volaním setState(() { … }). Flutter v tom momente vytvorí novú vetvu widget stromu, porovná ju so starou a mení len tie render objekty, ktoré sa skutočne zmenili.

    Koreňový widget býva často MaterialApp alebo CupertinoApp. Okrem lokalizácie a smerovania definuje aj navigačný kontext. Navigáciu spravuje trieda Navigator, ktorá v pamäti drží Route objekty. Keď zavoláš Navigator.push, do zásobníka pribudne nová trasa a framework vykreslí cieľovú stránku: pri pop() sa vrátiš. Od Flutteru 3 môžeš použiť aj opisný GoRouter, ktorý mapuje URI na widgety a zjednodušuje hlbšie prelinkovania.

    Rozloženie a dizajn UI

    Systém rozloženia frameworku Flutter stojí na kombinácii flexibilných kontajnerov. Row a Column rozkladajú deti (child:…) v jednom smere, Expanded rozdelí voľný priestor, Flexible umožní podmieniť rast. Stack prekryje widgety podobne ako RelativeLayout v Androide, no s možnosťou definovať rôzne zarovnania a z-index. Všetky kontajnery sú relatívne jednoduché.

    Pretože UI píšeš deklaratívne (opisne), kód vyzerá ako hierarchia volaní konštruktorov. Nie je to reťaz príkazov, ale opis výsledného stavu.

    Dôležité je pochopiť, že Flutter neskladá UI z platformových pohľadov. Namiesto toho vytvára vlastné abstrakcie, ktoré potom renderuje na plátno. Preto sú animácie rovnako plynulé na Androide aj iOS a nemusíš riešiť rozdiely medzi dp a pt. Ak potrebuješ interagovať so systémovými API (Bluetooth, fotoaparát, in-app purchases,…), využiješ „platform channel“. Pomocou jazyka Dart zavoláš metódu, Flutter ju preloží na nativný kód Kotlinu alebo Swiftu a vráti odpoveď.

    Pre jednotnejší dizajn Flutter ponúka dve hotové sady: Material 3 a Cupertino. V praxi ich môžeš miešať – ak vyvíjaš primárne pre Android, no na iOS chceš natívny CupertinoPicker, jednoducho ho vložíš do stromu. Flutter sa postará o správne metriky aj pohybové krivky. Aktíva (obrázky, fonty, JSON) deklaruješ v pubspec.yaml. Pri builde CLI zabalí súbory do balíka a engine ich načíta v runtime z AssetBundle. Ak potrebuješ lokalizáciu, vytvoríš súbor arb a použiješ flutter gen-l10n.

    Príklad:

    void main() => runApp(const MyApp());
    
    class MyApp extends StatelessWidget {
    
    const MyApp({super.key});
    
    @override
    
    Widget build(BuildContext context) => MaterialApp(
    
    home: Scaffold(
    
    appBar: AppBar(title: const Text('Počítadlo')),
    
    body: const Center(child: Counter()),
    
    ),
    
    );
    
    }
    
    class Counter extends StatefulWidget {
    
    const Counter({super.key});
    
    @override
    
    State<Counter> createState() => _CounterState();
    
    }
    
    class _CounterState extends State<Counter> {
    
    int _value = 0;
    
    @override
    
    Widget build(BuildContext context) => Column(
    
    mainAxisAlignment: MainAxisAlignment.center,
    
    children: [
    
    Text(
    
    '$_value',
    
    style: Theme.of(context).textTheme.displayMedium,
    
    ),
    
    const SizedBox(height: 16),
    
    ElevatedButton(
    
    onPressed: () => setState(() => _value++),
    
    child: const Text('Pridať'),
    
    ),
    
    ],
    
    );
    
    }

    Vysvetlenie:

    MyApp je koreň aplikácie: vytvára MaterialApp a základný Scaffold. Widget Counter dedí z StatefulWidget, pretože drží meniacu sa hodnotu _value. Po stlačení tlačidla ElevatedButton sa spustí setState, Flutter vytvorí novú vetvu widget stromu, porovná zmeny a prekreslí len text s aktuálnym číslom. Výsledkom je jednoduchá, plne reaktívna obrazovka, ktorá demonštruje princíp runApp(), rozdiel medzi StatelessWidget a StatefulWidget a deklaratívny štýl tvorby UI.

    Multiplatformový vývoj

    Flutter ti umožňuje spúšťať ten istý Dart kód na všetkých hlavných platformách – Android, iOS, Windows,… Pri spustení vo webovom prehliadači sa Dart kód preloží do WebAssembly, ktoré je od verzie Flutter 3.22 stabilné. Na desktope zas Flutter využíva natívne knižnice daného systému – Win32 na Windows, Cocoa na macOS a GTK v Linuxe.

    Každá platforma má však svoje špecifiká. Na webe ťa obmedzuje izolované prostredie pre prácu so súbormi, pretože nemáš priamy prístup na disk ani ku klasickému súborovému systému. Na desktope zase Flutter nemá vstavané API na správu systémových oprávnení, ktoré poznáš z mobilných platforiem (napr. žiadosť o prístup k polohe).

    Keď si pomocou príkazového riadku frameworku Flutter (CLI) vytvoríš nový projekt, automaticky sa ti nastavia všetky hlavné cieľové platformy, na ktoré môžeš appku vyvíjať. Už v reálne zabehnutých aplikáciách firiem ako Toyota (Infotaintment) alebo BMW (v aplikácii My BMW) využívajú spoločnú kódovú bázu, pričom približne 90 % kódu je zdieľaných medzi všetkými platformami. Špecifiká jednotlivých platforiem riešia pomocou podmienok ako „Platform.isMacOS“ alebo cez FFI (Foreign Function Interface), ak potrebujú volať natívny kód priamo.

    Testovanie

    Flutter ponúka tri úrovne testovania, ktoré pokrývajú celý vývojový cyklus aplikácie:

    1. Unit testy sú určené na testovanie čistej logiky – teda funkcií, ktoré nevyžadujú žiadne UI alebo stav aplikácie. Používaš ich napríklad na overenie výpočtov, transformácií dát alebo spracovania vstupov.
    2. Druhou vrstvou sú widget testy, ktoré slúžia na testovanie jednotlivých komponentov používateľského rozhrania. Využíva sa pri nich balík flutter_test a funkcia testWidgets(). Táto metóda renderuje testovaný widget len v pamäti, bez reálneho zariadenia a umožňuje ti s ním manipulovať. Napríklad pomocou tester.tap() alebo tester.enterText(). Takto môžeš overiť, či sa widget správne správa pri konkrétnych vstupoch, či obsahuje požadovaný text, alebo či reaguje na používateľské akcie.
    3. Tretia úroveň integračné testy, ktoré testujú aplikáciu ako celok, od štartu až po reálne interakcie medzi obrazovkami. Spúšťajú sa na emulátoroch, fyzických zariadeniach alebo v cloudovej infraštruktúre ako napríklad Firebase Test Lab. Tieto testy používajú balík integration_test, ktorý umožňuje automatizovať kliky, posúvania či čakanie na widgety tak, ako by to robil koncový používateľ.

    Najväčší tromf frameworku je jednoznačne jedno UI pre všetky platformy a vyšší výkon vďaka vlastnému vykresľovaciemu enginu. Komunita rastie, pluginy pre Bluetooth, Stripe či Camera majú aktívny vývoj a open-source filozofia láka mnoho start-upov. Niektoré API (Apple Watch, Android Auto) však ešte stále nemajú oficiálny plugin. A hoci Flutter existuje sedem rokov, React Native má stále o niečo väčšie ekosystémové zázemie. Ostáva len čakať, akým smerom sa bude vývoj frameworku poberať naďalej.

    ZDROJE:

    • https://skedbooks.com/articles/sangeeta-k/flutter-framework-overview-key-features-benefits-components/
    • https://docs.flutter.dev/resources/architectural-overview
    • https://www.geeksforgeeks.org/flutter-architecture-application/
    • https://medium.com/@devab.me/top-5-reasons-to-choose-flutter-for-your-cross-platform-app-development-project-e1550f642a29

     

    O autorovi

    Michaela Kojnoková

    Agile Test Engineer

    Po štúdiu informatiky na ŽU a TUKE som sa najviac ponorila do oblasti automatizácie testovania. Okrem toho sa venujem tvorbe webov, databázam, dátovej analytike, umelej inteligencii a strojovému učeniu. Mám rada cestovanie, šport a najviac si užívam čas strávený v prírode s mojimi blízkymi. LinkedIn

    Daj nám o sebe vedieť