Animating Apps With Flutter

Shubham

Über den Autor

Ein Full-Stack-Softwareentwickler bei Tag und Mobile-App-Entwickler bei Nacht. Wenn ich nicht arbeite, liebe ich es zu kochen und PC-Spiele zu spielen.Mehr überShubham↬

  • 14 min read
  • Apps,Animation
  • Saved for offline reading
  • Share on Twitter, LinkedIn
Flutter bietet großartige Animationsunterstützung für plattformübergreifende Apps. In diesem Artikel wird die neue, unkonventionelle und einfachere Methode zum Hinzufügen von Animationen zu Apps vorgestellt. Was genau sind diese neuen „Animations- und Bewegungs“-Widgets und wie können wir sie verwenden, um einfache und komplexe Animationen hinzuzufügen?

Apps für jede Plattform werden gelobt, wenn sie intuitiv sind, gut aussehen und ein angenehmes Feedback zu Benutzerinteraktionen liefern. Animation ist eine der Möglichkeiten, genau das zu erreichen.

Flutter, ein plattformübergreifendes Framework, ist in den letzten zwei Jahren gereift und unterstützt nun auch Web und Desktop. Es hat sich den Ruf erworben, dass die damit entwickelten Anwendungen reibungslos funktionieren und gut aussehen. Mit seiner umfangreichen Animationsunterstützung, der deklarativen Art, UI zu schreiben, „Hot Reload“ und anderen Funktionen ist es jetzt ein vollständiges, plattformübergreifendes Framework.

Wenn Sie mit Flutter beginnen und eine unkonventionelle Art des Hinzufügens von Animationen erlernen wollen, dann sind Sie hier richtig: Wir werden das Reich der Animations- und Bewegungswidgets erkunden, eine implizite Art des Hinzufügens von Animationen.

Flutter basiert auf dem Konzept der Widgets. Jede visuelle Komponente einer App ist ein Widget – man kann sie sich wie Ansichten in Android vorstellen. Flutter bietet Animationsunterstützung mit einer Animationsklasse, einem „AnimationController“-Objekt zur Verwaltung und „Tween“ zur Interpolation des Datenbereichs. Diese drei Komponenten arbeiten zusammen, um eine reibungslose Animation zu ermöglichen. Da dies eine manuelle Erstellung und Verwaltung der Animation erfordert, wird es als explizite Art der Animation bezeichnet.

Nun möchte ich Ihnen die Animations- und Bewegungs-Widgets vorstellen. Flutter bietet zahlreiche Widgets, die von Haus aus Animationen unterstützen. Es ist nicht nötig, ein Animationsobjekt oder einen Controller zu erstellen, da die gesamte Animation von dieser Kategorie von Widgets erledigt wird. Wählen Sie einfach das entsprechende Widget für die gewünschte Animation aus und übergeben Sie die Werte für die Eigenschaften des Widgets, um es zu animieren. Diese Technik ist eine implizite Art der Animation.

Animationshierarchie in Flutter. (Große Vorschau)

Das obige Diagramm stellt grob die Animationshierarchie in Flutter dar, wie sowohl explizite als auch implizite Animation unterstützt werden.

Einige der in diesem Artikel behandelten animierten Widgets sind:

  • AnimatedOpacity
  • AnimatedCrossFade
  • AnimatedAlign
  • AnimatedPadding
  • AnimatedSize
  • AnimatedPositioned.

Flutter bietet nicht nur vordefinierte animierte Widgets, sondern auch ein generisches Widget namens AnimatedWidget, mit dem eigene implizit animierte Widgets erstellt werden können. Wie aus dem Namen ersichtlich, gehören diese Widgets zur Kategorie der animierten und bewegten Widgets, und so haben sie einige gemeinsame Eigenschaften, die es uns ermöglichen, Animationen viel glatter und besser aussehend zu machen.

Lassen Sie mich diese gemeinsamen Eigenschaften jetzt erklären, da sie später in allen Beispielen verwendet werden.

  • duration
    Die Dauer, über die die Parameter animiert werden sollen.
  • reverseDuration
    Die Dauer der umgekehrten Animation.
  • curve
    Die Kurve, die bei der Animation der Parameter angewendet werden soll. Die interpolierten Werte können aus einer linearen Verteilung oder, falls angegeben, aus einer Kurve entnommen werden.

