Animování aplikací pomocí Flutteru
O autorovi
Přes den vývojář softwaru a v noci vývojář mobilních aplikací. Když nepracuji, rád vařím a hraji počítačové hry.Více oShubham↬
- 14 minut čtení
- Aplikace,animace
- Uloženo pro offline čtení
- Sdílet na Twitteru, LinkedIn
Aplikace pro jakoukoli platformu jsou chváleny, když jsou intuitivní, dobře vypadají a poskytují příjemnou zpětnou vazbu na interakce s uživatelem. Jedním ze způsobů, jak toho dosáhnout, je animace.
Flutter, multiplatformní framework, v posledních dvou letech dozrál a zahrnuje podporu webu i stolních počítačů. Získal si pověst, že aplikace s ním vytvořené jsou plynulé a dobře vypadající. Díky bohaté podpoře animací, deklarativnímu způsobu psaní uživatelského rozhraní, funkci „Hot Reload“ a dalším funkcím je nyní kompletním multiplatformním frameworkem.
Pokud s Flutterem začínáte a chcete se naučit netradiční způsob přidávání animací, pak jste na správném místě: prozkoumáme oblast animací a motion widgetů, implicitního způsobu přidávání animací.
Flutter je založen na konceptu widgetů. Každá vizuální součást aplikace je widget – představte si je jako pohledy v systému Android. Flutter poskytuje podporu animací pomocí třídy Animation, objektu „AnimationController“ pro správu a „Tween“ pro interpolaci rozsahu dat. Tyto tři komponenty spolupracují a zajišťují plynulou animaci. Protože to vyžaduje ruční vytváření a správu animace, označuje se to jako explicitní způsob animace.
Nyní vás seznámím s animací a widgety pohybu. Flutter poskytuje řadu widgetů, které ze své podstaty podporují animaci. Není třeba vytvářet objekt animace ani žádný řadič, protože veškerou animaci obstarává tato kategorie widgetů. Stačí vybrat vhodný widget pro požadovanou animaci a předat mu hodnoty vlastností, které má animovat. Tato technika představuje implicitní způsob animace.
Ve výše uvedeném grafu je zhruba uvedena hierarchie animací ve Flutteru, jak jsou podporovány explicitní i implicitní animace.
Některé z animovaných widgetů, kterými se tento článek zabývá, jsou:
AnimatedOpacity
AnimatedCrossFade
AnimatedAlign
AnimatedPadding
AnimatedSize
-
AnimatedPositioned
.
Flutter poskytuje nejen předdefinované animované widgety, ale také obecný widget s názvem AnimatedWidget
, který lze použít k vytvoření vlastních implicitně animovaných widgetů. Jak je patrné z názvu, tyto widgety patří do kategorie animovaných a pohybových widgetů, a mají tedy některé společné vlastnosti, které nám umožňují vytvářet animace mnohem plynulejší a lépe vypadající.
Nechte mě nyní tyto společné vlastnosti vysvětlit, protože je budeme později používat ve všech příkladech.
-
duration
Doba trvání, po kterou se mají parametry animovat. -
reverseDuration
Doba trvání zpětné animace. -
curve
Křivka, která se má při animaci parametrů použít. Interpolované hodnoty mohou být převzaty z lineárního rozdělení nebo, pokud a kdy je to zadáno, mohou být převzaty z křivky.
Začněme cestu vytvořením jednoduché aplikace, kterou nazveme „Citace“. Ta bude při každém spuštění aplikace zobrazovat náhodný citát. Je třeba si uvědomit dvě věci: za prvé, všechny tyto citáty budou v aplikaci pevně zakódovány; a za druhé, nebudou se ukládat žádná uživatelská data.
Poznámka: Všechny soubory pro tyto příklady najdete na GitHubu.
Začínáme
Flutter by měl být nainstalován a než budete pokračovat, budete se muset seznámit se základním průběhem. Dobrým začátkem je kniha „Using Google’s Flutter For Truly Cross-Platform Mobile Development“.
Vytvořte nový projekt Flutter v aplikaci Android Studio.
Otevře se průvodce novým projektem, kde můžete nastavit základy projektu.
Na obrazovce výběru typu projektu jsou k dispozici různé typy projektů Flutter, z nichž každý vyhovuje určitému scénáři. Pro tento výukový program vyberte možnost Flutter Application a stiskněte tlačítko Next.
Nyní je třeba zadat některé specifické informace o projektu: název a cestu k projektu, doménu společnosti atd. Podívejte se na následující obrázek.
Přidejte název projektu, cestu k Flutter SDK, umístění projektu a volitelný popis projektu. Stiskněte tlačítko Další.
Každá aplikace (ať už pro Android nebo iOS) vyžaduje jedinečný název balíčku. Obvykle se používá obrácený název domény vaší webové stránky; například com.google nebo com.yahoo. Stisknutím tlačítka Dokončit vygenerujete funkční aplikaci Flutter.
Po vygenerování projektu byste měli vidět výše uvedenou obrazovku. Otevřete soubor main.dart (zvýrazněný na obrázku). Jedná se o hlavní soubor aplikace. Ukázkový projekt je sám o sobě kompletní a lze jej spustit přímo na emulátoru nebo fyzickém zařízení bez jakýchkoli úprav.
Nahraďte obsah souboru main.dart následujícím úryvkem kódu:
import 'package:animated_widgets/FirstPage.dart';import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Animated Widgets', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.blue, accentColor: Colors.redAccent, ), home: FirstPage(), ); }}
Tento kód vyčistí soubor main.dart pouze přidáním jednoduchých informací důležitých pro vytvoření nové aplikace. Třída MyApp vrací objekt: MaterialApp
widget, který poskytuje základní strukturu pro vytváření aplikací odpovídajících Material Designu. Aby byl kód strukturovanější, vytvořte dva nové soubory dart uvnitř složky lib: FirstPage.dart a Quotes.dart.
Soubor FirstPage.dart bude obsahovat veškerý kód zodpovědný za všechny vizuální prvky (widgety) potřebné pro naši aplikaci Citace. V tomto souboru se zpracovává veškerá animace.
Poznámka: Později v článku jsou do tohoto souboru přidány všechny úryvky kódu pro jednotlivé animované widgety jako děti widgetu Scaffold. Pro více informací může být užitečný tento příklad na GitHubu.
Začněte přidáním následujícího kódu do souboru FirstPage.dart. Jedná se o částečný kód, do kterého budou později přidány další věci.
import 'dart:math';import 'package:animated_widgets/Quotes.dart';import 'package:flutter/material.dart';class FirstPage extends StatefulWidget { @override State createState() { return FirstPageState(); }}class FirstPageState extends State with TickerProviderStateMixin { bool showNextButton = false; bool showNameLabel = false; bool alignTop = false; bool increaseLeftPadding = false; bool showGreetings = false; bool showQuoteCard = false; String name = ''; double screenWidth; double screenHeight; String quote; @override void initState() { super.initState(); Random random = new Random(); int quoteIndex = random.nextInt(Quotes.quotesArray.length); quote = Quotes.quotesArray; } @override Widget build(BuildContext context) { screenWidth = MediaQuery.of(context).size.width; screenHeight = MediaQuery.of(context).size.height; return Scaffold( appBar: _getAppBar(), body: Stack( children: , ), ); }}
Soubor Quotes.dart obsahuje seznam všech pevně zadaných citátů. Zde je třeba upozornit na to, že seznam je statický objekt. To znamená, že jej lze použít na jiných místech, aniž by bylo nutné vytvářet nový objekt třídy Quotes. To je zvoleno záměrně, protože výše uvedený seznam funguje pouze jako utilita.
Přidejte do tohoto souboru následující kód:
class Quotes { static const quotesArray = ;}
Kostra projektu je nyní hotová, pojďme tedy Citace ještě trochu doplnit.
AnimatedOpacity
Abychom aplikaci dodali osobní nádech, bylo by dobré znát jméno uživatele, takže se na něj zeptáme a zobrazíme tlačítko další. Dokud uživatel nezadá své jméno, je toto tlačítko skryté a po zadání jména se elegantně zobrazí. Potřebujeme nějakou animaci viditelnosti tlačítka, ale existuje na to nějaký widget? Ano, existuje.
Enter AnimatedOpacity
. Tento widget navazuje na widget Neprůhlednost přidáním implicitní podpory animace. Jak jej můžeme použít? Vzpomeňte si na náš scénář: potřebujeme zobrazit tlačítko Další s animovanou viditelností. Zabalíme widget tlačítka dovnitř widgetu AnimatedOpacity
, vložíme do něj několik správných hodnot a přidáme podmínku pro spuštění animace – a Flutter se postará o zbytek.
_getAnimatedOpacityButton() { return AnimatedOpacity( duration: Duration(seconds: 1), reverseDuration: Duration(seconds: 1), curve: Curves.easeInOut, opacity: showNextButton ? 1 : 0, child: _getButton(), );}
Widget AnimatedOpacity
má dvě povinné vlastnosti:
-
opacity
Hodnota 1 znamená zcela viditelný; 0 (nula) znamená skrytý. Při animaci Flutter interpoluje hodnoty mezi těmito dvěma extrémy. Vidíte, jak je umístěna podmínka, která změní viditelnost, a tím spustí animaci. -
child
Dětský widget, jehož viditelnost bude animována.
Teď byste měli pochopit, jak je opravdu jednoduché přidat animaci viditelnosti pomocí implicitního widgetu. A všechny takové widgety se řídí stejnými pravidly a jsou snadno použitelné. Přejděme k dalšímu.
AnimatedCrossFade
Máme jméno uživatele, ale widget stále čeká na vstup. V předchozím kroku, jakmile uživatel zadá své jméno, zobrazíme tlačítko další. Nyní, když uživatel stiskne tlačítko, chci přestat přijímat vstup a zobrazit zadané jméno. Existuje samozřejmě mnoho způsobů, jak to udělat, ale třeba můžeme widget vstupu skrýt a zobrazit neupravitelný textový widget. Vyzkoušíme to pomocí widgetu AnimatedCrossFade
.
Tento widget vyžaduje dvě děti, protože widget mezi nimi přechází na základě nějaké podmínky. Při použití tohoto widgetu je třeba mít na paměti jednu důležitou věc: oba potomci by měli mít stejnou šířku. Pokud se výška liší, pak se vyšší widget ořízne odspodu. V tomto scénáři budou jako děti použity dva widgety: input a label.
_getAnimatedCrossfade() { return AnimatedCrossFade( duration: Duration(seconds: 1), alignment: Alignment.center, reverseDuration: Duration(seconds: 1), firstChild: _getNameInputWidget(), firstCurve: Curves.easeInOut, secondChild: _getNameLabelWidget(), secondCurve: Curves.easeInOut, crossFadeState: showNameLabel ? CrossFadeState.showSecond : CrossFadeState.showFirst, );}
Tento widget vyžaduje jinou sadu povinných parametrů:
-
crossFadeState
Tento stav vyřeší, které dítě se má zobrazit. -
firstChild
Určuje první dítě pro tento widget. -
secondChild
Určuje druhé dítě.
AnimatedAlign
V tomto okamžiku je popisek s názvem umístěn na střed obrazovky. Nahoře bude vypadat mnohem lépe, protože potřebujeme, aby se uprostřed obrazovky zobrazovaly uvozovky. Jednoduše řečeno, zarovnání widgetu popisku jména by mělo být změněno ze středu na vrchol. A nebylo by hezké tuto změnu zarovnání animovat spolu s předchozí animací křížového prolínání? Pojďme na to.
Jako vždy lze k dosažení tohoto cíle použít několik technik. Vzhledem k tomu, že widget se jmenovkou je již zarovnán na střed, animace jeho zarovnání by byla mnohem jednodušší než manipulace s hodnotami horního a levého okraje widgetu. Widget AnimatedAlign
je pro tuto práci ideální.
Pro spuštění této animace je zapotřebí spouštěč. Jediným účelem tohoto widgetu je animovat změnu zarovnání, takže má jen několik vlastností: přidat potomka, nastavit jeho zarovnání, spustit změnu zarovnání a to je vše.
_getAnimatedAlignWidget() { return AnimatedAlign(duration: Duration(seconds: 1),curve: Curves.easeInOut,alignment: alignTop ? Alignment.topLeft : Alignment.center,child: _getAnimatedCrossfade(), );}
Má pouze dvě povinné vlastnosti:
- dítě:
Dítě, jehož zarovnání bude změněno. - zarovnání:
Požadovaná hodnota zarovnání.
Tento widget je opravdu jednoduchý, ale výsledky jsou elegantní. Navíc jsme viděli, jak snadno můžeme pomocí dvou různých animovaných widgetů vytvořit složitější animaci. V tom je krása animovaných widgetů.
AnimatedPadding
Nyní máme jméno uživatele v horní části plynule animované bez větší námahy pomocí různých druhů animovaných widgetů. Před jméno přidáme pozdrav „Ahoj“. Přidáním textového widgetu s hodnotou „Ahoj,“ v horní části dojde k překrytí textového widgetu pozdravu, což bude vypadat jako na obrázku níže.
Co kdyby měl textový widget jména vlevo nějaký padding? Zvětšení paddingu vlevo bude určitě fungovat, ale počkejte: můžeme zvětšit padding pomocí nějaké animace? Ano, a právě to dělá AnimatedPadding
. Aby to celé vypadalo mnohem lépe, nechme widget s textem pozdravu vyblednout a zároveň zvětšit výplň widgetu s textem jména.
_getAnimatedPaddingWidget() { return AnimatedPadding( duration: Duration(seconds: 1), curve: Curves.fastOutSlowIn, padding: increaseLeftPadding ? EdgeInsets.only(left: 28.0) : EdgeInsets.only(left: 0), child: _getAnimatedCrossfade(), );}
Protože výše uvedená animace by měla nastat až po dokončení předchozího animovaného zarovnání, musíme spuštění této animace odložit. Odbočíme-li krátce od tématu, je to vhodná chvíle, abychom si pověděli o oblíbeném mechanismu přidávání zpoždění. Flutter poskytuje několik takových technik, ale konstruktor Future.delayed je jedním z jednodušších, čistších a čitelnějších přístupů. Například pro spuštění kusu kódu po 1 sekundě:
Future.delayed(Duration(seconds: 1), (){ sum = a + b; // This sum will be calculated after 1 second. print(sum);});
Protože je již známa doba trvání zpoždění (vypočítaná z předchozích dob trvání animace), lze animaci spustit po tomto intervalu.
// Showing "Hi" after 1 second - greetings visibility trigger._showGreetings() { Future.delayed(Duration(seconds: 1), () { setState(() { showGreetings = true; }); });}// Increasing the padding for name label widget after 1 second - increase padding trigger._increaseLeftPadding() { Future.delayed(Duration(seconds: 1), () { setState(() { increaseLeftPadding = true; }); });}
Tento widget má pouze dvě povinné vlastnosti:
-
child
Dítě uvnitř tohoto widgetu, na které bude aplikováno padding. -
padding
Velikost přidávaného prostoru.
AnimatedSize
Dnes každá aplikace, která má nějaký druh animace, zahrnuje zvětšování nebo zmenšování vizuálních komponent, aby upoutala pozornost uživatele (běžně se nazývá animace škálování). Proč nepoužít stejnou techniku i zde? Můžeme uživateli zobrazit motivační citát, který se přiblíží ze středu obrazovky. Představím vám widget AnimatedSize
, který umožňuje efekty přiblížení a oddálení ovládané změnou velikosti jeho potomka.
Tento widget se od ostatních trochu liší, pokud jde o požadované parametry. Potřebujeme to, co Flutter nazývá „Ticker“. Flutter má metodu, která dává objektům vědět, kdykoli je spuštěna událost nového snímku. Lze si ji představit jako něco, co vyšle signál: „Udělej to teď! … Udělej to teď! … Udělej to teď! …“
Widget AnimatedSize
vyžaduje vlastnost – vsync – která akceptuje zprostředkovatele tickeru. Nejjednodušší způsob, jak získat poskytovatele tickeru, je přidat do třídy Mixin. Existují dvě základní implementace poskytovatele tickerů: SingleTickerProviderStateMixin
, který poskytuje jeden ticker, a TickerProviderStateMixin
, který jich poskytuje několik.
Výchozí implementace tickeru se používá k označení snímků animace. V tomto případě je použita druhá z nich. Více o mixinech.
// Helper method to create quotes card widget._getQuoteCardWidget() { return Card( color: Colors.green, elevation: 8.0, child: _getAnimatedSizeWidget(), );}// Helper method to create animated size widget and set its properties._getAnimatedSizeWidget() { return AnimatedSize( duration: Duration(seconds: 1), curve: Curves.easeInOut, vsync: this, child: _getQuoteContainer(), );}// Helper method to create the quotes container widget with different sizes._getQuoteContainer() { return Container( height: showQuoteCard ? 100 : 0, width: showQuoteCard ? screenWidth - 32 : 0, child: Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: Text(quote, style: TextStyle(color: Colors.white, fontWeight: FontWeight.w400, fontSize: 14),), ), ), );}// Trigger used to show the quote card widget._showQuote() { Future.delayed(Duration(seconds: 2), () { setState(() { showQuoteCard = true; }); });}
Povinné vlastnosti tohoto widgetu:
-
vsync
Potřebný zprostředkovatel tickeru pro koordinaci animace a změn snímků.< -
child
Dítě, jehož změny velikosti budou animovány.
Animace přiblížení a oddálení je nyní snadno zkrotitelná.
AnimatedPositioned
Skvělé! Citace se zvětšují od středu, aby upoutaly pozornost uživatele. Co kdyby se při přiblížení posouvaly odspodu nahoru? Zkusme to. Tento pohyb zahrnuje hraní si s pozicí widgetu citace a animaci změn vlastností pozice. Ideálním kandidátem je widget AnimatedPositioned
.
Tento widget automaticky přechází na pozici dítěte po danou dobu, kdykoli se zadaná pozice změní. Jedna poznámka: funguje pouze v případě, že jeho rodičovský widget je „zásobník“. Tento widget je poměrně jednoduchý a přímočarý na používání. Podívejme se na to.
// Helper method to create the animated positioned widget.// With position changes based on "showQuoteCard" flag._getAnimatedPositionWidget() { return AnimatedPositioned( duration: Duration(seconds: 1), curve: Curves.easeInOut, child: _getQuoteCardWidget(), top: showQuoteCard ? screenHeight/2 - 100 : screenHeight, left: !showQuoteCard ? screenWidth/2 : 12, );}
Tento widget má pouze jednu povinnou vlastnost:
-
child
Widget, jehož pozice se bude měnit.
Pokud se neočekává, že se spolu s pozicí dítěte bude měnit i jeho velikost, je výkonnější alternativou tohoto widgetu SlideTransition
.
Tady je naše kompletní animace:
Závěr
Animace jsou nedílnou součástí uživatelského prostředí. Statické aplikace nebo aplikace s nepovedenými animacemi nejenže snižují retenci uživatelů, ale také pověst vývojáře, který je schopen přinášet výsledky.
Dnes má většina populárních aplikací nějakou jemnou animaci, která uživatele potěší. Animovaná zpětná vazba na požadavky uživatelů je také může zaujmout k dalšímu zkoumání. Flutter nabízí spoustu funkcí pro vývoj napříč platformami, včetně bohaté podpory plynulých a citlivých animací.
Flutter má skvělou podporu zásuvných modulů, která nám umožňuje používat animace od jiných vývojářů. Nyní, když dozrál do verze 1.9, s takovou láskou od komunity, bude Flutter v budoucnu určitě ještě lepší. Řekl bych, že teď je skvělý čas naučit se Flutter!
Leave a Reply