Tranziții și animație. Tranziții animate între vizualizări

Săptămâna trecută a fost o „vacanță în Velaribo” - am primit actualizarea mult așteptată la versiunea 7.1, care a adăugat câteva funcții și, se presupune, a eliminat unele erori. Dar caracteristica principala Actualizarea a fost o creștere a vitezei. Ei spun că pe „mere” totul a început să zboare. Dragă „Velabagio”, nu mai spălați vasele - citiți mai jos tăietura pentru a afla cum să vă organizați aceeași vacanță!

Pentru ce suntem? iubesc Android? Desigur, pentru flexibilitatea sa. Sistemul nu este doar deschis diverse feluri„decorări” terțe, dar are și unele funcții care permit utilizatorului să schimbe semnificativ experiența de utilizare a dispozitivului.

Și acum vă vom spune despre trei setări simple, care va crește semnificativ viteza cu care apar animațiile atunci când comutați între aplicații, precum și atunci când deschideți și minimizați ferestrele acestora. Pentru a face acest lucru, va trebui să urmați câțiva pași simpli.


Mai întâi, trebuie să accesați elementul de meniu „Opțiuni pentru dezvoltatori”. Pentru a face acest lucru, accesați setările smartphone-ului dvs. și accesați elementul de meniu „Despre dispozitiv”, acolo găsiți linia cu informații despre numărul versiunii și faceți clic pe ea de 7 ori. Dacă nu puteți găsi niciunul dintre elementele de meniu, atunci Google cum să activați „Opțiuni pentru dezvoltatori” în mod specific pe modelul telefonului dvs.

Apoi accesați elementul „Opțiuni pentru dezvoltatori” care apare în setări și găsiți acolo următoarele setări:

  • Scara de animație a ferestrei
  • Scala de animație de tranziție
  • Scala de durată a animatorului

De cel puţin, așa se numesc în Samsung-ul meu. În orice caz, numele ar trebui să fie apropiate ca semnificație, indiferent de producător.

Valorile implicite aici sunt „1x” - schimbați-le în „0,5x”. Voila!

Aceste setări Android vă vor schimba experiența utilizatorului, accelerând tranzițiile între ferestrele de interfață. Adică făcând același lucru ca și Actualizare iOS. Mai mult, acest lucru nu ar trebui să afecteze în niciun fel consumul bateriei. Deși, dacă utilizați un model de telefon mai vechi cu procesor lent, este posibil să vedeți câteva tremurări.

Încearcă-l și împărtășește-ți impresiile în comentarii!

Paul este un avocat pentru design și performanță

Într-o aplicație, este adesea necesar ca utilizatorul să navigheze de la o vizualizare la alta. Aceasta ar putea fi navigarea de la o listă la o vizualizare de detaliu sau afișarea unei bare de navigare laterale. Adăugarea de efecte de animație la tranzițiile dintre aceste vizualizări este excelentă pentru a menține atenția utilizatorului și pentru a crește atracție vizuală proiectele tale

TL;DR

  • Utilizați proprietatea de tranziție pentru a vă deplasa între vederi; Nu trebuie să aplicați left , top sau orice altă proprietate care determină recalcularea aspectului.
  • Orice animație ar trebui să fie instantanee; durata sa nu trebuie să fie lungă.
  • Gândește-te cum se vor schimba lucrurile efecte de animațieși machete pe măsură ce dimensiunea ecranului crește; pentru ce este potrivit ecran mic poate părea ciudat pe ecran dimensiune mare.

Cum vor arăta și cum vor funcționa aceste tranziții între vizualizări depinde în mare măsură de tipul de vizualizări cu care aveți de-a face. Deci, de exemplu, animarea unei suprapuneri modale deasupra unei vizualizări va fi diferită de trecerea dintr-o listă la o vizualizare de detaliu sau invers.

Nota:Ar trebui să vă străduiți să vă asigurați că rata de cadre a oricărei animații este de 60 de cadre pe secundă. Acest lucru va evita bâlbâiala atunci când redați animații, ceea ce este puțin probabil să vă mulțumească utilizatorilor. Orice element care este animat ar trebui să aibă proprietatea de schimbare setat pe toate componentele care se vor schimba, cu mult înainte ca animația în sine să fie implementată. Este foarte probabil ca proprietatea will-change: transform să fie folosită pentru a trece între vederi

Utilizarea atributelor de traducere pentru a vă deplasa între vizualizări