Beginnen wir mit der Erstellung einer einfachen Anwendung, die wir „Quoted“ nennen werden. Sie wird bei jedem Start der App ein zufälliges Zitat anzeigen. Zwei Dinge sind zu beachten: Erstens werden alle Zitate in der Anwendung fest kodiert, und zweitens werden keine Benutzerdaten gespeichert.

Hinweis: Alle Dateien für diese Beispiele können auf GitHub gefunden werden.

Getting Started

Flutter sollte installiert sein, und Sie sollten mit dem grundlegenden Ablauf vertraut sein, bevor Sie weitermachen. Ein guter Startpunkt ist „Using Google’s Flutter For Truly Cross-Platform Mobile Development“.

Erstellen Sie ein neues Flutter-Projekt in Android Studio.

Neues Flutter-Projekt-Menü in Android Studio. (Große Vorschau)

Dies öffnet einen neuen Projektassistenten, in dem Sie die Projektgrundlagen konfigurieren können.

Auswahlbildschirm für den Flutter-Projekttyp. (Große Vorschau)

Im Bildschirm zur Auswahl des Projekttyps gibt es verschiedene Arten von Flutter-Projekten, die jeweils auf ein bestimmtes Szenario zugeschnitten sind. Wählen Sie für dieses Tutorial Flutter Application und drücken Sie auf Next.

Sie müssen nun einige projektspezifische Informationen eingeben: den Projektnamen und -pfad, die Firmendomäne und so weiter. Schauen Sie sich das folgende Bild an.

Flutter Application configuration screen. (Große Vorschau)

Fügen Sie den Projektnamen, den Flutter SDK-Pfad, den Projektstandort und eine optionale Projektbeschreibung hinzu. Drücken Sie auf Weiter.

Bildschirm „Flutter-Anwendungspaketname“. (Große Vorschau)

Jede Anwendung (egal ob Android oder iOS) benötigt einen eindeutigen Paketnamen. Normalerweise verwenden Sie den umgekehrten Namen Ihrer Website-Domain, z. B. com.google oder com.yahoo. Drücken Sie auf Fertigstellen, um eine funktionierende Flutter-Anwendung zu generieren.

Das generierte Beispielprojekt. (Große Vorschau)

Wenn das Projekt generiert ist, sollten Sie den oben gezeigten Bildschirm sehen. Öffnen Sie die Datei main.dart (im Bildschirmfoto hervorgehoben). Dies ist die Hauptanwendungsdatei. Das Beispielprojekt ist in sich vollständig und kann ohne Änderungen direkt auf einem Emulator oder einem physischen Gerät ausgeführt werden.

Ersetzen Sie den Inhalt der Datei main.dart durch den folgenden Codeschnipsel:

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(), ); }}

Dieser Code bereinigt die Datei main.dart, indem er nur einfache Informationen hinzufügt, die für die Erstellung einer neuen Anwendung relevant sind. Die Klasse MyApp gibt ein Objekt zurück: ein MaterialApp-Widget, das die Grundstruktur für die Erstellung von Apps gemäß dem Material Design bietet. Um den Code besser zu strukturieren, erstellen Sie zwei neue Dart-Dateien im lib-Ordner: FirstPage.dart und Quotes.dart.

Die FirstPage.dart-Datei. (Große Vorschau)

FirstPage.dart enthält den gesamten Code, der für alle visuellen Elemente (Widgets) verantwortlich ist, die für unsere Quotes-App benötigt werden. Die gesamte Animation wird in dieser Datei abgewickelt.

Hinweis: Später im Artikel werden alle Codeschnipsel für jedes animierte Widget dieser Datei als Kinder des Scaffold-Widgets hinzugefügt. Für weitere Informationen könnte dieses Beispiel auf GitHub nützlich sein.

Starten Sie, indem Sie den folgenden Code zu FirstPage.dart hinzufügen. Dies ist der Teilcode, zu dem später noch weitere Dinge hinzugefügt werden.

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: , ), ); }}

Die Datei Quotes.dart. (Große Vorschau)

Die Datei „Quotes.dart“ enthält eine Liste aller fest kodierten Zitate. Dabei ist zu beachten, dass die Liste ein statisches Objekt ist. Das bedeutet, dass sie an anderen Stellen verwendet werden kann, ohne dass ein neues Objekt der Klasse „Quotes“ erstellt werden muss. Dies ist so gewollt, da die obige Liste lediglich als Hilfsmittel fungiert.

