Animering af apps med Flutter
Om forfatteren
En full stack softwareudvikler om dagen og udvikler af mobile apps om natten. Når jeg ikke arbejder, elsker jeg at lave mad og spille pc-spil.Mere omShubham↬
- 14 min læsning
- Apps,Animation
- Sparet til offline læsning
- Del på Twitter, LinkedIn
Apps til enhver platform bliver rost, når de er intuitive, ser godt ud og giver behagelig feedback på brugerinteraktioner. Animation er en af måderne at gøre netop dette på.
Flutter, en ramme på tværs af platforme, er i de seneste to år modnet til at omfatte understøttelse af web og desktop. Det har fået et ry for, at apps, der er udviklet med det, er smidige og flotte. Med sin rige animationsunderstøttelse, deklarative måde at skrive brugergrænseflader på, “Hot Reload” og andre funktioner er det nu en komplet ramme på tværs af platforme.
Hvis du starter med Flutter og ønsker at lære en utraditionel måde at tilføje animation på, er du kommet til det rette sted: Vi vil udforske området animation og motion widgets, en implicit måde at tilføje animationer på.
Flutter er baseret på konceptet widgets. Hver visuel komponent i en app er en widget – tænk på dem som visninger i Android. Flutter giver understøttelse af animation ved hjælp af en Animation-klasse, et “AnimationController”-objekt til styring og “Tween” til at interpolere dataområdet. Disse tre komponenter arbejder sammen for at give en jævn animation. Da dette kræver manuel oprettelse og forvaltning af animation, er det kendt som en eksplicit måde at animere på.
Lad mig nu introducere dig til animation og bevægelseswidgets. Flutter tilbyder adskillige widgets, som i sagens natur understøtter animation. Der er ikke behov for at oprette et animationsobjekt eller en controller, da al animation håndteres af denne kategori af widgets. Du skal blot vælge den passende widget til den ønskede animation og sende widgets egenskabsværdier for at animere. Denne teknik er en implicit måde at animere på.
Diagrammet ovenfor beskriver groft sagt animationshierarkiet i Flutter, hvordan både eksplicit og implicit animation understøttes.
Nogle af de animerede widgets, der er omfattet af denne artikel, er:
AnimatedOpacity
AnimatedCrossFade
AnimatedAlign
AnimatedPadding
AnimatedSize
-
AnimatedPositioned
.
Flutter indeholder ikke kun foruddefinerede animerede widgets, men også en generisk widget kaldet AnimatedWidget
, som kan bruges til at oprette brugerdefinerede implicit animerede widgets. Som det fremgår af navnet, tilhører disse widgets kategorien animerede widgets og bevægelseswidgets, og de har derfor nogle fælles egenskaber, som gør det muligt for os at lave animationer meget glattere og flottere.
Lad mig forklare disse fælles egenskaber nu, da de vil blive brugt senere i alle eksempler.
-
duration
Den varighed, som parametrene skal animeres over. -
reverseDuration
Den omvendte animations varighed. -
curve
Den kurve, der skal anvendes ved animationen af parametrene. De interpolerede værdier kan tages fra en lineær fordeling eller, hvis og når det er angivet, kan de tages fra en kurve.
Lad os begynde rejsen ved at oprette en simpel app, som vi kalder “Citeret”. Den vil vise et tilfældigt citat, hver gang appen starter. To ting skal bemærkes: For det første vil alle disse citater blive hardcodet i applikationen, og for det andet vil der ikke blive gemt nogen brugerdata.
Notat: Alle filer til disse eksempler kan findes på GitHub.
Gå i gang
Flutter bør være installeret, og du skal have et vist kendskab til det grundlæggende flow, før du går videre. Et godt sted at starte er: “Using Google’s Flutter For Truly Cross-Platform Mobile Development”.
Opret et nyt Flutter-projekt i Android Studio.
Dette åbner en ny projektguide, hvor du kan konfigurere projektets grundelementer.
I skærmbilledet til valg af projekttype er der forskellige typer Flutter-projekter, som hver især henvender sig til et specifikt scenarie… I denne vejledning skal du vælge Flutter Application og trykke på Next.
Du skal nu indtaste nogle projektspecifikke oplysninger: projektets navn og sti, virksomhedsdomæne osv. Tag et kig på billedet nedenfor.
Føj projektnavn, Flutter SDK-sti, projektplacering og en valgfri projektbeskrivelse. Tryk på Næste.
Alle applikationer (uanset om det er Android eller iOS) kræver et unikt pakkenavn. Typisk bruger du det omvendte af dit websteds domæne; f.eks. com.google eller com.yahoo. Tryk på Afslut for at generere en fungerende Flutter-applikation.
Når projektet er genereret, bør du se den ovenfor viste skærm. Åbn filen main.dart (fremhævet i skærmbilledet). Dette er den vigtigste programfil. Eksempelprojektet er komplet i sig selv og kan køres direkte på en emulator eller en fysisk enhed uden nogen ændring.
Udskift indholdet af filen main.dart med følgende kodestump:
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(), ); }}
Denne kode rydder op i filen main.dart ved blot at tilføje simple oplysninger, der er relevante for oprettelse af en ny app. Klassen MyApp returnerer et objekt: en MaterialApp
widget, som giver den grundlæggende struktur til oprettelse af apps, der er i overensstemmelse med Material Design. For at gøre koden mere struktureret skal du oprette to nye dart-filer i lib-mappen: FirstPage.dart og Quotes.dart.
FirstPage.dart vil indeholde al den kode, der er ansvarlig for alle de visuelle elementer (widgets), der er nødvendige for vores Citat-app. Al animation håndteres i denne fil.
Bemærk: Senere i artiklen tilføjes alle kodestumperne for hver animeret widget til denne fil som børn af Scaffold-widget’en. Hvis du vil have flere oplysninger, kan dette eksempel på GitHub være nyttigt.
Start med at tilføje følgende kode til FirstPage.dart. Dette er den delvise kode, hvor andre ting vil blive tilføjet senere.
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: , ), ); }}
Filen Quotes.dart indeholder en liste over alle de hårdkodede citater. Et punkt, der skal bemærkes her, er, at listen er et statisk objekt. Det betyder, at den kan bruges andre steder uden at oprette et nyt objekt af klassen Cotes. Dette er valgt med vilje, da ovenstående liste blot fungerer som et hjælpeværktøj.
Føj følgende kode til denne fil:
class Quotes { static const quotesArray = ;}
Projektskelettet er nu klar, så lad os konkretisere Citat lidt mere.
AnimatedOpacity
For at give appen et personligt præg ville det være rart at kende brugerens navn, så lad os spørge om det og vise en næste knap. Indtil brugeren indtaster sit navn, er denne knap skjult, og den vil elegant blive vist, når et navn er angivet. Vi har brug for en form for synlighedsanimation for knappen, men er der en widget til det? Ja, det er der.
Indtast AnimatedOpacity
. Denne widget bygger videre på widgetten Opacity ved at tilføje understøttelse af implicit animation. Hvordan kan vi bruge den? Husk vores scenarie: Vi har brug for at vise en næste knap med animeret synlighed. Vi pakker knapwidgetten ind i AnimatedOpacity
-widgetten, indfører nogle ordentlige værdier og tilføjer en betingelse for at udløse animationen – og Flutter kan klare resten.
_getAnimatedOpacityButton() { return AnimatedOpacity( duration: Duration(seconds: 1), reverseDuration: Duration(seconds: 1), curve: Curves.easeInOut, opacity: showNextButton ? 1 : 0, child: _getButton(), );}
Den AnimatedOpacity
widget har to obligatoriske egenskaber:
-
opacity
En værdi på 1 betyder helt synlig; 0 (nul) betyder skjult. Under animationen interpolerer Flutter værdier mellem disse to ekstremer. Du kan se, hvordan en betingelse er placeret for at ændre synligheden og dermed udløse animationen. -
child
Den underordnede widget, hvis synlighed vil blive animeret.
Du burde nu forstå, hvor virkelig enkelt det er at tilføje synlighedsanimation med den implicitte widget. Og alle sådanne widgets følger de samme retningslinjer og er nemme at bruge. Lad os gå videre til den næste.
AnimatedCrossFade
Vi har brugerens navn, men widget’en venter stadig på input. I det foregående trin, når brugeren indtaster sit navn, viser vi den næste knap. Nu, når brugeren trykker på knappen, ønsker jeg at stoppe med at acceptere input og vise det indtastede navn. Der er naturligvis mange måder at gøre det på, men måske kan vi skjule input-widget’en og vise en widget med tekst, der ikke kan redigeres. Lad os prøve det med widget AnimatedCrossFade
.
Denne widget kræver to børn, da widget’en krydspasser mellem dem baseret på en eller anden betingelse. En vigtig ting at huske på, mens du bruger denne widget, er, at begge børn skal have samme bredde. Hvis højden er forskellig, vil den højere widget blive klippet fra bunden. I dette scenarie vil der blive brugt to widgets som børn: input og 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, );}
Denne widget kræver et andet sæt obligatoriske parametre:
-
crossFadeState
Denne tilstand finder ud af, hvilket barn der skal vises. -
firstChild
Angiver det første barn for denne widget. -
secondChild
Angiver det andet barn.
AnimatedAlign
På dette tidspunkt er navneetiketten placeret i midten af skærmen. Det vil se meget bedre ud i toppen, da vi har brug for midten af skærmen til at vise citater. Kort sagt skal justeringen af widgetten til navneskiltet ændres fra midten til toppen. Og ville det ikke være rart at animere denne justering sammen med den tidligere cross-fade-animation? Lad os gøre det.
Som altid kan der bruges flere teknikker til at opnå dette. Da widgeten med navneskiltet allerede er centerjusteret, ville det være meget enklere at animere dens justering end at manipulere widgets værdier for top og venstre. Widgeten AnimatedAlign
er perfekt til denne opgave.
For at igangsætte denne animation er der brug for en trigger. Det eneste formål med denne widget er at animere ændring af justeringen, så den har kun få egenskaber: Tilføj et barn, indstil dets justering, udløs ændringen af justeringen, og det er det hele.
_getAnimatedAlignWidget() { return AnimatedAlign(duration: Duration(seconds: 1),curve: Curves.easeInOut,alignment: alignTop ? Alignment.topLeft : Alignment.center,child: _getAnimatedCrossfade(), );}
Den har kun to obligatoriske egenskaber:
- child:
Det barn, hvis justering vil blive ændret. - alignment:
Nødvendig justeringsværdi.
Denne widget er virkelig enkel, men resultaterne er elegante. Desuden så vi, hvor nemt vi kan bruge to forskellige animerede widgets til at skabe en mere kompleks animation. Det er det smukke ved animerede widgets.
AnimatedPadding
Nu har vi brugerens navn øverst, der er flydende animeret uden større anstrengelser ved hjælp af forskellige typer animerede widgets. Lad os tilføje en hilsen, “Hej”, før navnet. Hvis vi tilføjer en tekstwidget med værdien “Hej,” øverst, vil den overlappe hilsen-tekstwidgetten, så den ser ud som på billedet nedenfor.
Hvad nu hvis widgeten med navnetekst havde noget padding til venstre? En forøgelse af padding til venstre vil helt sikkert virke, men vent: Kan vi øge padding med noget animation? Ja, og det er det, som AnimatedPadding
gør. For at få det hele til at se meget bedre ud, kan vi lade hilsen-tekst-widgetten fade ind og lade navnetekst-widgettens padding stige på samme tid.
_getAnimatedPaddingWidget() { return AnimatedPadding( duration: Duration(seconds: 1), curve: Curves.fastOutSlowIn, padding: increaseLeftPadding ? EdgeInsets.only(left: 28.0) : EdgeInsets.only(left: 0), child: _getAnimatedCrossfade(), );}
Da animationen ovenfor først skal ske, når den foregående animerede tilpasning er færdig, skal vi forsinke udløsningen af denne animation. Hvis vi kort afviger fra emnet, er dette et godt tidspunkt til at tale om en populær mekanisme til at tilføje forsinkelse. Flutter tilbyder flere sådanne teknikker, men konstruktøren Future.delayed er en af de enklere, renere og mere læsevenlige tilgange. For eksempel for at udføre et stykke kode efter 1 sekund:
Future.delayed(Duration(seconds: 1), (){ sum = a + b; // This sum will be calculated after 1 second. print(sum);});
Da forsinkelsesvarigheden allerede er kendt (beregnet ud fra tidligere animationsvarigheder), kan animationen udløses efter dette interval.
// 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; }); });}
Leave a Reply