Pentru a menține lucrurile simple, să presupunem că există două vederi: o vizualizare listă și o vizualizare de detaliu. După ce utilizatorul face clic pe un articol din listă din vizualizarea listă, vizualizarea detaliată apare pe ecran și vizualizarea listă dispare de pe ecran.

Pentru a obține acest efect, veți avea nevoie de un container pentru ambele vizualizări, care va fi setat să depășească: ascuns . În acest fel, ambele vizualizări pot fi în container în același timp fără a fi afișate dungi orizontale derulabil, fiecare vedere alunecând dintr-o parte în alta în interiorul containerului, după cum este necesar.

Cod CSS pentru container:

Container ( lățime: 100%; înălțime: 100%; preaplin: ascuns; poziție: relativă; )

Poziția containerului este specificată ca relativă. Aceasta înseamnă că fiecare vedere din interiorul unui container poate fi plasată exact în stânga colțul de sus, apoi mutați folosind proprietatea transform. Această metodă oferă un avantaj de performanță în comparație cu utilizarea proprietăţi rămase(din moment ce face ca aspectul să fie recalculat și pagina să fie efectiv redesenată), este, de asemenea, în general mai ușor de raționalizat.

Vizualizare ( lățime: 100%; înălțime: 100%; poziție: absolut; stânga: 0; sus: 0; /* anunțați browserul că intenționăm să animam fiecare vizualizare în și în afara */ se va schimba: transforma; )

Adăugarea de tranziție la proprietatea de transformare oferă un efect de alunecare atractiv. Pentru ca alunecarea să se simtă bine, trebuie să utilizați o curbă cubic-bezier personalizată, care este discutată în documentul [Ghid pentru modificarea vitezei animației personalizate] (custom-easing.html).

Vizualizare ( /* Sunt necesare prefixe pentru Safari și alte browsere bazate pe WebKit */ tranziție: -webkit-transform 0.3s cubic-bezier(0.465, 0.183, 0.153, 0.946); tranziție: transform 0.3s cubic-bezier(0.465, 0.183) , 0,153, 0,946);

O vedere care dispare de pe ecran ar trebui mutată la dreapta, deci în în acest caz, vizualizarea cu astfel de informații trebuie mutată:

Vizualizare detalii ( -webkit-transform: translateX(100%); transform: translateX(100%); )

Var container = document.querySelector(".container"); var backButton = document.querySelector(".back-button"); var listItems = document.querySelectorAll(".list-item"); /** * Comută clasa pe container, astfel încât * alegem vizualizarea corectă.< listItems.length; i++) { listItems[i].addEventListener("click", onViewChange, false); } // And switch it back again when you click on the back button backButton.addEventListener("click", onViewChange);

*/ funcția onViewChange(evt) ( container.classList.toggle("view-change"); ) // Când faceți clic pe un element din listă, deschideți vizualizarea detaliilor. pentru (var i = 0; i

În cele din urmă, adăugăm declarațiile CSS pentru aceste clase.

