Förenkla animationer i Flutter med implicit animerade widgets
Animeringar är ganska enkla att göra i Flutter och en hel del komplexitet kan uppnås med mycket mindre ansträngning än i Android. Detta uppnås vanligtvis genom sätt som att definiera en Animation + en AnimationController. Men det finns inbyggda widgets som till och med reducerar detta och gör animationer så enkla som att helt enkelt ändra värden!
De fullständiga exemplen kommer att finnas på min Github-sida som anges i slutet av den här artikeln.
En AnimatedContainer övergår automatiskt till de definierade värdena (färger, storlekar etc.) i stället för att bara omedelbart ändra till dem. GIF:en ovan är ett exempel på en AnimatedContainer.
En AnimatedContainer definieras som:
var myColor = Colors.blue;
var myHeight = 100.0;
var myWidth = 100.0;AnimatedContainer(
duration: Duration(seconds: 1),
color: myColor,
height: myHeight,
width: myWidth,
),
I normala fall skulle du definiera en controller och en Tween<double> och en ColorTween för att uppnå animationen i GIF:en ovan. Men med AnimatedContainer behöver du bara göra följande:
- Sätt en varaktighet för animationen
duration: Duration(seconds: 1),
2. Ändra värden (Ändra färg och storlek till dina värden)
myColor = Colors.green;
myHeight = MediaQuery.of(context).size.height;
myWidth = MediaQuery.of(context).size.width;
3. SetState()
setState(() {});
Ingen kontrollanter. Inga Tweens.
I det ögonblick du ändrar värdena för myColor, my Height eller myWidth och setState() övergår behållaren automatiskt till värdena i stället för att ändras direkt till det värdet.
onPressed: () {
myColor = Colors.green;
myHeight = MediaQuery.of(context).size.height;
myWidth = MediaQuery.of(context).size.width;
setState(() {});
}
I början var myColor inställd på Colors.blue. När vi ändrar den till Colors.green och setState för att återskapa den övergår den från blått till grönt utan att några Tweens används. (Observera: Tweens används implicit men behöver inte vara användardefinierade.)
Från vad jag har sett verkar många utvecklare inte vara medvetna om dessa implicit animerade widgets och slösar tid när det inte är nödvändigt. Självklart kommer det att finnas fall där man vill ha ett annat slags beteende, men för det mesta klarar AnimatedContainer av jobbet.
Heroanimationer
En Heroanimation gör att ett element från en sida ”flyger” till en annan och automatiskt anpassar sig till storleken på samma element på den andra sidan. Detta gör något som en lista i en app som har en detaljsida så mycket mer intressant.
Flutter gör det otroligt enkelt att implementera hjälteanimationer. Allt du behöver göra är att omsluta det element som du vill göra till en ”hjälte” med en hjältewidget och förse den med en tagg. Om du vill göra detta i en lista måste du leverera en annan tagg för varje element, som jag bara brukar ställa in på ”hero” + elementets position i listan.
Ovanstående exempel har ett enkelt kort på den första sidan med en behållare med en röd färg.
Hero(
tag: "heroTag",
child: Container(
color: Colors.red,
height: 100.0,
),
),
På detaljsidan finns det återigen en större behållare med röd färg också.
Expanded(
child: Hero(
tag: "heroTag",
child: Container(
color: Colors.red,
),
),
),
Och när jag väl har skjutit den från den ena sidan till den andra med hjälp av
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return new HeroDetailPage();
},
),
);
Det är klart!
Den färgade behållaren flyger automatiskt och expanderar till den senares storlek.
För ett tag sedan använde jag många animationer i en konceptschackapp som jag skapade med Flutter.
Här finns en artikel som jag skrev om du vill ha en mer detaljerad titt på koden för den här appen.
AnimatedCrossFade
En CrossFade är en smidig övergång från en widget till en annan med en given längd. Flutter gör detta enkelt med hjälp av en AnimatedCrossFade-widget.
Så här definieras en AnimatedCrossFade:
AnimatedCrossFade(
firstChild: // Your first element here,
secondChild: // Element after transition,
crossFadeState: // State of the transition,
duration: Duration(milliseconds: 1500),
),
Vi levererar:
- Widgeten före övergång
firstChild: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: CircularProgressIndicator(),
),
height: 200.0,
width: 200.0,
),
2. Widgeten efter övergång
secondChild: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: FlutterLogo(),
),
height: 100.0,
width: 200.0,
),
3. Övergångens tillstånd (Om övergången redan har skett eller inte)
(Här är firstStateEnabled en boolean som vi kan ändra för att ändra tillståndet.)
crossFadeState: firstStateEnabled
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
4. Övergångens varaktighet
duration: Duration(milliseconds: 1500),
Denna mängd kod räcker för att ge oss ovanstående exempel. Övergången utlöses helt enkelt genom att crossFadeState ändras.
Notera: Om de två barnen är av olika storlek övergår den automatiskt från den ena storleken till den andra.
Här är en demo:
AnimatedOpacity
AnimatedOpacity animerar förändringar i opacitet, dvs.dvs. hur synlig en widget är. En opacitet på 0 gör en widget helt transparent, medan en opacitet på 1 är helt synlig.
AnimatedOpacity deklareras som:
AnimatedOpacity(
opacity: // Your variable holding opacity value,
duration: // Duration of the transition,
child: FlutterLogo(),
)
Som liknar de senaste widgetarna, i AnimatedOpacity, ändrar du opaciteten och setState och den animerar automatiskt opacitetsförändringen.
I exemplet ovan deklareras den som
AnimatedOpacity(
child: FlutterLogo(size: 100.0,),
opacity: myOpacity,
duration: Duration(seconds: 1),
),
När knappen klickas ändrar den helt enkelt opacitet och sätter state.
onPressed: () {
myOpacity = 0.0;
setState(() {});
},