Izgradnja interaktivnog zaslona za prijavu s Flare & Flutter-om

Nedavno je naš tim u 2Dimensions naišao na interaktivni oblik Remembear prijave: mislili smo da je ovo savršen primjer koji možemo graditi u Flareu i dijeliti sa zajednicom!

Izvorni kod dostupan je na GitHub-u, a datoteka Flare može se naći na 2Dimensions.

Pregled

Prvo moramo uvesti biblioteku flare_flutter u pubspec.yaml (N.B. Koristimo relativan put od trenutka kada smo u repo biblioteci, ali je paket dostupan i na DartPubu). U pubspec.yaml smo dodali i mapu imovine tako da je njen sadržaj dostupan u programu Flutter.

Sve se datoteke nalaze u mapi / lib, dok se datoteka Flare nalazi u mapi imovine:

/ lib
  - input_helper.dart
  - glavni.dart
  - signin_button.dart
  - teddy_controller.dart
  - track_text_input.dart
/imovina
  - Teddy.flr

Kako ovo funkcionira

Pogledajmo prvo Teddyja u Flareu: ovaj lik ima čvor ctrl_face koji je cilj za ograničenje prijevoda elemenata lica. To znači da će pomicanje čvora također pokrenuti sve njegove ovisnike.

Uhvativši referencu na ctrl_face čvor, možemo pomaknuti Teddyjevo lice i prilagoditi smjer njegova pogleda. Trebat ćemo pronaći položaj tekstnog polja ispod Teddyja i prilagoditi položaj čvora ctrl_face u skladu s tim.

U kodeks

U main.dartu, MyHomePage gradi izgled za aplikaciju.
Za postavljanje animacije u prikaz koristimo widget FlareActor iz biblioteke flare_flutter:

[...]
FlareActor (
  „Imovina / Teddy.flr”
  // Vezati FlareController
  kontroler: _teddyController
  [...]
)

Budući da želimo manipulirati položajem ctrl_face čvora, vežemo _teddyController za naš FlareActor. Kontrolor je konkretna implementacija FlareController-a, sučelja koje nudi flare_flutter, a omogućuje nam ispitivanje i upravljanje hijerarhijom Flare-a.

Prilagođene kontrole

Pogledajmo klasuTeddyController: primijetit ćete da TeddyController proširuje FlareControls, a ne FlareController!
FlareControls je konkretna implementacija FlareControllera koju flare_flutter već nudi, a ima i nekoliko osnovnih play / mix funkcija.

TeddyController ima nekoliko polja:

// Matrica za transformiranje Flutter globalnih koordinata
// u koordinate svijeta Flare.
Mat2D _globalToFlareWorld = Mat2D ();
// Upućivanje na čvor `ctrl_look`.
ActorNode _faceControl;
// Spremite podrijetlo čvora u svjetske i lokalne prostore transformacije.
Vec2D _faceOrigin = Vec2D ();
Vec2D _faceOriginLocal = Vec2D ();
// Karet u globalnim koordinatama lepršavih i u svjetskim koordinatama Flare.
Vec2D _caretGlobal = Vec2D ();
Vec2D _caretWorld = Vec2D ()

Nakon toga će ova klasa morati nadjačati tri metode: inicijalizirati (), unaprijed () i setViewTransform ().
zove se inicijalizacija () - pogodili ste! - u vrijeme inicijalizacije, kada je ugrađen widget FlareActor. Ovdje se prvo preuzima naša referenca na čvor, opet s pozivom u biblioteku:

_faceControl = artboard.getNode ("ctrl_face");
ako je (_faceControl! = null) {
  _faceControl.getWorldTranslation (_faceOrigin);
  Vec2D.copy (_faceOriginLocal, _faceControl.translation);
}
igrati ( "praznom hodu");

Artboards in Flare su spremnici najviše razine za čvorove, oblike i animacije. artboard.getNode (Ime niza) vraća referencu ActorNode s danim imenom.

Nakon što spremimo referencu čvora, spremamo i izvorni prijevod tako da je možemo vratiti kada tekstualno polje izgubi fokus i počnemo reproducirati animaciju u praznom hodu.

Druga dva poništavanja nazivaju se svaki okvir: setViewTransform () koristi se ovdje za izgradnju _globalToFlareWorld - to je matrica za transformiranje globalnih koordinata lepršavog zaslona u koordinate Flare svijeta.

Unaprijed () metoda je ona gdje se sve gore navedeno spaja!
Kada korisnik počne tipkati, TrackingTextInput će položaj zaslona karata prenijeti u _caretGlobal. Pomoću ove koordinate kontroler može izračunati novi položaj ctrl_face i na taj način preusmjeravati svoj pogled.

// Projektni pogled naprijed za ovoliko piksela.
statički const double _projectGaze = 60,0;
[...]
// Nabavite karet u svjetskom prostoru Flare.
Vec2D.transformMat2D (
  _caretWorld, _caretGlobal, _globalToFlareWorld);
[...]
// Izračunajte vektor smjera.
Vec2D toCaret = Vec2D.subtrakt (Vec2D (), _caretWorld, _faceOrigin);
Vec2D.normalizirati (toCaret, toCaret);
// Smanjite smjer stalnom vrijednošću.
Vec2D.scale (toCaret, toCaret, _projectGaze);
// Izračunajte transformaciju koja nas dobiva u prostoru ctrl_face.
Mat2D toFaceTransform = Mat2D ();
ako (Mat2D.invert (toFaceTransform,
        _faceControl.parent.worldTransform)) {
  // Stavite toCaret u lokalni prostor.
  // N.B. koristimo vektor smjera, a ne prijevod,
  // pa za transformiranje bez prijevoda koristite transformMat2 ()
  Vec2D.transformMat2 (toCaret, toCaret, toFaceTransform);
  // Konačni položaj ctrl_face izvorni je prijevod lica
  // plus ovaj vektor
  targetTranslation = Vec2D.add (Vec2D (), toCaret, _faceOriginLocal);
}

Budući da slika vrijedi tisuću riječi - ili u ovom slučaju linije koda - ispod, možemo vidjeti kako se izračunava smjer: vektor razlike pohranjen je u toCaret.

Budući da je to smjer, on se normalizira, a zatim povećava brojem piksela što bi ga trebalo projicirati iz svoje izvorne pozicije.

Napokon, toCaret pretvaramo u vlastiti prostor čvora tako da ga možemo dodati izvornom prijevodu čvora.

Položaj karata

Posljednji komad slagalice je kako izračunati položaj zaslona karata.

To se postiže u widgetu TrackingTextInput. Ovaj widget pohranjuje referencu na GlobalKey za izgradnju njegovih TextFormFields. Kroz ovaj ključ, Flutter nam omogućava da dobijemo RenderObject koji obuhvaća ovo TextFormField:

RenderObject fieldBox = _fieldKey.currentContext.findRenderObject ();

S tri pomoćne funkcije dostupne u lib / input_helper.dart, možemo koristiti RenderBox za izračunavanje stvarnog položaja karata u koordinatama zaslona prelazeći hijerarhiju widgeta s tog RenderBoxa i tražeći RenderEditable. Ova klasa lepršavanja pruža metodu getEndpointsForSelection () koja se koristi za računanje lokalnih koordinata, a koje originalniRenderBox može pretvoriti u globalne koordinate.

I to je to!

Još jednom provjerite izvore na GitHub-u i Flareu i pridružite nam se na 2Dimensions.com!