View-change .list-view ( -webkit-transform: translateX(-100%); transform: translateX(-100%); ) .view-change .details-view ( -webkit-transform: translateX(0); transform : translateX(0); Acest cod poate fi modificat pentru a include mai multe vizualizări, dar ideea de bază rămâne aceeași. Fiecare vizualizare invizibilă ar trebui să fie păstrată în afara ecranului și să apară pe ea numai atunci când este necesar, și o vizualizare care esteîn acest moment

Nota:este pe ecran, ar trebui să dispară de pe el. browsere diferite, poate foarte sarcină provocatoare. De exemplu, în iOS pentru repornire fling-scroll este necesar proprietate suplimentară CSS, -webkit-overflow-scrolling: atingeți , dar acest lucru nu vă permite să controlați pentru ce axă va funcționa această defilare (în timp ce proprietatea standard de overflow permite acest lucru). Asigurați-vă că testați codul pe diferite dispozitive!

Pe lângă navigarea între vizualizări, această tehnică poate fi folosită și pentru alte elemente de pe ecran, cum ar fi elementele de navigare laterale. Singura diferență este că alte puncte de vedere nu trebuie mutate.

Asigurarea funcționării animației pe ecrane mari

Pe ecranele mari, vizualizarea listă nu trebuie eliminată deloc de pe ecran, iar vizualizarea detaliilor ar trebui să fie afișată cu partea dreaptă. Acest lucru este în esență același cu deschiderea vizualizării de navigare.

O evoluție a CSS3 este capacitatea de a defini comportamentul pentru tranziții și animații. Dezvoltatorii front-end au cerut de ani de zile să implementeze aceste interacțiuni în HTML și CSS, fără folosind JavaScript sau Flash. Acum visul lor s-a împlinit.

Cu tranzițiile CSS3 aveți potențialul de a vă schimba aspectși comportamentul elementului ori de câte ori starea acestuia se schimbă, cum ar fi atunci când elementul este plasat peste, primește focalizare, devine activ sau este urmat de o legătură.

Animația în CSS3 vă permite să schimbați aspectul și comportamentul unui element folosind câteva cadre cheie. Tranzițiile oferă o tranziție de la o stare la alta, în timp ce animația poate stabili mai multe puncte de tranziție în cadre cheie diferite.

Tranziții

Cadru cheie de animație

Pentru a seta mai multe puncte în care un element ar trebui să tranziție, este utilizată regula @keyframes. Această regulă include numele animației, orice număr de puncte de control și proprietățile care urmează să fie animate.

@keyframes slide ( 0% ( stânga: 0; sus: 0; ) 50% ( stânga: 244px; sus: 100px; ) 100% ( stânga: 488px; sus: 0; ) )

Prefixele furnizorului în regula @keyframes

Regula @keyframes trebuie să aibă prefixul furnizorului, la fel ca toate celelalte proprietăți de tranziție și animație. Prefixele pentru @keyframes arată astfel:

  • @-moz-keyframes
  • @-o-keyframes
  • @-webkit-keyframes

Animația de mai sus se numește slide , stările încep imediat după ce regula @keyframes este deschisă. Diferite puncte de întrerupere ale cadrelor cheie sunt setate folosind procente, începând de la 0% și lucrând până la 100%, cu punct intermediar cu 50%. Dacă se dorește, cuvintele cheie de la și către pot fi folosite în loc de 0% și 100%. Pe lângă 50%, pot fi specificate și puncte de control suplimentare. Proprietățile elementelor de animat sunt listate în interiorul fiecărui punct de control, în stânga și sus în exemplul de mai sus.

Este important de reținut, ca și în cazul tranzițiilor, numai proprietățile individuale pot fi animate. Gândiți-vă la cum ați putea muta un element de sus în jos, de exemplu. Încercarea de a anima de sus: 0 în jos: 0 nu va funcționa, deoarece animația poate aplica doar o tranziție într-o proprietate, nu de la o proprietate la alta. În acest caz, elementul trebuie să fie animat de sus: 0 până sus: 100%.

animatie-nume

Odată ce cadrele cheie pentru animație sunt declarate, acestea trebuie alocate elementului. Pentru a face acest lucru, utilizați proprietatea animation-name cu numele animației din regula @keyframes ca valoare a proprietății. Declarația de nume animație se aplică elementului pentru care urmează să fie specificată animația.

Stage:hover .ball (nume animație: slide; )

Utilizarea proprietății animation-name singură nu este suficientă. În plus, trebuie să declarați o proprietate de durată a animației și o valoare, astfel încât browserul să știe cât de mult ar trebui să dureze animația înainte de a termina.

animație-durată, funcție de timp și animație-întârziere

Odată ce ați declarat proprietatea animation-name pe un element, animațiile se comportă ca niște tranziții. Acestea includ durata, funcția de timp și întârzierea, dacă se dorește. Animația necesită mai întâi o durată, declarată folosind proprietatea animation-duration. Ca și în cazul tranzițiilor, durata poate fi specificată în secunde sau milisecunde.

Stage:hover .ball ( animație-nume: diapozitiv; animație-durată: 2s; )

Funcția de sincronizare și întârzierea pot fi declarate utilizând proprietățile animație-funcție-temporizare și, respectiv, animație-întârziere. Valorile acestor proprietăți sunt imitate și se comportă în același mod ca și tranzițiile.

Stage:hover .ball ( animație-nume: diapozitiv; animație-durată: 2s; animație-timing-funcție: ease-in-out; animație-întârziere: .5s; )

Animația de mai jos ar trebui să facă mingea să sară o dată când se deplasează spre dreapta, dar numai când trece cu mouse-ul peste scenă.

@keyframes slide ( 0% ( stânga: 0; sus: 0; ) 50% ( stânga: 244px; sus: 100px; ) 100% ( stânga: 488px; sus: 0; ) ) .stage ( înălțime: 150px; poziție: relativ; ) .ball ( înălțime: 50px; poziție: absolut; lățime: 50px; ) .stage:hover .ball ( animație-nume: slide; animație-durată: 2s; animație-timing-funcție: ease-in-out; întârziere animație: .5s)

Setări de animație

Animația oferă, de asemenea, posibilitatea personalizare ulterioară comportamentul elementului, inclusiv de câte ori rulează animația și direcția în care se termină animația.

animație-iterație-număr

În mod implicit, animația se realizează o dată de la început până la sfârșit și apoi se oprește. Pentru a face animația să se repete de mai multe ori, poate fi utilizată proprietatea animation-iteration-count. Valorile pentru acesta includ un număr întreg sau cuvântul cheie infinit. Folosirea unui număr întreg va repeta animația de câte ori este specificat, în timp ce cuvântul cheie infinit va repeta animația la nesfârșit și nu se va opri niciodată.

Stage:hover .ball (nume animație: slide; animație-durată: 2s; animație-timing-funcție: ease-in-out; animation-delay: .5s; animație-iterație-număr: infinit; )

regia-animatie

Pe lângă faptul că puteți seta de câte ori se repetă animația, puteți declara și direcția în care se termină animația folosind proprietatea animation-direction. Valorile pentru această proprietate includ normal, invers, alternativ și alternativ-invers.

Valoarea normală redă animația așa cum este intenționat, de la început până la sfârșit. Valoarea inversă redă animația exact în sens invers, așa cum este definit în regula @keyframes, începând astfel de la 100% și rulând la sens invers până la 0%.

Valoarea alternativă va reda animația înainte și apoi înapoi. În cadrele cheie, aceasta implică executarea înainte de la 0% la 100% și apoi înapoi de la 100% la 0%. Folosind proprietatea animation-iteration-count, puteți limita numărul de ori în care animația rulează înainte și înapoi. Numărarea începe de la 1 pe măsură ce animația avansează de la 0% la 100%, apoi se adaugă 1 pe măsură ce animația progresează la ordine inversă de la 100% la 0%. Combinând un total de două iterații. Valoarea alternativă inversează, de asemenea, caracteristicile oricărui timp când se redă înapoi. Dacă o animație folosește o valoare de ease-in care merge de la 0% la 100%, atunci folosește o valoare de ease-out care merge de la 100% la 0%.

În cele din urmă, valoarea alternativ-invers combină atât valorile alternative, cât și cele inverse, rulând animația înapoi și apoi înainte. Valoarea inversă alternativă începe de la 100% și rulează la 0% și apoi înapoi la 100%.

Stage: hover .ball ( animație-nume: diapozitiv; animație-durată: 2s; animație-funcție de sincronizare: ease-in-out; animation-delay: .5s; animație-iterație-număr: infinit; animație-direcție: alternativă )

animație-play-stare

Proprietatea animation-play-state permite ca animația să fie redată sau întreruptă, folosind cuvinte cheie alergare și, respectiv, pauză. Când animația este întreruptă, se reia de la starea actuală, mai degrabă decât a începe din nou de la început.

Exemplul de mai jos setează proprietatea animation-play-state să se întrerupă atunci când scena este activă când se face clic pe ea. Observați cum animația se întrerupe temporar până când eliberați butonul mouse-ului.

Stage: hover .ball ( animație-nume: diapozitiv; animație-durată: 2s; animație-funcție de sincronizare: ease-in-out; animation-delay: .5s; animație-iterație-număr: infinit; animație-direcție: alternativă ; ) .stage:activ .ball ( animație-play-state: pauză; )

animație-umplere-mod

Proprietatea animation-fill-mode determină modul în care ar trebui să fie stilat elementul - înainte, după sau înainte și după începerea animației. Proprietatea animation-fill-mode acceptă patru valori ale cuvintelor cheie, inclusiv none , forwards , backwards și ambele .

Valoarea none nu va aplica niciun stil elementului înainte sau după începerea animației.

Valoarea forwards va păstra stilurile declarate în ultimul cadru cheie specificat. Aceste stiluri, însă, pot fi afectate de valorile proprietăților animație-direcție și animație-iterație-număr, schimbând unde se termină animația.

Valoarea inversă va aplica stilurile primului cadru cheie specificat înainte de rularea animației. Permite aplicarea acestor stiluri cât mai mult posibil, ceea ce poate fi setat în animație-întârziere . Valoarea înapoi poate depinde și de valoarea proprietății animație-direcție.

În cele din urmă, valoarea ambelor va aplica comportamentul de la valorile înainte și înapoi simultan.

Stage:hover .ball (animation-name: slide; animation-durata: 2s; animation-timing-function: ease-in-out; animation-delay: .5s; animation-fill-mode: forward; ) .stage:activ .ball ( animație-play-state: paused; )

proprietatea stenografiei animației

Din fericire, animațiile, precum tranzițiile, pot fi înregistrate într-un format scurtat. Acest lucru se realizează prin utilizarea unei singure proprietăți de animație în loc de declarații multiple. Ordinea valorilor în proprietatea animației ar trebui să fie: animation-name , animation-duration , animation-timing-function , animation-delay , animation-iteration-count , animation-direction , animation-fill-mode și în final animație- joc- stare.

Stage:hover .ball (animație: slide 2s ease-in-out .5s infinite alternate; ) .stage:active .ball (animation-play-state: paused; )

Resurse și link-uri

  • Înțelegerea tranzițiilor CSS3 pe o listă aparte
  • CSS Cubic-Bezier Builder de Rob LaPlaca
  • Ghidul pentru animația CSS: principii și exemple pe Smashing Magazine
  • Utilizarea animațiilor CSS pe Mozilla Developer Network

Vizualizări post: 3.215

Tranzițiile aplicației Design material asigură integritatea vizuală. Pe măsură ce utilizatorul navighează prin aplicație, diverse elemente ale aplicației își schimbă starea. Mișcarea și transformarea întăresc ideea că interfața este tangibilă și conectează elemente comune ale reprezentărilor.

În acest articol vom demonstra cum să implementăm o tranziție de la imagine la imagine. RecyclerView pe o activitate în imagine în ViewPagerîntr-o altă activitate folosind Elemente comune pentru a determina ce reprezentări sunt implicate în procesul de tranziţie şi cum. Ne vom uita si la caz dificil revenind la listă la un element care nu era anterior pe ecran.

Iată rezultatul pe care îl vom obține:

Care sunt elementele comune?

O tranziție de element partajat definește modul în care un element care este prezent în două activități se anime între ele. De exemplu, o imagine care este afișată în ImageView asupra activităților OŞi B, se mută din activitate O la activitate B Când B devine vizibil.

Implementarea tranziției de la RecyclerView la ViewPager

Mai jos este o animație a unui element partajat care trece de la RecyclerView la ViewPager.

Mai întâi, să deschidem fișierul res/values-v21/styles.xml iar în proprietățile temei vom seta windowsContentTransitions și animație.

adevărat @transition/change_image_transform

Acum să definim animația prin crearea unui fișier change_image_transform.xmlîntr-un folder res/tranziție.

RecyclerView și ViewPager folosesc un adaptor pentru a funcționa, astfel încât nu pot seta transitionName în marcajul XML. Trebuie folosit View.setTransitionName()Şi View.setTag() pentru a instala dinamic transitionNameŞi etichetă respectiv în timpul legării vederii la adaptor. Prin urmare, în metoda adaptorului onBindViewHolder() să adăugăm următorul cod:

@Override public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) ( holder.image.setTag(position); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) ( holder.image.setTransitionName(holder.image) .getContext().getString(R.string.transition_name, position)); // ca exemplu, resursa R.string.transition_name este setată la name%1$d ) )

