Von Dribbble zu Android Motion



Im Internet gibt es viele interessante animierte Vorlagen mit schönen Benutzeroberflächen für mobile Anwendungen, aber es gibt nicht viele Beispiele für die Implementierung dieser Schnittstellen. Trotz der Fülle verschiedener integrierter Frameworks und Tools im Android SDK ist es für Anfänger oft nicht einfach, eine schöne Benutzeroberfläche zu implementieren, auch mit einer vorgefertigten Vorlage.

In diesem Artikel werden wir versuchen, die vom Designer Ivan Parfyonov für das PLATES-Studio entwickelte Benutzeroberfläche zu implementieren.


Erstellen Sie zunächst zwei Fragmente: RecyclerFragment und DetailsFragment .


Android Transition Framework?


Das Android Transition Framework funktioniert gut, aber es gibt einige Nuancen. Erstens möchten wir, dass zumindest für API 19 alles für uns funktioniert, und zweitens müssen wir mehrere Benutzerelemente gleichzeitig animieren, von denen einige nur in einem Fragment vorhanden sind. Daher implementieren wir die Animation des Übergangselements (Shared Element Transition) manuell mit ViewPropertyAnimator .

Alles in Ordnung


  1. Wir berechnen die endgültigen Koordinaten des ausgewählten Elements aus der Liste (seine Koordinaten in DerailsFragment ). Die Liste ist eine RecyclerView .
  2. Wir speichern die aktuellen Koordinaten (Koordinaten in RecyclerFragment ) und übergeben sie an DetailsFragment (dies ist für die umgekehrte Animation mit API <21 erforderlich).
  3. Erstellen Sie eine Kopie des ausgewählten Elements aus der Liste.
  4. Wir machen das ausgewählte Element unsichtbar (keine Kopie, sondern das Element selbst);
  5. Fügen Sie die in Schritt 3 erstellte Kopie zum Stammlayout des übergeordneten Fragments hinzu. In unserem Fall handelt es sich um RecyclerFragment .
  6. Wir starten die Animation der verbleibenden Schnittstellenelemente und verschieben die erstellte Kopie ab Schritt 1 an die endgültigen Koordinaten.
  7. Wenn die Animation beendet ist, erstellen Sie eine Transaktion und zeigen Sie DetailsFragment .
  8. Wir starten die Animation von Schnittstellenelementen in DetailsFragment .

UI-Elemente Animation


Um die Toolbar zu animieren Toolbar erstellen wir eine zusätzliche View im RecyclerFragment und platzieren sie oben hinter dem Bildschirm. Diese View wird mit DetailsFragment im DetailsFragment in DetailsFragment (blaue Farbe auf ViewPropertyAnimator ) ViewPropertyAnimator .

 <View android:id="@+id/details_toolbar_helper" android:layout_width="wrap_content" android:layout_height="@dimen/details_toolbar_container_height" android:background="@color/colorPrimary" app:layout_constraintTop_toTopOf="parent"/> // In RecyclerFragment details_toolbar_helper.translationY = -details_toolbar_helper.height 

Bild

BottomNavigationView und RecyclerView Animationen BottomNavigationView ebenfalls mit ViewPropertyAnimator implementiert, ViewPropertyAnimator nicht kompliziert ist (Transparenz ändern und verschieben).

Ein bisschen vom Transition Framework


Mit einfachen Worten, dann erstellt das Android-Übergangsframework beim Animieren des Übergangselements eine Kopie des Inhalts dieses Übergangselements (z. B. Druckbildschirm), erstellt aus dieser Kopie eine ImageView und fügt dieses Bild der zusätzlichen Überlagerungsebene in der Überlagerungsebene hinzu das aufgerufene Fragment und startet die Animation.

Das Android Transition Framework ist für uns nicht ganz geeignet, weil Wenn die Übergangselementanimation beginnt, werden alle anderen Elemente der Benutzeroberfläche im Fragment zerstört und können nicht animiert werden. Das heißt, Wenn wir in RecyclerFragment auf ein Listenelement klicken, um DetailsFragment zu öffnen und eine Übergangsanimation zu starten, werden alle anderen Oberflächenelemente in RecyclerFragment ohne Animation zerstört.

Um das gewünschte Ergebnis zu erzielen, erstellen wir manuell eine Kopie des aus der Liste ausgewählten Elements, fügen es der Überlagerungsebene hinzu und animieren es dann. Hier tritt jedoch ein kleines Problem auf. In der Dokumentation zur ViewGroupOverlay add(view: View) Methode ViewGroupOverlay add(view: View) heißt es:
Wenn die Ansicht ein übergeordnetes Element hat, wird die Ansicht von diesem übergeordneten Element entfernt, bevor sie dem Overlay hinzugefügt wird.

Bei RecyclerView funktioniert dies jedoch nicht. Das ausgewählte Element wird nicht aus RecyclerView gelöscht, nachdem es der Überlagerungsebene hinzugefügt wurde.

Folgendes passiert, wenn wir das ausgewählte Element zur Überlagerungsebene hinzufügen:



Und wir brauchen das:



Daher werden wir die Überlagerungsebene nicht verwenden und die Kopie sofort zum Stammlayout hinzufügen. Erstellen Sie eine Kopie des Inhalts des ausgewählten Elements, fügen Sie es der ImageView und legen Sie die Koordinaten fest:

 fun View.copyViewImage(): View { val copy = ImageView(context) val bitmap = drawToBitmap() copy.setImageBitmap(bitmap) //  pre-Lollipop   ,   card view  ,      card view return (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { CardView(context).apply { cardElevation = resources.getDimension(R.dimen.card_elevation) radius = resources.getDimension(R.dimen.card_corner_radius) addView(copy) } } else { copy }).apply { layoutParams = this@copyViewImage.layoutParams layoutParams.height = this@copyViewImage.height layoutParams.width = this@copyViewImage.width x = this@copyViewImage.x y = this@copyViewImage.y } } 


Warum eine Kopie erstellen, wenn Sie nur das direkt ausgewählte Element aus der Liste animieren können?

Weil RecyclerView selbst auch animiert wird und dementsprechend alle seine Elemente, einschließlich des ausgewählten, die wir separat animieren möchten.

Fügen Sie danach eine Kopie zum Root-Markup hinzu und starten Sie die Animation.

 override fun onClick(view: View) { val fragmentTransaction = initFragmentTransaction(view) val copy = view.createCopyView() root.addView(copy) view.visibility = View.INVISIBLE startAnimation(copy, fragmentTransaction) } 


Und hier ist was wir haben:



Ziellinie


Die obige GIF-Animation findet in einem RecyclerFragment . Nach dessen Abschluss müssen wir DetailsFragment .

 .withEndAction { fragmentTransaction?.commitAllowingStateLoss() } 

Warum verwenden wir commitAllowingStateLoss ?

Wenn Sie es nicht verwenden und sich zum Zeitpunkt der Animation beispielsweise die Ausrichtung des Bildschirms ändert, erhalten wir IllegalStateExeption . Hier ist es gut darüber geschrieben.

Als Nächstes starten wir die Animation der erforderlichen Elemente der Benutzeroberfläche in DetailsFragment .

Führen Sie alles zusammen




Nicht ganz das gleiche wie das Original, aber es sieht ähnlich aus.

Beispiele


Der Quellcode ist auf GitHub verfügbar, und der Artikel ist auch in englischer Sprache verfügbar.

Vielen Dank für Ihre Aufmerksamkeit!

Source: https://habr.com/ru/post/de423235/


All Articles