Fügen Sie den folgenden Code zu dieser Datei hinzu:

class Quotes { static const quotesArray = ;}

Das Projektgerüst ist nun fertig, also lassen Sie uns Quoted ein wenig mehr ausarbeiten.

AnimatedOpacity

Um der Anwendung eine persönliche Note zu verleihen, wäre es schön, den Namen des Benutzers zu kennen, also lassen Sie uns danach fragen und eine Schaltfläche „Next“ anzeigen. Bis der Benutzer seinen Namen eingibt, ist diese Schaltfläche ausgeblendet und wird erst angezeigt, wenn der Name eingegeben wurde. Wir brauchen eine Art Sichtbarkeitsanimation für die Schaltfläche, aber gibt es dafür ein Widget? Ja, das gibt es.

Eingabe AnimatedOpacity. Dieses Widget baut auf dem Opacity-Widget auf, indem es implizite Animationsunterstützung hinzufügt. Wie verwenden wir es? Erinnern wir uns an unser Szenario: Wir müssen eine Schaltfläche „Next“ mit animierter Sichtbarkeit anzeigen. Wir wickeln das Schaltflächen-Widget in das AnimatedOpacity-Widget ein, fügen einige geeignete Werte ein und fügen eine Bedingung hinzu, um die Animation auszulösen – und Flutter kümmert sich um den Rest.

_getAnimatedOpacityButton() { return AnimatedOpacity( duration: Duration(seconds: 1), reverseDuration: Duration(seconds: 1), curve: Curves.easeInOut, opacity: showNextButton ? 1 : 0, child: _getButton(), );}
Animation der Deckkraft der nächsten Schaltfläche. (Große Vorschau)

Das AnimatedOpacityWidget hat zwei obligatorische Eigenschaften:

  • opacity
    Ein Wert von 1 bedeutet vollständig sichtbar; 0 (Null) bedeutet versteckt. Während der Animation interpoliert Flutter die Werte zwischen diesen beiden Extremen. Sie können sehen, wie eine Bedingung platziert wird, um die Sichtbarkeit zu ändern und damit die Animation auszulösen.
  • child
    Das untergeordnete Widget, dessen Sichtbarkeit animiert wird.

Sie sollten jetzt verstehen, wie einfach es ist, die Sichtbarkeitsanimation mit dem impliziten Widget hinzuzufügen. Und alle diese Widgets folgen den gleichen Richtlinien und sind einfach zu verwenden. Gehen wir zum nächsten über.

AnimatedCrossFade

Wir haben den Namen des Benutzers, aber das Widget wartet immer noch auf eine Eingabe. Im vorherigen Schritt haben wir, während der Benutzer seinen Namen eingibt, die Schaltfläche „Weiter“ angezeigt. Wenn der Benutzer nun die Schaltfläche drückt, möchte ich keine Eingaben mehr annehmen und den eingegebenen Namen anzeigen. Es gibt natürlich viele Möglichkeiten, aber vielleicht können wir das Eingabewidget ausblenden und ein nicht editierbares Textwidget anzeigen. Probieren wir es mit dem AnimatedCrossFade-Widget aus.

Dieses Widget benötigt zwei untergeordnete Elemente, da das Widget in Abhängigkeit von einer Bedingung zwischen ihnen überblendet. Eine wichtige Sache, die bei der Verwendung dieses Widgets beachtet werden muss, ist, dass beide Kinder die gleiche Breite haben sollten. Wenn die Höhe unterschiedlich ist, wird das größere Widget von unten abgeschnitten. In diesem Szenario werden zwei Widgets als Kinder verwendet: input und 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, );}
Überblendung zwischen dem input widget und dem name widget. (Große Vorschau)

Dieses Widget erfordert einen anderen Satz obligatorischer Parameter:

  • crossFadeState
    Dieser Status bestimmt, welches Kind angezeigt werden soll.
  • firstChild
    Bestimmt das erste Kind für dieses Widget.
  • secondChild
    Bestimmt das zweite Kind.

AnimatedAlign

Zu diesem Zeitpunkt ist das Namensetikett in der Mitte des Bildschirms positioniert. Oben sieht er viel besser aus, da wir die Mitte des Bildschirms für die Anzeige von Anführungszeichen benötigen. Einfach ausgedrückt: Die Ausrichtung des Widget-Namens sollte von der Mitte nach oben geändert werden. Und wäre es nicht schön, diese Ausrichtungsänderung zusammen mit der vorherigen Überblendungsanimation zu animieren? Machen wir es.