Aici este câmpul imagine este ImageView a cărui animație de tranziție o vom implementa. Ca rezultat, fiecărui element i se va da un transitionName egal cu numeX, Unde X— poziția elementului în listă.

Nota:în exemplul nostru vor fi folosite următoarele nume de activitate: SourceActivity pentru activitatea cu RecycleView și DestinationActivity pentru activitatea cu ViewPager.

Este important să înțelegeți că animația de tranziție a unui element comun necesită o relație unu-la-unu pentru a defini animația. Următoarele puncte sunt, de asemenea, importante:

  • În primul rând, fiecare vedere trebuie să aibă un unic transitionName.
  • În al doilea rând, trebuie să așteptați până ViewPager va începe să arate imagini înainte de a începe animația.

Acum trebuie să implementăm procesarea clicurilor pe un element. Când faceți clic, se va deschide o a doua activitate, în care vor fi transferate numele și eticheta create. Pentru a face acest lucru, vom redirecționa un ascultător din activitate către adaptor.

Interfață ClickListener ( void onItemClick (ImageView imagine); ) ascultător ClickListener privat; ... RecyclerAdapter (Lista de fotografii Listă, ascultător ClickListener) ( this.photoList = new ArrayList<>(fotoLista); asta.ascultător = ascultător; ) ... @Override public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) ( final int fotografie = photoList.get(position); holder.image.setImageResource(photo); holder.image.setTag(position); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) ( holder.image.setTransitionName(holder.image.getContext().getString(R.string.transition_name, position)); ) holder.image.setOnClickListener(new View.OnClickListener() ( @Override public void onClick( Vedere vizualizare }

) ( listener.onItemClick(holder.image); ) )); În activitate, să creăm o instanță a acestui ascultător și să înlocuim metoda.

