Vereinfachung von Animationen in Flutter mit implizit animierten Widgets
Animationen sind in Flutter recht einfach zu machen und eine Menge Komplexität kann mit viel weniger Aufwand als im nativen Android erreicht werden. Dies wird normalerweise durch die Definition einer Animation + eines AnimationControllers erreicht. Aber es gibt eingebaute Widgets, die dies sogar reduzieren und Animationen so einfach machen, wie das Ändern von Werten!
Die kompletten Beispiele werden auf meiner Github-Seite gehostet, die am Ende dieses Artikels angegeben ist.
Ein AnimatedContainer geht automatisch zu den definierten Werten (Farben, Größen etc.) über, anstatt einfach nur augenblicklich zu wechseln. Das obige GIF ist ein Beispiel für einen AnimatedContainer.
Ein AnimatedContainer ist wie folgt definiert:
var myColor = Colors.blue;
var myHeight = 100.0;
var myWidth = 100.0;AnimatedContainer(
duration: Duration(seconds: 1),
color: myColor,
height: myHeight,
width: myWidth,
),
In normalen Fällen würde man einen Controller und ein Tween<double> und ein ColorTween definieren, um die Animation im obigen GIF zu erreichen. Aber mit AnimatedContainer müssen Sie nur folgendes tun:
- Eine Dauer für die Animation festlegen
duration: Duration(seconds: 1),
2. Werte ändern (Farbe und Größe auf Ihre Werte ändern)
myColor = Colors.green;
myHeight = MediaQuery.of(context).size.height;
myWidth = MediaQuery.of(context).size.width;
3. SetState()
setState(() {});
Keine Controller. Keine Tweens.
In dem Moment, in dem du die Werte von myColor, my Height oder myWidth und setState() änderst, geht der Container automatisch zu den Werten über, anstatt direkt zu diesem Wert zu wechseln.
onPressed: () {
myColor = Colors.green;
myHeight = MediaQuery.of(context).size.height;
myWidth = MediaQuery.of(context).size.width;
setState(() {});
}
Am Anfang war myColor auf Colors.blue gesetzt. Wenn wir es auf Colors.green ändern und setState neu erstellen, geht es von blau zu grün über, ohne dass Tweens verwendet werden. (Hinweis: Tweens werden implizit verwendet, müssen aber nicht benutzerdefiniert sein.)
Nach dem, was ich gesehen habe, scheinen sich viele Entwickler dieser implizit animierten Widgets nicht bewusst zu sein und verschwenden Zeit, wenn es nicht notwendig ist. Natürlich wird es Fälle geben, in denen man ein anderes Verhalten wünscht, aber in den meisten Fällen erfüllt AnimatedContainer die Aufgabe.
Helden-Animationen
Eine Helden-Animation lässt ein Element von einer Seite auf die zweite „fliegen“ und passt sich automatisch an die Größe des gleichen Elements auf der zweiten Seite an. Das macht so etwas wie eine Liste in einer App, die eine Detailseite hat, viel interessanter.
Flutter macht es unglaublich einfach, Hero-Animationen zu implementieren. Alles, was Sie tun müssen, ist, das Element, das Sie zu einem „Hero“ machen wollen, mit einem Hero-Widget zu umhüllen und es mit einem Tag zu versehen. Wenn Sie dies in einer Liste tun wollen, müssen Sie für jedes Element ein anderes Tag angeben, das ich normalerweise einfach auf „hero“ + Position des Elements in der Liste setze.
Das obige Beispiel hat eine einfache Karte auf der ersten Seite mit einem Container mit einer roten Farbe.
Hero(
tag: "heroTag",
child: Container(
color: Colors.red,
height: 100.0,
),
),
Auf der Detailseite befindet sich wiederum ein größerer Container mit ebenfalls roter Farbe.
Expanded(
child: Hero(
tag: "heroTag",
child: Container(
color: Colors.red,
),
),
),
Und sobald ich ihn von einer Seite auf die andere schiebe, indem ich
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return new HeroDetailPage();
},
),
);
Das war’s!
Der farbige Container fliegt automatisch und vergrößert sich auf die Größe der zweiten Seite.
Vor einiger Zeit habe ich eine Menge Animationen in einer Konzeptschach-App verwendet, die ich mit Flutter erstellt habe.
Hier ist ein Artikel, den ich geschrieben habe, wenn Sie einen detaillierteren Blick auf den Code dieser App werfen wollen.
AnimatedCrossFade
Ein CrossFade ist ein sanfter Übergang von einem Widget zu einem anderen mit einer bestimmten Dauer. Flutter macht dies einfach mit einem AnimatedCrossFade Widget.
So wird ein AnimatedCrossFade definiert:
AnimatedCrossFade(
firstChild: // Your first element here,
secondChild: // Element after transition,
crossFadeState: // State of the transition,
duration: Duration(milliseconds: 1500),
),
Wir liefern:
- Das Widget vor dem Übergang
firstChild: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: CircularProgressIndicator(),
),
height: 200.0,
width: 200.0,
),
2. Das Widget nach dem Übergang
secondChild: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: FlutterLogo(),
),
height: 100.0,
width: 200.0,
),
3. Der Zustand des Übergangs (ob der Übergang bereits stattgefunden hat oder nicht)
(Hier ist firstStateEnabled ein boolescher Wert, den wir ändern können, um den Zustand zu ändern)
crossFadeState: firstStateEnabled
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
4. Die Dauer des Übergangs
duration: Duration(milliseconds: 1500),
Diese Menge an Code reicht aus, um uns das obige Beispiel zu liefern. Der Übergang wird einfach durch die Änderung des crossFadeState ausgelöst.
Hinweis: Wenn die beiden Kinder unterschiedlich groß sind, wird automatisch von einer Größe zur anderen übergegangen.
Hier ist eine Demo:
AnimatedOpacity
AnimatedOpacity animiert Änderungen der Deckkraft, d.d.h. wie sichtbar ein Widget ist. Eine Deckkraft von 0 macht ein Widget vollständig transparent, während eine Deckkraft von 1 vollständig sichtbar ist.
AnimatedOpacity wird wie folgt deklariert:
AnimatedOpacity(
opacity: // Your variable holding opacity value,
duration: // Duration of the transition,
child: FlutterLogo(),
)
Wie bei den letzten Widgets ändert man bei AnimatedOpacity die Deckkraft und setState und es animiert automatisch die Änderung der Deckkraft.
Im obigen Beispiel wird es deklariert als
AnimatedOpacity(
child: FlutterLogo(size: 100.0,),
opacity: myOpacity,
duration: Duration(seconds: 1),
),
Wenn die Schaltfläche angeklickt wird, ändert es einfach die Deckkraft und setzt den Status.
onPressed: () {
myOpacity = 0.0;
setState(() {});
},