Animating Apps With Flutter
A szerzőről
Nappal full stack szoftverfejlesztő, éjjel mobilalkalmazás-fejlesztő. Amíg nem dolgozom, szeretek főzni és PC-s játékokkal játszani.További információShubham↬
- 14 perc olvasás
- Alkalmazások,animáció
- Off-line olvasásra mentve
- Megosztás Twitteren, LinkedIn
A bármilyen platformra készült alkalmazásokat dicsérik, ha intuitívak, jól néznek ki, és kellemes visszajelzést adnak a felhasználói interakciókról. Az animáció az egyik módja ennek.
A Flutter, egy platformokon átívelő keretrendszer, az elmúlt két évben megérett a webes és asztali támogatásra. Hírnevet szerzett arról, hogy a vele fejlesztett alkalmazások simák és jól néznek ki. Gazdag animáció-támogatásával, a felhasználói felület megírásának deklaratív módjával, a “Hot Reload”-al és más funkciókkal mára egy teljes körű, platformokon átívelő keretrendszerré vált.
Ha a Flutterrel kezdesz, és az animáció hozzáadásának egy nem szokványos módját szeretnéd megtanulni, akkor jó helyen jársz: az animáció és a motion widgetek birodalmát, az animációk hozzáadásának egy implicit módját fogjuk felfedezni.
A Flutter a widgetek koncepciójára épül. Az alkalmazás minden egyes vizuális összetevője egy widget – gondolj rájuk úgy, mint az Androidban a nézetekre. A Flutter animációs támogatást nyújt egy Animation osztály, egy “AnimationController” objektum a kezeléshez, és egy “Tween” segítségével a tartomány interpolálásához. Ez a három komponens együtt dolgozik, hogy sima animációt biztosítson. Mivel ehhez manuálisan kell létrehozni és kezelni az animációt, az animáció explicit módjának nevezik.
Most hadd mutassam be az animációt és a mozgás widgeteket. A Flutter számos olyan widgetet biztosít, amelyek eredendően támogatják az animációt. Nincs szükség animációs objektum vagy bármilyen vezérlő létrehozására, mivel az összes animációt a widgetek ezen kategóriája kezeli. Csak válasszuk ki a megfelelő widgetet a kívánt animációhoz, és adjuk át a widget tulajdonságainak értékeit az animációhoz. Ez a technika az animáció implicit módja.
A fenti táblázat nagyjából meghatározza az animációs hierarchiát a Flutterben, hogy mind az explicit, mind az implicit animáció támogatott.
A cikkben tárgyalt animált widgetek közül néhány:
AnimatedOpacity
AnimatedCrossFade
AnimatedAlign
AnimatedPadding
AnimatedSize
-
AnimatedPositioned
.
A Flutter nem csak előre definiált animált widgeteket biztosít, hanem egy AnimatedWidget
nevű általános widgetet is, amely egyedi, implicit módon animált widgetek létrehozására használható. Mint a nevükből is kitűnik, ezek a widgetek az animált és mozgó widgetek kategóriájába tartoznak, így van néhány közös tulajdonságuk, amelyekkel sokkal simább és jobban kinéző animációkat készíthetünk.
Hadd magyarázzam el most ezeket a közös tulajdonságokat, mivel később minden példában használni fogjuk őket.
-
duration
Az időtartam, amely alatt a paramétereket animálni kell. -
reverseDuration
A fordított animáció időtartama. -
curve
A paraméterek animálásakor alkalmazandó görbe. Az interpolált értékek lineáris eloszlásból vagy, ha és amennyiben meg van adva, egy görbéből is vehetők.
Kezdjük az utazást egy egyszerű alkalmazás létrehozásával, amelyet “Idézett” néven fogunk hívni. Ez egy véletlenszerű idézetet fog megjeleníteni minden alkalommal, amikor az alkalmazás elindul. Két dolgot kell megjegyeznünk: először is, az összes ilyen idézet keményen kódolva lesz az alkalmazásban; másodszor, semmilyen felhasználói adat nem kerül elmentésre.
Megjegyzés: A példák összes fájlja megtalálható a GitHubon.
Kezdés
A Fluttert telepíteni kell, és a folytatás előtt meg kell ismernünk az alapfolyamatot. Jó kiindulópont a “Using Google’s Flutter For Truly Cross-Platform Mobile Development” című könyv.
Új Flutter projekt létrehozása az Android Studio-ban.
Ez megnyitja az új projekt varázslót, ahol beállíthatja a projekt alapjait.
A projekttípus kiválasztó képernyőn különböző típusú Flutter projektek vannak, amelyek mindegyike egy adott forgatókönyvnek felel meg… Ehhez a bemutatóhoz válassza a Flutter-alkalmazást, majd nyomja meg a Tovább gombot.
Ezután meg kell adnia néhány projektspecifikus információt: a projekt nevét és elérési útvonalát, a vállalati tartományt stb. Nézze meg az alábbi képet.
Adja meg a projekt nevét, a Flutter SDK elérési útját, a projekt helyét és egy opcionális projektleírást. Nyomja meg a Tovább gombot.
Minden alkalmazás (legyen az Android vagy iOS) egyedi csomagnevet igényel. Általában a weboldal domainjének fordítottját használja; például com.google vagy com.yahoo. Nyomja meg a Befejezés gombot a működő Flutter alkalmazás létrehozásához.
A projekt generálása után a fenti képernyőt kell látnia. Nyissa meg a main.dart fájlt (a képernyőképen kiemelve). Ez a fő alkalmazásfájl. A mintaprojekt önmagában teljes, és módosítás nélkül közvetlenül futtatható emulátoron vagy fizikai eszközön.
A main.dart fájl tartalmát a következő kódrészlettel cserélje ki:
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(), ); }}
Ez a kód megtisztítja a main.dart fájlt, és csak egyszerű, az új alkalmazás létrehozásához szükséges információkat ad hozzá. A MyApp osztály egy objektumot ad vissza: egy MaterialApp
widgetet, amely az alapvető struktúrát biztosítja a Material Designnak megfelelő alkalmazások létrehozásához. A kód strukturáltabbá tételéhez hozzon létre két új dart fájlt a lib mappán belül: FirstPage.dart és Quotes.dart.
A FirstPage.dart tartalmazza majd a Quoted alkalmazásunkhoz szükséges összes vizuális elemért (widgetekért) felelős kódot. Az összes animációt ebben a fájlban kezeljük.
Megjegyzés: A cikk későbbi részében az egyes animált widgetek összes kódrészlete a Scaffold widget gyermekeiként kerül ebbe a fájlba. További információért hasznos lehet ez a példa a GitHubon.
Kezdje a következő kód hozzáadásával a FirstPage.dart fájlhoz. Ez a részleges kód, amelybe később más dolgok is bekerülnek.
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: , ), ); }}
A Quotes.dart fájl tartalmazza az összes keményen kódolt idézet listáját. Itt érdemes megjegyezni, hogy a lista egy statikus objektum. Ez azt jelenti, hogy más helyeken is felhasználható anélkül, hogy új objektumot hoznánk létre a Quotes osztályból. Ezt eleve így választottuk, mivel a fenti lista egyszerűen csak segédprogramként funkcionál.
Adjuk hozzá a következő kódot ehhez a fájlhoz:
class Quotes { static const quotesArray = ;}
A projekt váza most már készen áll, tehát konkretizáljuk még egy kicsit az Idézeteket.
AnimatedOpacity
Az alkalmazásnak személyes jelleget kölcsönözve jó lenne tudni a felhasználó nevét, ezért kérdezzük meg és jelenítsünk meg egy tovább gombot. Amíg a felhasználó nem adja meg a nevét, addig ez a gomb el van rejtve, és a név megadásakor elegánsan megjelenik. Szükségünk van valamilyen láthatósági animációra a gombhoz, de van erre valamilyen widget? Igen, van.
Enter AnimatedOpacity
. Ez a widget az Opacity widgetre épül az implicit animációs támogatás hozzáadásával. Hogyan használjuk? Emlékezzünk a forgatókönyvünkre: egy következő gombot kell megjelenítenünk animált láthatósággal. Becsomagoljuk a gomb widgetet a AnimatedOpacity
widgetbe, betáplálunk néhány megfelelő értéket és hozzáadunk egy feltételt az animáció elindításához – a többit pedig a Flutter elintézi.
_getAnimatedOpacityButton() { return AnimatedOpacity( duration: Duration(seconds: 1), reverseDuration: Duration(seconds: 1), curve: Curves.easeInOut, opacity: showNextButton ? 1 : 0, child: _getButton(), );}
A AnimatedOpacity
widgetnek két kötelező tulajdonsága van:
-
opacity
Az 1 érték teljesen láthatót jelent, a 0 (nulla) pedig rejtettet. Animálás közben a Flutter interpolálja az értékeket e két szélsőérték között. Láthatjuk, hogyan kerül egy feltétel a láthatóság megváltoztatására, és így az animáció elindítására. -
child
A gyermek widget, amelynek láthatóságát animálni fogjuk.
Most már meg kell értenünk, hogy milyen igazán egyszerű a láthatósági animációt hozzáadni az implicit widgethez. És minden ilyen widget ugyanazokat az irányelveket követi, és könnyen használható. Lépjünk tovább a következőre.
AnimatedCrossFade
Megvan a felhasználó neve, de a widget még vár a bevitelre. Az előző lépésben, ahogy a felhasználó beírja a nevét, megjelenítjük a következő gombot. Most, amikor a felhasználó megnyomja a gombot, le akarom állítani a bemenet fogadását és megjeleníteni a beírt nevet. Erre persze sokféleképpen van lehetőség, de talán elrejthetjük a beviteli widgetet, és megjeleníthetünk egy szerkeszthetetlen szöveg widgetet. Próbáljuk ki a AnimatedCrossFade
widget segítségével.
Ez a widget két gyermeket igényel, mivel a widget valamilyen feltétel alapján váltogat közöttük. Egy fontos dolog, amit szem előtt kell tartani ennek a widgetnek a használata során, hogy mindkét gyermeknek azonos szélességűnek kell lennie. Ha a magasság eltérő, akkor a magasabb widget alulról le lesz vágva. Ebben a forgatókönyvben két widgetet használunk gyermekként: input és 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, );}
Ez a widget más kötelező paramétereket igényel:
-
crossFadeState
Ez az állapot dolgozza ki, hogy melyik gyermekét jelenítse meg. -
firstChild
Meghatározza az első gyermekét ennek a widgetnek. -
secondChild
Meghatározza a második gyermeket.
AnimatedAlign
A névcímke ekkor a képernyő közepére kerül. Sokkal jobban fog kinézni felül, mivel a képernyő közepére van szükségünk az idézőjelek megjelenítéséhez. Egyszerűen fogalmazva, a névcímke widget igazítását középről felülre kell változtatni. És nem lenne jó, ha ezt az igazításváltozást az előző átlapoló animációval együtt animálhatnánk? Csináljuk meg.
Mint mindig, most is többféle technikát használhatunk ennek elérésére. Mivel a névcímke widget már középre igazított, az igazítás animálása sokkal egyszerűbb lenne, mint a widget felső és bal oldali értékeinek manipulálása. A AnimatedAlign
widget tökéletes erre a feladatra.
Az animáció elindításához egy triggerre van szükség. Ennek a widgetnek egyetlen célja az igazításváltás animálása, ezért csak néhány tulajdonsággal rendelkezik: hozzáad egy gyermeket, beállítja az igazítását, kiváltja az igazításváltást, és ennyi.
_getAnimatedAlignWidget() { return AnimatedAlign(duration: Duration(seconds: 1),curve: Curves.easeInOut,alignment: alignTop ? Alignment.topLeft : Alignment.center,child: _getAnimatedCrossfade(), );}
Mindössze két kötelező tulajdonsága van:
- gyermek:
A gyermek, amelynek az igazítása módosul. - igazítás:
Szükséges igazítási érték.
Ez a widget nagyon egyszerű, de az eredmény elegáns. Ráadásul láttuk, hogy milyen egyszerűen használhatunk két különböző animált widgetet egy összetettebb animáció létrehozásához. Ez az animált widgetek szépsége.
AnimatedPadding
Most már a felhasználó neve van a tetején, simán animálva, különösebb erőfeszítés nélkül, különböző animált widgetek használatával. Adjunk a név elé egy üdvözlést, a “Hi”-t. Ha egy “Hi,” értékű szöveg widgetet adunk hozzá a tetején, akkor az átfedésben lesz az üdvözlő szöveg widgettel, az alábbi képen látható módon.
Mi lenne, ha a név szöveg widgetnek lenne egy kis kitöltés a bal oldalon? A bal oldali kitöltés növelése biztosan működik, de várjunk csak: a kitöltést növelhetjük valamilyen animációval? Igen, és ez az, amit a AnimatedPadding
tesz. Hogy mindez sokkal jobban nézzen ki, hagyjuk, hogy az üdvözlő szöveg widget egyszerre halványuljon és a név szöveg widget paddingja növekedjen.
_getAnimatedPaddingWidget() { return AnimatedPadding( duration: Duration(seconds: 1), curve: Curves.fastOutSlowIn, padding: increaseLeftPadding ? EdgeInsets.only(left: 28.0) : EdgeInsets.only(left: 0), child: _getAnimatedCrossfade(), );}
_getAnimatedPaddingWidget() { return AnimatedPadding( duration: Duration(seconds: 1), curve: Curves.fastOutSlowIn, padding: increaseLeftPadding ? EdgeInsets.only(left: 28.0) : EdgeInsets.only(left: 0), child: _getAnimatedCrossfade(), );}
Mivel a fenti animációnak csak az előző animált igazítás befejezése után kellene bekövetkeznie, késleltetnünk kell ennek az animációnak a kiváltását. Röviden elkalandozva a témától, ez egy jó alkalom arra, hogy beszéljünk a késleltetés hozzáadásának egy népszerű mechanizmusáról. A Flutter több ilyen technikát is kínál, de a Future.delayed konstruktor az egyik egyszerűbb, tisztább és olvashatóbb megközelítés. Például egy kódrészlet 1 másodperc után történő végrehajtásához:
Future.delayed(Duration(seconds: 1), (){ sum = a + b; // This sum will be calculated after 1 second. print(sum);});
Mivel a késleltetés időtartama már ismert (korábbi animációs időtartamokból kiszámítva), az animáció elindítható ezen intervallum után.
// 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; }); });}
Ez a widget csak két kötelező tulajdonsággal rendelkezik:
-
child
A widgeten belüli gyermek, amelyre a kitöltést alkalmazni fogja. -
padding
A hozzáadandó hely mennyisége.
AnimatedSize
Minden olyan alkalmazás, amely valamilyen animációval rendelkezik, manapság magában foglalja a vizuális komponensek nagyítását vagy kicsinyítését, hogy megragadja a felhasználó figyelmét (ezt általában skálázó animációnak nevezik). Miért ne használhatnánk ugyanezt a technikát itt is? Megmutathatunk a felhasználónak egy motivációs idézetet, amely a képernyő közepéről zoomol be. Hadd mutassam be a AnimatedSize
widgetet, amely a gyermeke méretének változtatásával vezérelt nagyítás és kicsinyítés effektust teszi lehetővé.
Ez a widget egy kicsit eltér a többitől, ami a szükséges paramétereket illeti. Szükségünk van arra, amit a Flutter “ketyegőnek” nevez. A Flutter rendelkezik egy olyan módszerrel, amellyel az objektumok tudatják, ha egy új képkocka eseményt vált ki. Ezt úgy lehet elképzelni, mint valami olyasmit, ami egy jelet küld, ami azt mondja: “Csináld most! … Csináld most! … Csináld most! …”
A AnimatedSize
widgetnek szüksége van egy tulajdonságra – vsync -, amely elfogad egy futásszolgáltatót. A legegyszerűbb módja a ticker provider megszerzésének, ha egy Mixin-t adunk az osztályhoz. Két alapvető ticker provider implementáció létezik: SingleTickerProviderStateMixin
, amely egyetlen tickert biztosít; és TickerProviderStateMixin
, amely több tickert biztosít.
A ticker alapértelmezett implementációja egy animáció képkockáinak jelölésére szolgál. Ebben az esetben ez utóbbit alkalmazzuk. Bővebben a mixinekről.
// 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; }); });}
A widget kötelező tulajdonságai:
-
vsync
Az animáció és a keretváltozások koordinálásához szükséges ketyegő szolgáltató.< -
child
A gyermek, amelynek méretváltozása animálva lesz.
A zoom in és zoom out animáció most már könnyen megszelídíthető.
AnimatedPositioned
Nagyszerű! Az idézetek középről zoomolnak, hogy megragadják a felhasználó figyelmét. Mi lenne, ha alulról csúszna felfelé zoomolás közben? Próbáljuk ki! Ez a mozgás az idézet widget pozíciójával való játékot és a pozíciótulajdonságok változásainak animálását jelenti. A AnimatedPositioned
tökéletes jelölt.
Ez a widget automatikusan átállítja a gyermek pozícióját egy adott időtartam alatt, amikor a megadott pozíció változik. Egy megjegyzés: csak akkor működik, ha a szülő widget egy “Stack”. Ez a widget elég egyszerű és könnyen használható. Lássuk.
// 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, );}
Ez a widget csak egy kötelező tulajdonsággal rendelkezik:
-
child
A widget, amelynek a pozíciója változik.
Ha a gyermek mérete várhatóan nem változik a pozíciójával együtt, akkor ennek a widgetnek a SlideTransition
egy performatívabb alternatívája lenne.
Itt a teljes animációnk:
Következtetés
Az animációk a felhasználói élmény szerves részét képezik. A statikus alkalmazások vagy a béna animációval ellátott alkalmazások nem csak a felhasználók megtartását csökkentik, hanem a fejlesztő hírnevét is, hogy eredményeket érjen el.
A legtöbb népszerű alkalmazás manapság valamilyen finom animációval örvendezteti meg a felhasználókat. A felhasználói kérésekre adott animált visszajelzések szintén arra ösztönözhetik őket, hogy többet fedezzenek fel. A Flutter számos funkciót kínál a keresztplatformos fejlesztéshez, beleértve a sima és reszponzív animációk gazdag támogatását.
A Flutter nagyszerű plug-in támogatással rendelkezik, amely lehetővé teszi számunkra, hogy más fejlesztők animációit használjuk. Most, hogy megérett az 1.9-es verzióra, a közösség sok szeretetével, a Flutter biztosan még jobb lesz a jövőben. Azt mondanám, hogy most van itt az ideje megtanulni a Fluttert!
Leave a Reply