@Override protected void onCreate(Bundle savedInstanceState) ( ... recyclerView.setAdapter(new RecyclerAdapter(photoList, new RecyclerAdapter.ClickListener()) ( @Override public void onItemClick(ImageView imagine) ( Intenție = new Intent(SourceActivity.Activity.this) .class); intent.putExtra("curent", (int) image.getTag()); options = ActivityOptions.makeSceneTransitionAnimation(SourceActivity.this, image, image.getTransitionName() startActivity(intent, options.toBundle()) else ( startActivity(intent); ) ));

Principalul punct aici este folosirea obiectului Opțiuni de activitate, în care folosind metoda makeSceneTransitionAnimation() a trecut contextul, vizualizarea de animat și transiția sa.

După aceasta, începe intenția și trecem la activitate cu ViewPager. După cum am menționat mai sus, nu puteți începe imediat o animație când începe activitatea, deoarece ViewPager necesită timp pentru a genera elementele. Deci înainte de a suna setContentView()în metodă onCreate() adăugați un apel de metodă postponeEnterTransition(), care împiedică trecerea unui element comun.

@Override protected void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) ( postponeEnterTransition(); ) setContentView(R.layout.activity_destination); )

După aceasta, începe inițializarea ViewPagerși transferul de date către adaptor. În adaptor, trebuie să setăm același transitionName și aceeași etichetă pe care le avea elementul din RecyclerView și apoi să mă sunăm