Wie immer können verschiedene Techniken verwendet werden, um dies zu erreichen. Da das Widget für die Namensbeschriftung bereits mittig ausgerichtet ist, wäre es viel einfacher, seine Ausrichtung zu animieren, als die oberen und linken Werte des Widgets zu manipulieren. Das AnimatedAlignWidget eignet sich perfekt für diese Aufgabe.

Um diese Animation auszulösen, wird ein Auslöser benötigt. Der einzige Zweck dieses Widgets ist es, die Ausrichtungsänderung zu animieren, daher hat es nur wenige Eigenschaften: ein Kind hinzufügen, seine Ausrichtung festlegen, die Ausrichtungsänderung auslösen und das war’s.

_getAnimatedAlignWidget() { return AnimatedAlign(duration: Duration(seconds: 1),curve: Curves.easeInOut,alignment: alignTop ? Alignment.topLeft : Alignment.center,child: _getAnimatedCrossfade(), );}
Ausrichtungsanimation des Namenswidgets. (Große Vorschau)

Es hat nur zwei obligatorische Eigenschaften:

  • Kind:
    Das Kind, dessen Ausrichtung geändert wird.
  • Ausrichtung:
    Erforderlicher Ausrichtungswert.

Dieses Widget ist wirklich einfach, aber die Ergebnisse sind elegant. Außerdem haben wir gesehen, wie einfach wir zwei verschiedene animierte Widgets verwenden können, um eine komplexere Animation zu erstellen. Das ist das Schöne an animierten Widgets.

AnimatedPadding

Jetzt haben wir den Namen des Benutzers oben, sanft animiert ohne viel Aufwand, mit verschiedenen Arten von animierten Widgets. Fügen wir eine Begrüßung, „Hi“, vor dem Namen ein. Wenn Sie oben ein Textwidget mit dem Wert „Hi“ hinzufügen, wird es das Begrüßungstextwidget überlappen, so dass es wie in der folgenden Abbildung aussieht.

Die Begrüßungs- und Namenswidgets überlappen. (Große Vorschau)

Was wäre, wenn das Widget für den Namenstext auf der linken Seite etwas gepolstert wäre? Die linke Auffüllung zu erhöhen, wird auf jeden Fall funktionieren, aber halt: können wir die Auffüllung mit einer Animation erhöhen? Ja, und genau das macht AnimatedPadding. Um das Ganze noch besser aussehen zu lassen, sollten wir das Grußtext-Widget einblenden lassen und gleichzeitig die Füllung des Namenstext-Widgets vergrößern.

_getAnimatedPaddingWidget() { return AnimatedPadding( duration: Duration(seconds: 1), curve: Curves.fastOutSlowIn, padding: increaseLeftPadding ? EdgeInsets.only(left: 28.0) : EdgeInsets.only(left: 0), child: _getAnimatedCrossfade(), );}

Da die obige Animation erst nach Abschluss der vorherigen animierten Ausrichtung erfolgen soll, müssen wir die Auslösung dieser Animation verzögern. Um kurz vom Thema abzuschweifen, ist dies ein guter Moment, um über einen beliebten Mechanismus zum Hinzufügen von Verzögerungen zu sprechen. Flutter bietet mehrere solcher Techniken, aber der Future.delayed-Konstruktor ist einer der einfacheren, saubereren und besser lesbaren Ansätze. Zum Beispiel, um ein Stück Code nach 1 Sekunde auszuführen:

Future.delayed(Duration(seconds: 1), (){ sum = a + b; // This sum will be calculated after 1 second. print(sum);});

Da die Verzögerungsdauer bereits bekannt ist (berechnet aus früheren Animationsdauern), kann die Animation nach diesem Intervall ausgelöst werden.

// 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; }); });}
Padding-Animation des Name-Widgets. (Große Vorschau)

Dieses Widget hat nur zwei obligatorische Eigenschaften:

  • child
    Das Kind innerhalb dieses Widgets, auf das die Auffüllung angewendet wird.
  • padding
    Die Menge des hinzuzufügenden Platzes.

AnimatedSize

Heutzutage beinhaltet jede Anwendung, die irgendeine Art von Animation hat, das Vergrößern oder Verkleinern von visuellen Komponenten, um die Aufmerksamkeit des Benutzers zu erregen (allgemein als Skalierungsanimation bezeichnet). Warum nicht die gleiche Technik hier verwenden? Wir können dem Benutzer ein motivierendes Zitat zeigen, das aus der Mitte des Bildschirms heran gezoomt wird. Ich möchte Ihnen das AnimatedSize-Widget vorstellen, das die Ein- und Auszoom-Effekte ermöglicht, die durch die Änderung der Größe des untergeordneten Widgets gesteuert werden.

Dieses Widget unterscheidet sich ein wenig von den anderen, wenn es um die erforderlichen Parameter geht. Wir brauchen das, was Flutter einen „Ticker“ nennt. Flutter hat eine Methode, um Objekte zu benachrichtigen, wenn ein neues Frame-Ereignis ausgelöst wird. Man kann es sich als etwas vorstellen, das ein Signal sendet, das sagt: „Tu es jetzt! … Tu es jetzt! … Tu es jetzt! …“

Das AnimatedSize Widget benötigt eine Eigenschaft – vsync – die einen Ticker-Anbieter akzeptiert. Der einfachste Weg, einen Ticker-Provider zu erhalten, besteht darin, der Klasse ein Mixin hinzuzufügen. Es gibt zwei grundlegende Implementierungen von Ticker-Anbietern: SingleTickerProviderStateMixin, die einen einzelnen Ticker bereitstellt; und TickerProviderStateMixin, die mehrere bereitstellt.

Die Standardimplementierung eines Tickers wird verwendet, um die Frames einer Animation zu markieren. In diesem Fall wird die letztere verwendet. Mehr über Mixins.

// 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; }); });}

Skalierende Animation des Zitate-Widgets. (Große Vorschau)

Pflichtige Eigenschaften für dieses Widget:

  • vsync
    Der erforderliche Ticker-Provider, um Animation und Frame-Änderungen zu koordinieren.<
  • child
    Das Kind, dessen Größenänderungen animiert werden sollen.

Die Vergrößerungs- und Verkleinerungsanimation ist jetzt leicht zu bändigen.

AnimatedPositioned

Gut! Die Zitate zoomen von der Mitte aus heran, um die Aufmerksamkeit des Benutzers zu erregen. Wie wäre es, wenn sie beim Heranzoomen von unten nach oben rutschen würden? Probieren wir es aus. Bei dieser Bewegung spielen wir mit der Position des Zitat-Widgets und animieren die Änderungen der Positionseigenschaften. AnimatedPositioned ist der perfekte Kandidat.

Dieses Widget ändert automatisch die Position des Kinds über eine bestimmte Dauer, wenn sich die angegebene Position ändert. Ein Hinweis: Es funktioniert nur, wenn das übergeordnete Widget ein „Stack“ ist. Dieses Widget ist ziemlich einfach und unkompliziert in der Anwendung. Schauen wir es uns an.

// 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, );}
Position mit Skalierungsanimation von Zitaten. (Große Vorschau)

Dieses Widget hat nur eine obligatorische Eigenschaft:

  • child
    Das Widget, dessen Position geändert werden soll.

Wenn sich die Größe des Childs nicht zusammen mit seiner Position ändern soll, wäre eine performantere Alternative zu diesem Widget SlideTransition.

Hier ist unsere komplette Animation:

Alle animierten Widgets zusammen. (Große Vorschau)

Fazit

Animationen sind ein wesentlicher Bestandteil der Benutzererfahrung. Statische Apps oder Apps mit unsauberen Animationen verringern nicht nur die Benutzerbindung, sondern auch den Ruf eines Entwicklers, Ergebnisse zu liefern.

Heutzutage haben die meisten beliebten Apps eine Art von subtiler Animation, um die Benutzer zu erfreuen. Animierte Rückmeldungen auf Benutzeranfragen können sie auch dazu verleiten, mehr zu erkunden. Flutter bietet viele Funktionen für die plattformübergreifende Entwicklung, einschließlich umfangreicher Unterstützung für reibungslose und reaktionsschnelle Animationen.

Flutter hat eine großartige Plug-in-Unterstützung, die es uns ermöglicht, Animationen von anderen Entwicklern zu verwenden. Jetzt, wo es bis zur Version 1.9 gereift ist, mit so viel Liebe von der Community, wird Flutter in Zukunft sicher noch besser werden. Ich würde sagen, jetzt ist ein guter Zeitpunkt, um Flutter zu lernen!

Leave a Reply