@Override @NonNull public Object instantiateItem(@NonNull ViewGroup collection, int position) ( int fotografie = photoList.get(position); LayoutInflater inflater = LayoutInflater.from(mContext); View v = inflater.inflate(R.layout.item, collection, false); ImageView img = v.findViewById(R.id.image); Nume șir = mContext.getString(R.string.nume_tranziție, poziție); img.setTag(poziție); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) ( img.setTransitionName(nume); if (poziție == curent) ( listener.setStartPostTransition(img); ) )întoarcere v; )

Acum că totul este pregătit, trebuie să începem animația. Să transmitem interfața adaptorului din activitate, în care, folosind metoda setStartPostTransition() Să începem animația care a fost întreruptă când a început activitatea.

@TargetApi(21) @Override public void setStartPostTransition(vizualizare finală View) ( view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() ( @Override public boolean onPreDraw() ( view.getViewTreeObserver(reistene) ); startPostponedEnterTransition(); returnează false;

Ca rezultat, vom obține o animație lină a tranziției de la RecyclerView la ViewPager.

Implementarea tranziției de la ViewPager la RecyclerView

Acum trebuie să realizăm o animație inversă când ne întoarcem de la DestinationActivity la SourceActivity. Problema principală aici poate fi că la revenirea la prima activitate, același element nu va reveni neapărat așa cum a fost în timpul tranziției. În acest caz, trebuie să determinați poziția noului element, să derulați dacă este necesar și să redați animația.

ÎN DestinationActivity trebuie să trecem peste metoda finishAfterTransition(), în interiorul căruia trebuie să plasați poziția curentă a elementului în intenție.

@Override public void finishAfterTransition() ( int pos = viewPager.getCurrentItem(); Intent intent = new Intent(); intent.putExtra("exit_position", pos); setResult(RESULT_OK, intent); if (current != pos) ( View View = viewPager.findViewWithTag(pos); setSharedElementCallback(view); ) super.finishAfterTransition( ) @TargetApi(21) private void setSharedElementCallback(final View view) ( setEnterSharedElementCallback(new SharedElementCallback(new SharedElementCallback) (new SharedElementElementCallback) onMaiS public (onMail) (Listă nume, Hartă sharedElements) ( names.clear(); sharedElements.clear(); names.add(view.getTransitionName()); sharedElements.put(view.getTransitionName(), vizualizare); ) )); )

Dacă poziția actuală nu coincide cu cea care era atunci când a început activitatea, atunci trebuie să apelați metoda setEnterSharedElements(), în care actualizăm lista de elemente partajate, înlocuind elementul vechi cu unul nou.

După aceasta, activitatea se închide și ne întoarcem la SourceActivity. Aici numim metoda activitatii onActivityReenter() pentru a prinde intentia cu pozitia.

Public void onActivityReenter(int resultCode, Intent data) ( super.onActivityReenter(resultCode, date); if (resultCode == RESULT_OK && data != null) ( exitPosition = data.getIntExtra("exit_position", 0); if (Build. VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) ( final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); View viewAtPosition = layoutManager.findViewByPosition(exitPosition); // Derulați la poziția dacă vizualizarea pentru poziția curentă nu este nulă (adică // nu face parte din elementele secundare ale managerului de layout) sau dacă // nu este complet vizibil dacă (viewAtPosition == null || layoutManager.isViewPartiallyVisible(viewAtPosition, false, true)) ( layoutManager.scrollToPosition(. exitPosition); setTransitionOnView ( );

Dacă nu aveți nevoie să defilați sau defilarea este completă, începeți să redați animația. În acest scop se numește metoda setTransitionOnView(), în care așteptăm sfârșitul derulării și începem animația.

@TargetApi(Build.VERSION_CODES.LOLLIPOP) clasă statică privată CustomSharedElementCallback extinde SharedElementCallback ( private View mView; public void setView (View view) ( mView = view; ) @Override public void onMapSharedElements(List) nume, Hartă sharedElements) ( names.clear(); sharedElements.clear(); if (mView != null) ( String transitionName = ViewCompat.getTransitionName(mView); names.add(transitionName); sharedElements.put(transitionName, mView); ) ) ) @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void setTransitionOnView() ( callback final CustomSharedElementCallback = nou CustomSharedElementCallback(); setExitSharedElementCallback(callback); getWindow().getSharedElementExitTransition(Listende.Transition(new)(New). public void onTransitionStart(Tranziție de tranziție) ( ) @Override public void onTransitionPause (Tranziție de tranziție) ( ) @Override public void onTransitionResume (Tranziție de tranziție) ( ) @Override public void onTransitionEnd(Tranziție de tranziție) ( removeCallback(); ) @Override public void onTransitionCancel(Tranziție de tranziție) ( removeCallback(); ) private void removeCallback() ( getWindow().getSharedElementExitTransition().removeListener(this);

setExitSharedElementCallback(null);

) ));

postponeEnterTransition(); recyclerView.getViewTreeObserver() .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() ( @Override public boolean onPreDraw() ( recyclerView.getViewTreeObserver().removeOnPreDrawListener(this.Viewer.ViewerPoder); tion(exitPosition); if ( holder instanceof RecyclerAdapter.MyViewHolder) ( callback.setView(((RecyclerAdapter.MyViewHolder) holder).image); ) return true ) )); ) Asta e tot. Acum animația de tranziție inversă va funcționa chiar dacă elementul nu a fost vizibil anterior.

Exemplul de cod sursă poate fi vizualizat pe GitHub accesând Una dintre pietrele de temelie în Design material

sunt mișcări semnificative între ecrane. Lollipop oferă suport pentru aceste animații sub forma unui cadru de tranziție între Activitate și Fragment. Deoarece nu sunt multe articole pe această temă, m-am hotărât să le scriu pe al meu! Noastre produs final

va fi destul de simplu. Vom face o aplicație de galerie cu pisici. Făcând clic pe imagine, se va deschide un ecran cu detalii. Datorită cadrului, trecerea de la grila de imagini la fereastra de detalii va fi însoțită de animație. Daca vrei sa vezi ce s-a intamplat... aplicare gata

Am două vești pentru tine: bune și rele. Vestea proastă este că acest cadru nu funcționează înainte de Lollipop. În ciuda acestui fapt, problema este rezolvată prin metodele bibliotecii de suport cu care puteți implementa tranziții animate disponibile în API 21+.

Acest articol va folosi funcții din biblioteca de asistență pentru a permite mișcarea conținutului.

Nume de tranziție

Pentru a asocia vizualizarea de pe primul ecran cu omologul său de pe al doilea, este nevoie de o conexiune. Lollipop sugerează folosirea „ nume de tranziție” pentru comunicarea între Vizualizări.

Există două moduri de a adăuga un nume de tranziție ( nume de tranziție) pentru vizualizarea dvs.:

  • Puteți utiliza ViewCompat.setTransitionName() în codul dvs. Desigur, puteți, de asemenea, să apelați setTransitionName() dacă suportul începe cu Lollipop.
  • Pentru a-l adăuga în XML, utilizați atributul android:transitionName.
Este important de reținut că într-un singur aspect ( aspect), numele de tranziție trebuie să fie unice. Țineți cont de acest lucru atunci când organizați tranzițiile. Arătând nume de tranziție pentru ListView sau RecyclerView va seta același nume pentru toate celelalte elemente.

Configurarea FragmentTransaction

Configurarea FragmentTransactions ar trebui să vă fie foarte familiară:

GetSupportFragmentManager() .beginTransaction() .addSharedElement(sharedElement, transitionName) .replace(R.id.container, newFragment) .addToBackStack(null) .commit();
Pentru a specifica ce vizualizare vom transfera între fragmente, folosim metoda addSharedElement().

Vederea transmisă la addSharedElement() este vizualizarea din primul fragment pe care doriți să-l partajați ( împărtășește) cu al doilea fragment. Numele tranziției aici este numele tranziției în formatul separat ( împărtășită) Vezi în al doilea fragment.

Configurarea animației de tranziție

În sfârșit, a sosit momentul în care vom seta animația de tranziție între fragmente.

Pentru elementele comune:

  • Pentru a trece de la primul fragment la al doilea, folosim metoda setSharedElementEnterTransition().
  • Pentru a reveni înapoi folosim metoda setSharedElementReturnTransition(). Animația va avea loc când apăsați butonul Înapoi.
Rețineți că trebuie să apelați aceste metode în al doilea fragment, deoarece dacă faceți acest lucru în primul, nu se va întâmpla nimic.

De asemenea, puteți anima tranzițiile pentru toată lumea nedistribuit Vedere. Pentru aceste vizualizări, utilizați setEnterTransition() , setExitTransition() , setReturnTransition() și setReenterTransition() în fragmentele corespunzătoare.

Fiecare dintre aceste metode acceptă un parametru de tranziție destinat realizării animației.

Vom crea animație foarte simplu. Folosim tranziția personalizată pentru a muta imaginea (mai multe despre asta mai târziu) și Fade când ieșim.

Cursuri de animație de tranziție

Android oferă câteva animații de tranziție prestabilite care sunt potrivite pentru majoritatea cazurilor. Fade realizează o animație de estompare. Slide animă tranziția apariție/dispariție prin alunecarea din colțul ecranului. Explode O animație asemănătoare unei explozii, imaginea se mișcă de la marginile ecranului. În cele din urmă, AutoTranziția va face ca imaginea să se estompeze, să se miște și să redimensioneze. Acestea sunt doar câteva exemple din pachetul de mutari, de fapt sunt multe altele!

Am menționat că vom avea nevoie de o tranziție personalizată pentru imaginea noastră. Iată-l:

Clasa publică DetailsTransition extinde TransitionSet ( public DetailsTransition() ( setOrdering(ORDERING_TOGETHER); addTransition(new ChangeBounds()). addTransition(new ChangeTransform()). addTransition(new ChangeImageTransform())); ) )
Tranziția noastră personalizată nu este altceva decât un set de trei tranziții gata făcute asamblate împreună:

Toți împreună

Codul cu care am ajuns sa dovedit a fi destul de simplu:

DetailsFragment details = DetailsFragment.newInstance(); // Rețineți că avem nevoie de verificarea versiunii API aici, deoarece clasele reale de tranziție (de exemplu, Fade) // nu suntîn biblioteca de asistență și sunt disponibile numai în API 21+. Metodele pe care le apelăm la Fragment // SUNT disponibile în biblioteca de suport (deși nu fac nimic pe API< 21) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) ( details.setSharedElementEnterTransition(nou DetailsTransition()); details.setEnterTransition(new Fade()); setExitTransition(new Fade()); details.setSharedElementReturnTransition(new DetailsTransition()); ) getActivity() .getSupportFragmentManager() .beginTransaction() .addSharedElement(holder.image, "sharedImage") .replace(R.id.container, detalii) .addToBackStack(null) .commit();
Asta este! O modalitate simplă de a implementa animația tranzițiilor între două fragmente este gata!

  • Serghei Savenkov

    un fel de recenzie „scurtă”... de parcă s-ar grăbi undeva