Kotlin 03.2'de Gelişmiş Android: MotionLayout ile Animasyon

1. Başlamadan önce

Bu codelab, Kotlin'de İleri Düzey Android kursunun bir parçasıdır. Bu kurstan en iyi şekilde yararlanmak için codelab'leri sıralı bir şekilde uygulamanız gerekir. Ancak bu zorunlu değildir. Tüm kurs codelab'leri Gelişmiş Android in Kotlin codelab'leri açılış sayfasında listelenmiştir.

MotionLayout, Android uygulamanıza rich motion eklemenizi sağlayan bir kitaplıktır. ConstraintLayout, öğesini temel alır ve ConstraintLayout ile oluşturabileceğiniz her şeyi canlandırmanızı sağlar.

Birden fazla görünümün konum, boyut, görünürlük, alfa, renk, yükseklik, döndürme ve diğer özelliklerine aynı anda animasyon eklemek için MotionLayout öğesini kullanabilirsiniz. Bildirim temelli XML kullanarak, kodda ulaşılması zor olan birden çok görünüm içeren koordine animasyonlar oluşturabilirsiniz.

Animasyonlar, uygulama deneyimini geliştirmenin mükemmel bir yoludur. Animasyonları kullanarak şunları yapabilirsiniz:

  • Değişiklikleri göster: Durumlar arasında animasyon oluşturmak, kullanıcının kullanıcı arayüzündeki değişiklikleri doğal olarak izlemesini sağlar.
  • Dikkat çekin: Önemli kullanıcı arayüzü öğelerine dikkat çekmek için animasyonlar kullanın.
  • Güzel tasarımlar oluşturun: Tasarımda etkili hareketler olması uygulamaların şık görünmesini sağlar.

Ön koşullar

Bu codelab, Android geliştirme deneyimi olan geliştiriciler için tasarlanmıştır. Bu codelab'i tamamlamaya çalışmadan önce şunları yapmalısınız:

  • Etkinlik ve temel düzen içeren bir uygulama oluşturmayı ve Android Studio'yu kullanarak uygulamayı bir cihazda ya da emülatörde çalıştırmayı öğrenme. ConstraintLayout hakkında bilgi edinin. ConstraintLayout hakkında daha fazla bilgi edinmek için Kısıtlama Düzeni codelab'ini okuyun.

Yapacaklarınız

  • ConstraintSets ve MotionLayout ile animasyon tanımlayın
  • Sürükleme etkinliklerine göre animasyon uygulama
  • Animasyonu KeyPosition ile değiştirin
  • Özellikleri KeyAttribute ile değiştirin
  • Animasyonları kodla çalıştırma
  • Daraltılabilir başlıkları MotionLayout ile canlandırın

Gerekenler

  • Android Studio 4.0 (MotionLayout düzenleyicisi yalnızca Android Studio'nun bu sürümüyle çalışır.)

2. Başlarken

Örnek uygulamayı indirmek için:

... veya aşağıdaki komutu kullanarak GitHub deposunu komut satırından klonlayın:

$ git clone https://github.com/googlecodelabs/motionlayout.git

3. MotionLayout ile animasyon oluşturma

İlk olarak, kullanıcı tıklamalarına yanıt olarak görünümü ekranın üst kısmından en alt uca taşıyan bir animasyon oluşturacaksınız.

Başlangıç kodundan animasyon oluşturmak için aşağıdaki ana parçalara ihtiyacınız vardır:

  • ConstraintLayout alt sınıfı olan bir MotionLayout,. Animasyonlu olacak tüm görünümleri MotionLayout etiketinin içinde belirtirsiniz.
  • MotionLayout. için bir animasyonu açıklayan XML dosyası olan MotionScene,
  • Animasyon süresini, tetikleyiciyi ve görünümlerin nasıl taşınacağını belirten, MotionScene öğesinin parçası olan bir Transition,.
  • Geçişin hem start hem de end kısıtlamalarını belirten bir ConstraintSet.

MotionLayout ile başlayarak sırasıyla bunların her birine göz atalım.

1. Adım: Mevcut kodu inceleyin

MotionLayout, ConstraintLayout etiketinin alt sınıfıdır. Bu nedenle, animasyon eklerken aynı özellikleri destekler. MotionLayout özelliğini kullanmak için ConstraintLayout. kullanacağınız bir MotionLayout görünümü ekleyin

  1. res/layout içinde activity_step1.xml. uygulamasını açın. Burada, içinde tek bir ImageView yıldız bulunan ve içinde ton uygulanmış bir ConstraintLayout var.

activity_step1.xml

<!-- initial code -->
<androidx.constraintlayout.widget.ConstraintLayout
       ...
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       >

   <ImageView
           android:id="@+id/red_star"
           ...
   />

</androidx.constraintlayout.motion.widget.MotionLayout>

Bu ConstraintLayout cihazda herhangi bir kısıtlama yoktur. Bu nedenle, uygulamayı şimdi çalıştırırsanız yıldız ekranı kısıtlanmamış olarak gösterilir. Bu durum, öğelerin bilinmeyen bir konumda yer alacağı anlamına gelir. Android Studio, kısıtlama olmadığında size uyarı gönderir.

2. Adım: Hareket Düzeni'ne dönüştürün

MotionLayout, kullanarak animasyon eklemek için ConstraintLayout öğesini MotionLayout biçimine dönüştürmeniz gerekir.

Düzeninizin bir hareket sahnesini kullanabilmesi için sahneyi işaret etmesi gerekir.

  1. Bunu yapmak için tasarım yüzeyini açın. Android Studio 4.0'da, bir düzen XML dosyasına bakarken sağ üstteki bölme veya tasarım simgesini kullanarak tasarım yüzeyini açarsınız.

a2beea710c2decb7.png

  1. Tasarım yüzeyini açtıktan sonra önizlemeyi sağ tıklayın ve MotionLayout'a Dönüştür seçeneğini belirleyin.

4fa936a98a8393b9.png

Bu işlem, ConstraintLayout etiketini MotionLayout etiketiyle değiştirir ve MotionLayout etiketine, @xml/activity_step1_scene. öğesine işaret eden bir motion:layoutDescription ekler.

activity_step1**.xml**

<!-- explore motion:layoutDescription="@xml/activity_step1_scene" -->
<androidx.constraintlayout.motion.widget.MotionLayout
       ...
       motion:layoutDescription="@xml/activity_step1_scene">

Hareket sahnesi, MotionLayout içindeki bir animasyonu açıklayan tek bir XML dosyasıdır.

MotionLayout dönüştürdüğünüzde tasarım yüzeyinde Hareket Düzenleyici gösterilir

66d0e80d5ab4daf8.png

Hareket Düzenleyici'de üç yeni kullanıcı arayüzü öğesi var:

  1. Genel Bakış: Bu, animasyonun farklı bölümlerini seçmenize olanak tanıyan bir kalıcı seçimdir. Bu resimde start ConstraintSet seçilmiştir. Ayrıca, aralarındaki oku tıklayarak start ile end arasındaki geçişi de seçebilirsiniz.
  2. Bölüm: Genel bakışın altında, o sırada seçili olan genel bakış öğesine göre değişen bir bölüm penceresi bulunur. Bu resimde, start ConstraintSet bilgileri seçim penceresinde gösterilmektedir.
  3. Özellik: Özellik paneli, genel bakış veya seçim penceresinden seçili olan geçerli öğenin özelliklerini gösterir ve düzenlemenize olanak tanır. Bu resimde, start ConstraintSet özellikleri gösterilmektedir.

3. adım: Başlangıç ve bitiş kısıtlamalarını tanımlayın

Tüm animasyonlar bir başlangıç ve bitiş olarak tanımlanabilir. Başlangıç, animasyondan önceki ekranın, sonda ise animasyon tamamlandıktan sonra ekranın nasıl görüneceğiyle açıklanır. MotionLayout, başlangıç ve bitiş durumları arasında (zaman içinde) nasıl animasyon yapılacağını belirlemekten sorumludur.

MotionScene, başlangıç ve bitiş durumlarını tanımlamak için bir ConstraintSet etiketi kullanır. ConstraintSet, görünümlere uygulanabilecek bir dizi kısıtlamadır. Buna genişlik, yükseklik ve ConstraintLayout kısıtlamaları dahildir. Ayrıca alpha gibi bazı özellikler de içerir. Bu rapor, görünümlerin kendisini içermez, yalnızca bu görünümlerdeki kısıtlamaları içerir.

ConstraintSet öğesinde belirtilen kısıtlamalar, düzen dosyasında belirtilen kısıtlamaları geçersiz kılar. Hem düzende hem de MotionScene öğesinde kısıtlamalar tanımlarsanız yalnızca MotionScene öğesindeki kısıtlamalar uygulanır.

Bu adımda, yıldız görünümünü ekranın üst başlangıcında başlayıp alt ucunda bitecek şekilde sınırlandırırsınız.

Bu adımı Hareket Düzenleyici'yi kullanarak veya doğrudan activity_step1_scene.xml metnini düzenleyerek tamamlayabilirsiniz.

  1. Genel bakış panelinde start ConstraintSet'i seçin

6e57661ed358b860.png

  1. Seçim panelinde red_star simgesini seçin. Şu anda layout Kaynağı gösteriliyor. Bu, değerin bu ConstraintSet içinde kısıtlanmadığı anlamına gelir. Kısıtlama Oluşturma için sağ üstteki kalem simgesini kullanın.

f9564c574b86ea8.gif

  1. Genel bakış panelinde start ConstraintSet seçildiğinde, red_star öğesinin start Kaynağını gösterdiğini onaylayın.
  2. Özellikler panelinde, start ConstraintSet içinde red_star seçiliyken en üst kısma bir Sınırlama ekleyin ve mavi + düğmelerini tıklayarak başlayın.

2fce076cd7b04bd.png

  1. Hareket Düzenleyici'nin bu kısıtlama için oluşturduğu kodu görmek için xml/activity_step1_scene.xml dosyasını açın.

activity_step1_scene.xml

<!-- Constraints to apply at the start of the animation -->
<ConstraintSet android:id="@+id/start">
   <Constraint
           android:id="@+id/red_star"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           motion:layout_constraintStart_toStartOf="parent"
           motion:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>

ConstraintSet, id değerine sahip @id/start ve MotionLayout içindeki tüm görünümlere uygulanacak tüm kısıtlamaları belirtir. Bu MotionLayout, yalnızca bir görünüme sahip olduğundan yalnızca bir Constraint öğesine ihtiyaç duyuyor.

ConstraintSet içindeki Constraint, kısıtladığı görünümün kimliğini belirtir (@id/red_star activity_step1.xml içinde tanımlanır). Constraint etiketlerinin yalnızca kısıtlamaları ve düzen bilgilerini belirttiğini unutmayın. Constraint etiketi, bir ImageView öğesine uygulandığını bilmez.

Bu kısıtlama, red_star görünümünü üst öğesinin üst başlangıcıyla sınırlamak için gereken yüksekliği, genişliği ve diğer iki kısıtlamayı belirtir.

  1. Genel bakış panelinde end ConstraintSet'i seçin.

346e1248639b6f1e.png

  1. end ConstraintSet içinde red_star için Constraint eklemek üzere daha önce yaptığınız adımları uygulayın.
  2. Bu adımı tamamlamak üzere Hareket Düzenleyici'yi kullanmak için mavi + düğmelerini tıklayarak bottom ve end için bir kısıtlama ekleyin.

fd33c779ff83c80a.png

  1. XML'deki kod aşağıdaki gibi görünür:

activitiy_step1_scene.xml

<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/end">
   <Constraint
           android:id="@+id/red_star"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           motion:layout_constraintEnd_toEndOf="parent"
           motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>

@id/start gibi, bu ConstraintSet için de @id/red_star üzerinde tek bir Constraint var. Bu kez simge, ekranın alt ucuyla sınırlandırılıyor.

Bu öğeleri @id/start ve @id/end olarak adlandırmanıza gerek yoktur ancak kolaylık sağlar.

4. Adım: Bir geçiş tanımlayın

Her MotionScene en az bir geçiş içermelidir. Geçiş, bir animasyonun başından sonuna her bölümünü tanımlar.

Geçişin, geçiş için bir başlangıç ve bitiş ConstraintSet belirtmesi gerekir. Geçiş, animasyonun ne kadar süreyle çalıştırılacağını veya görünümleri sürükleyerek animasyonun nasıl düzenleneceğini gibi diğer şekillerde nasıl değiştirileceğini de belirtebilir.

  1. MotionScene dosyası oluşturulurken Hareket Düzenleyici varsayılan olarak bizim için bir geçiş oluşturdu. Oluşturulan geçişi görmek için activity_step1_scene.xml uygulamasını açın.

activity_step1_scene.xml

<!-- A transition describes an animation via start and end state -->
<Transition
   motion:constraintSetEnd="@+id/end"
   motion:constraintSetStart="@id/start"
   motion:duration="1000">
  <KeyFrameSet>
  </KeyFrameSet>
</Transition>

MotionLayout uygulamasının animasyon oluşturmak için ihtiyaç duyduğu tüm bilgiler bunlar. Özelliklere göz atarak:

  • Animasyon başladığında görünümlere constraintSetStart uygulanır.
  • constraintSetEnd, animasyonun sonundaki görünümlere uygulanır.
  • duration, animasyonun ne kadar süreceğini belirtir.

Ardından MotionLayout, başlangıç ve bitiş kısıtlamaları arasında bir yol belirler ve belirtilen süre boyunca bu kısıtlamaları canlandırır.

5. Adım: Hareket Düzenleyici'de animasyonu önizleyin

dff9ecdc1f4a0740.gif

Animasyon: Hareket Düzenleyici'de geçiş önizlemesi oynatma videosu

  1. Hareket Düzenleyici'yi açın ve genel bakış panelinde start ile end arasındaki oku tıklayarak geçişi seçin.

1dc541ae8c43b250.png

  1. Seçim panelinde, bir geçiş seçildiğinde oynatma kontrolleri ve bir ileri geri çubuğu gösterilir. Animasyonu önizlemek için oynat'ı tıklayın veya geçerli konumu sürükleyin.

a0fd2593384dfb36.png

6. Adım: Tıklama işleyici ekleyin

Animasyonu başlatmak için bir yönteme ihtiyacınız var. Bunu yapmanın bir yolu, MotionLayout öğesinin @id/red_star üzerindeki tıklama etkinliklerine yanıt vermesini sağlamaktır.

  1. Hareket düzenleyiciyi açın ve genel bakış panelinde başlangıç ve bitiş arasındaki oku tıklayarak geçişi seçin.

b6f94b344ce65290.png

  1. Genel bakış paneli için araç çubuğunda 699f7ae04024ccf6.png Tıklama veya kaydırma işleyici oluştur'u tıklayın . Bu işlem, geçiş başlatacak bir işleyici ekler.
  2. Pop-up'tan Tıklama İşleyici'yi seçin.

ccf92d06335105fe.png

  1. Tıklanacak Görünüm değerini red_star olarak değiştirin.

b0d3f0c970604f01.png

  1. Ekle'yi tıklayın. Tıklama işleyici, Hareket Düzenleyici'de Geçiş için küçük bir noktayla gösterilir.

cec3913e67fb4105.png

  1. Genel bakış panelinde geçiş seçiliyken, özellikler panelinde az önce eklediğiniz OnClick işleyiciye toggle için bir clickAction özelliği ekleyin.

9af6fc60673d093d.png

  1. Hareket Düzenleyici'nin oluşturduğu kodu görmek için activity_step1_scene.xml uygulamasını açın

activity_step1_scene.xml

<!-- A transition describes an animation via start and end state -->
<Transition
    motion:constraintSetStart="@+id/start"
    motion:constraintSetEnd="@+id/end"
    motion:duration="1000">
    <!-- MotionLayout will handle clicks on @id/red_star to "toggle" the animation between the start and end -->
    <OnClick
        motion:targetId="@id/red_star"
        motion:clickAction="toggle" />
</Transition>

Transition, MotionLayout uygulamasına, tıklama etkinliklerine yanıt olarak animasyonu <OnClick> etiketi kullanarak çalıştırmasını söyler. Özelliklere göz atarak:

  • targetId, tıklamalar için izlenecek görünümdür.
  • toggle öğesinin clickAction kadarı, tıklandığında başlangıç ve bitiş durumu arasında geçiş yapacak. clickAction ile ilgili diğer seçenekleri belgelerde bulabilirsiniz.
  1. Kodunuzu çalıştırın, 1. Adım'ı ve ardından kırmızı yıldızı tıklayın ve animasyonu görün!

5. Adım: Animasyonların işleyiş şekli

Uygulamayı çalıştırın. Yıldızı tıkladığınızda animasyonunuzun çalıştığını görürsünüz.

7ba88af963fdfe10.gif

Tamamlanan hareket sahnesi dosyası, ConstraintSet başlangıç ve bitişine işaret eden bir Transition tanımlar.

Animasyonun başında (@id/start) yıldız simgesi, ekranın üst başlangıcıyla sınırlandırılır. Animasyonun sonunda (@id/end) yıldız simgesi ekranın alt ucuyla sınırlanır.

<?xml version="1.0" encoding="utf-8"?>

<!-- Describe the animation for activity_step1.xml -->
<MotionScene xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:android="http://schemas.android.com/apk/res/android">
   <!-- A transition describes an animation via start and end state -->
   <Transition
           motion:constraintSetStart="@+id/start"
           motion:constraintSetEnd="@+id/end"
           motion:duration="1000">
       <!-- MotionLayout will handle clicks on @id/star to "toggle" the animation between the start and end -->
       <OnClick
               motion:targetId="@id/red_star"
               motion:clickAction="toggle" />
   </Transition>

   <!-- Constraints to apply at the end of the animation -->
   <ConstraintSet android:id="@+id/start">
       <Constraint
               android:id="@+id/red_star"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               motion:layout_constraintStart_toStartOf="parent"
               motion:layout_constraintTop_toTopOf="parent" />
   </ConstraintSet>

   <!-- Constraints to apply at the end of the animation -->
   <ConstraintSet android:id="@+id/end">
       <Constraint
               android:id="@+id/red_star"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               motion:layout_constraintEnd_toEndOf="parent"
               motion:layout_constraintBottom_toBottomOf="parent" />
   </ConstraintSet>
</MotionScene>

4. Sürükleme etkinliklerine dayalı animasyon

Bu adım için, animasyonu çalıştırmak üzere kullanıcı sürükleme etkinliğine (kullanıcı ekranı kaydırdığında) yanıt veren bir animasyon oluşturacaksınız. MotionLayout, görünümleri hareket ettirmek için dokunma etkinliklerini takip etmenin yanı sıra hareketi daha akıcı hale getirmek için fiziğe dayalı hızlıca kaydırma hareketlerini destekler.

1. Adım: İlk kodu inceleyin

  1. Başlamak için mevcut MotionLayout öğesine sahip activity_step2.xml düzen dosyasını açın. Koda göz atın.

activity_step2.xml

<!-- initial code -->

<androidx.constraintlayout.motion.widget.MotionLayout
       ...
       motion:layoutDescription="@xml/step2" >

   <ImageView
           android:id="@+id/left_star"
           ...
   />

   <ImageView
           android:id="@+id/right_star"
           ...
   />

   <ImageView
           android:id="@+id/red_star"
           ...
   />

   <TextView
           android:id="@+id/credits"
           ...
           motion:layout_constraintTop_toTopOf="parent"
           motion:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.motion.widget.MotionLayout>

Bu düzen, animasyona ilişkin tüm görünümleri tanımlar. Üç yıldız simgeleri, hareket sahnesinde canlandırılacağı için düzende kısıtlı değildir.

TextView kredilerine kısıtlamalar uygulandığından tüm animasyon boyunca aynı yerde kaldığı ve hiçbir özelliği değiştirmediği için bu kredilere kısıtlamalar uygulanmıştır.

2. Adım: Sahneyi canlandırın

Son animasyonda olduğu gibi animasyon bir başlangıç ve bitiş ConstraintSet, ile bir Transition ile tanımlanır.

ConstraintSet başlangıcını tanımlayın

  1. Animasyonu tanımlamak için xml/step2.xml hareket sahnesini açın.
  2. start başlangıç kısıtlaması için kısıtlamaları ekleyin. Başlangıçta, üç yıldız da ekranın alt kısmında ortalanır. Sağ ve sol yıldızlar, 0.0 olan alpha değerine sahiptir. Bu, tamamen şeffaf ve gizli oldukları anlamına gelir.

step2.xml

<!-- TODO apply starting constraints -->

<!-- Constraints to apply at the start of the animation -->
<ConstraintSet android:id="@+id/start">
   <Constraint
           android:id="@+id/red_star"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           motion:layout_constraintStart_toStartOf="parent"
           motion:layout_constraintEnd_toEndOf="parent"
           motion:layout_constraintBottom_toBottomOf="parent" />

   <Constraint
           android:id="@+id/left_star"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:alpha="0.0"
           motion:layout_constraintStart_toStartOf="parent"
           motion:layout_constraintEnd_toEndOf="parent"
           motion:layout_constraintBottom_toBottomOf="parent" />

   <Constraint
           android:id="@+id/right_star"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:alpha="0.0"
           motion:layout_constraintStart_toStartOf="parent"
           motion:layout_constraintEnd_toEndOf="parent"
           motion:layout_constraintBottom_toBottomOf="parent" />
</ConstraintSet>

Bu ConstraintSet içinde her bir yıldız için bir Constraint belirtirsiniz. Her kısıtlama, animasyonun başında MotionLayout tarafından uygulanır.

Her yıldız görünümü, başlangıç, bitiş ve alt sınırlamalar kullanılarak ekranın alt kısmına ortalanır. @id/left_star ve @id/right_star adlı iki yıldız, onları görünmez hale getiren ve animasyonun başında uygulanacak ek bir alfa değerine sahiptir.

start ve end kısıtlama grupları, animasyonun başlangıcını ve bitişini tanımlar. Başlangıçtaki motion:layout_constraintStart_toStartOf gibi bir sınırlama, bir görünümün başlangıcını başka bir görünümün başlangıcıyla kısıtlar. Bu durum başta kafa karıştırıcı olabilir çünkü start adı hem hem kısıtlamalar bağlamında kullanılır. Ayrımı ortaya çıkarmaya yardımcı olması açısından, layout_constraintStart içindeki start, "başlangıç" anlamına gelir soldan sağa dilde ve sağdan sola yazılan bir dilde sağdan sola görünümün bulunduğu görünümü içerir. start kısıtlaması ayarı, animasyonun başlangıcını ifade eder.

End ConstraintSet'i tanımlayın

  1. Üç yıldızın tümünü @id/credits altında birlikte konumlandırmak amacıyla zincir kullanmak için son kısıtlamayı tanımlayın. Buna ek olarak, sol ve sağ yıldızların alpha bitiş değeri 1.0 olarak ayarlanır.

step2.xml

<!-- TODO apply ending constraints -->

<!-- Constraints to apply at the end of the animation -->
<ConstraintSet android:id="@+id/end">

   <Constraint
           android:id="@+id/left_star"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:alpha="1.0"
           motion:layout_constraintHorizontal_chainStyle="packed"
           motion:layout_constraintStart_toStartOf="parent"
           motion:layout_constraintEnd_toStartOf="@id/red_star"
           motion:layout_constraintTop_toBottomOf="@id/credits" />

   <Constraint
           android:id="@+id/red_star"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           motion:layout_constraintStart_toEndOf="@id/left_star"
           motion:layout_constraintEnd_toStartOf="@id/right_star"
           motion:layout_constraintTop_toBottomOf="@id/credits" />

   <Constraint
           android:id="@+id/right_star"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:alpha="1.0"
           motion:layout_constraintStart_toEndOf="@id/red_star"
           motion:layout_constraintEnd_toEndOf="parent"
           motion:layout_constraintTop_toBottomOf="@id/credits" />
</ConstraintSet>

Sonuç olarak görünümler, hareket ettikçe merkeze doğru yayılır ve yukarıya doğru gider.

Buna ek olarak, alpha özelliği hem ConstraintSets içinde @id/right_start hem de @id/left_star üzerinde ayarlandığından, animasyon ilerledikçe her iki görünüm de azalır.

Kullanıcının kaydırmasına göre animasyon

MotionLayout, fiziğe dayalı bir "hızlı hareket" oluşturmak için kullanıcının sürükleme etkinliklerini veya kaydırma işlemlerini izleyebilir animasyon ekler. Diğer bir deyişle, kullanıcı tarafından sallanan görünümler devam edecek ve fiziksel bir nesnenin yuvarlandığı gibi yavaşlayacaktır. Bu animasyon türünü Transition içindeki bir OnSwipe etiketiyle ekleyebilirsiniz.

  1. OnSwipe etiketini <OnSwipe motion:touchAnchorId="@id/red_star" /> ile eklemek için YAPILACAKLAR kısmını değiştirin.

step2.xml

<!-- TODO add OnSwipe tag -->

<!-- A transition describes an animation via start and end state -->
<Transition
       motion:constraintSetStart="@+id/start"
       motion:constraintSetEnd="@+id/end">
   <!-- MotionLayout will track swipes relative to this view -->
   <OnSwipe motion:touchAnchorId="@id/red_star" />
</Transition>

OnSwipe birkaç özellik içeriyor. Bunlardan en önemlisi touchAnchorId.

  • touchAnchorId, dokunmaya yanıt olarak hareket eden izlenen görünümdür. MotionLayout, bu görünümü kaydıran parmakla aynı mesafede tutar.
  • touchAnchorSide, görünümün hangi tarafının izlenmesi gerektiğini belirler. Bu, yeniden boyutlandırılan, karmaşık yolları takip eden veya bir tarafı diğerine göre daha hızlı hareket eden görünümler için önemlidir.
  • dragDirection, bu animasyon için hangi yönün (yukarı, aşağı, sol veya sağ) önemli olduğunu belirler.

MotionLayout, sürükleme etkinliklerini dinlediğinde, işleyici touchAnchorId tarafından belirtilen görünüme değil, MotionLayout görünümüne kaydedilir. Kullanıcı ekranın herhangi bir yerinde bir hareketi başlattığında MotionLayout, parmağı ile touchAnchorId görünümünün touchAnchorSide arasındaki mesafeyi sabit tutar. Örneğin, sabit taraftan 100 dp uzaklığa dokunursa MotionLayout, animasyonun tamamı boyunca bu tarafı parmağından 100 dp uzakta tutar.

Deneyin

  1. Uygulamayı tekrar çalıştırın ve 2. Adım ekranını açın. Animasyonu görürsünüz.
  2. "Hızlıca kaydırma"yı deneyin veya MotionLayout öğesinin, akışkan fiziğe dayalı animasyonları nasıl görüntülediğini keşfetmek için parmağınızı animasyonun ortasında bırakın.

fefcdd690a0dcaec.gif

MotionLayout, zengin efektler oluşturmak için ConstraintLayout özelliklerini kullanarak çok farklı tasarımlar arasında animasyon oluşturabilir.

Bu animasyonda, üç görünüm de başlamak için ekranın alt kısmındaki üst öğelerine göre konumlandırılır. Sonda, üç görünüm bir zincirdeki @id/credits öğesine göre konumlandırılır.

Bu çok farklı düzenlere rağmen MotionLayout, başlangıç ve bitiş arasında değişken bir animasyon oluşturur.

5. Yolu değiştirme

Bu adımda, animasyon sırasında karmaşık bir yolu izleyen ve hareket sırasında jenerikleri animasyonla gösteren bir animasyon oluşturacaksınız. MotionLayout, görünümün başlangıç ve bitiş arasında izleyeceği yolu KeyPosition kullanarak değiştirebilir.

1. Adım: Mevcut kodu inceleyin

  1. Mevcut düzeni ve hareket sahnesini görmek için layout/activity_step3.xml ve xml/step3.xml öğelerini açın. ImageView ve TextView simgelerinde ay ve jenerik metni yer alıyor.
  2. Hareket sahnesi dosyasını (xml/step3.xml) açın. @id/start ile @id/end arasında bir Transition değerinin tanımlandığını görüyorsunuz. Animasyon, iki ConstraintSets öğesini kullanarak ay resmini ekranın sol alt kısmından ekranın sağ alt kısmına taşır. Ay hareket ederken alpha="0.0" ile alpha="1.0" arasında jenerik metni görünür ve görünür.
  3. Uygulamayı şimdi çalıştırın ve 3. Adım'ı seçin. Ay'ı tıkladığınızda ayın başından sonuna kadar doğrusal bir yol (veya düz bir çizgi) izlediğini göreceksiniz.

2. Adım: Yol hata ayıklama özelliğini etkinleştirin

Ayın hareketine bir yay eklemeden önce MotionLayout bölümünde yol hata ayıklama özelliğini etkinleştirmeniz faydalı olur.

MotionLayout ile karmaşık animasyonlar geliştirilmesine yardımcı olmak için her görünümün animasyon yolunu çizebilirsiniz. Bu, animasyonunuzu görselleştirmek ve hareketin küçük ayrıntılarını hassas bir şekilde ayarlamak istediğinizde yararlı olur.

  1. Hata ayıklama yollarını etkinleştirmek için layout/activity_step3.xml öğesini açın ve MotionLayout etiketine motion:motionDebug="SHOW_PATH" ekleyin.

activity_step3.xml

<!-- Add motion:motionDebug="SHOW_PATH" -->

<androidx.constraintlayout.motion.widget.MotionLayout
       ...
       motion:motionDebug="SHOW_PATH" >

Yol hata ayıklama özelliğini etkinleştirdikten sonra uygulamayı tekrar çalıştırdığınızda tüm görünümlerin yollarını noktalı bir çizgiyle görselleştirilmiş olarak görürsünüz.

23bbb604f456f65c.png

  • Daireler bir görünümün başlangıç veya bitiş konumunu temsil eder.
  • Çizgiler, bir görünümün yolunu temsil eder.
  • Elmas, yolu değiştiren bir KeyPosition temsil eder.

Örneğin, bu animasyonda ortadaki daire, jenerik metninin konumudur.

3. Adım: Yolu değiştirin

MotionLayout içindeki tüm animasyonlar, animasyon başlamadan önce ve tamamlandıktan sonra ekranın nasıl görüneceğini tanımlayan bir başlangıç ve bitiş (ConstraintSet) ile tanımlanır. Varsayılan olarak MotionLayout, konumu değiştiren her görünümün başlangıç ve bitiş konumları arasında doğrusal bir yol (düz bir çizgi) çizer.

Bu örnekte ayın yayağı gibi karmaşık yollar oluşturmak için MotionLayout, bir görünümün başlangıç ve bitiş arasında izlediği yolu değiştirmek üzere bir KeyPosition kullanır.

  1. xml/step3.xml öğesini açın ve sahneye KeyPosition ekleyin. KeyPosition etiketi, Transition etiketinin içine yerleştirilir.

eae4dae9a12d0410.png

step3.xml

<!-- TODO: Add KeyFrameSet and KeyPosition -->
<KeyFrameSet>
   <KeyPosition
           motion:framePosition="50"
           motion:motionTarget="@id/moon"
           motion:keyPositionType="parentRelative"
           motion:percentY="0.5"
   />
</KeyFrameSet>

KeyFrameSet, bir Transition öğesinin alt öğesidir. Geçiş sırasında uygulanması gereken tüm KeyFrames öğelerini (ör. KeyPosition) içeren bir gruptur.

MotionLayout, ayın başlangıç ve bitişi arasındaki yolunu hesaplarken yolu, KeyFrameSet öğesinde belirtilen KeyPosition temel alınarak değiştirir. Uygulamayı tekrar çalıştırarak yolu nasıl değiştirdiğini görebilirsiniz.

KeyPosition, yolu nasıl değiştirdiğini açıklayan çeşitli özelliklere sahiptir. Bunların en önemlileri şunlardır:

  • framePosition, 0 ile 100 arasında bir sayıdır. Bu KeyPosition öğesinin animasyonda ne zaman uygulanması gerektiğini tanımlar. 1, animasyondan% 1, 99 değeri animasyon aracılığıyla% 99'dur. Değer 50 ise bunu hemen ortaya uygularsınız.
  • motionTarget, bu KeyPosition öğesinin yolunu değiştirdiği görünümdür.
  • Bu KeyPosition, yolu keyPositionType olarak değiştirir. parentRelative, pathRelative veya deltaRelative olabilir (sonraki adımda açıklandığı gibi).
  • percentX | percentY, framePosition için yolun ne kadar değiştirileceğini belirtir (0,0 ile 1,0 arasındaki değerlere, negatif değerlere ve 1'den büyük değerlere izin verilir).

Şöyle düşünebilirsiniz: "framePosition konumunu percentX veya percentY yolu keyPositionType tarafından belirlenen koordinatlara göre taşıyarak motionTarget yolunu değiştirin."

MotionLayout, varsayılan olarak yolun değiştirilmesiyle ortaya çıkan tüm köşeleri yuvarlar. Az önce oluşturduğunuz animasyona bakarsanız ayın eğimli bir yolu takip ettiğini görebilirsiniz. Çoğu animasyonda istediğiniz budur. Aksi takdirde, animasyonları özelleştirmek için curveFit özelliğini belirtebilirsiniz.

Deneyin

Uygulamayı tekrar çalıştırırsanız bu adıma ilişkin animasyonu görürsünüz.

46b179c01801f19e.gif

Ay, Transition ayrıntısında belirtilen bir KeyPosition içinden geçtiği için bir yay izler.

<KeyPosition
       motion:framePosition="50"
       motion:motionTarget="@id/moon"
       motion:keyPositionType="parentRelative"
       motion:percentY="0.5"
/>

Bu KeyPosition öğesini şu şekilde okuyabilirsiniz: "framePosition 50 konumunda (animasyonun ortasında), parentRelative tarafından belirlenen koordinatlara göre (MotionLayout öğesinin tamamı) 50% Y kadar (ekranın ortasında) hareket ettirerek motionTarget @id/moon yolunu değiştirin."

Yani animasyonun yarısında, ayın ekranda% 50 aşağıda olan bir KeyPosition içinden geçmesi gerekiyor. Bu KeyPosition, X hareketini hiç değiştirmediği için ay, baştan sona yatay olarak hareket etmeye devam eder. MotionLayout, başlangıç ve bitiş arasında geçiş yaparken bu KeyPosition içinden geçen sorunsuz bir yol belirler.

Yakından bakarsanız jenerik metni ayın konumuyla sınırlanıyor. Neden dikey olarak da hareket etmiyor?

1c7cf779931e45cc.gif

<Constraint
       android:id="@id/credits"
       ...
       motion:layout_constraintBottom_toBottomOf="@id/moon"
       motion:layout_constraintTop_toTopOf="@id/moon"
/>

Görünüşe göre ayın izlediği yolu değiştirseniz bile ayın başlangıç ve bitiş noktaları dikey olarak hiç hareket etmiyor. KeyPosition, başlangıç veya bitiş konumunu değiştirmez. Bu nedenle, jenerik metni ayın son bitiş konumuyla sınırlandırılır.

Kredilerin ay ile birlikte hareket etmesini isterseniz jeneriklere KeyPosition ekleyebilir veya @id/credits paketindeki başlangıç kısıtlamalarını değiştirebilirsiniz.

Sonraki bölümde, MotionLayout dilindeki farklı keyPositionType türlerini inceleyeceksiniz.

6. keyPositionType'ı anlama

Son adımda, yolu ekranın% 50'si oranında dengelemek için keyPosition parentRelative türünü kullandınız. keyPositionType özelliği, MotionLayout'un percentX veya percentY öğesine göre yolu nasıl değiştireceğini belirler.

<KeyFrameSet>
   <KeyPosition
           motion:framePosition="50"
           motion:motionTarget="@id/moon"
           motion:keyPositionType="parentRelative"
           motion:percentY="0.5"
   />
</KeyFrameSet>

Olası üç farklı keyPosition türü vardır: parentRelative, pathRelative ve deltaRelative. Bir tür belirtmek, percentX ve percentY değerlerinin hesaplandığı koordinat sistemini değiştirir.

Koordinat sistemi nedir?

Koordinat sistemi, uzaydaki bir noktayı belirtmek için bir yöntem sağlar. Bunlar, ekrandaki bir konumu tanımlamak için de yararlıdır.

MotionLayout koordinat sistemleri bir alışveriş sepeti koordinat sistemidir. Bunun anlamı, bunların iki dik çizgiyle tanımlanan bir X ve Y ekseni vardır. Bunlar arasındaki temel fark, X ekseninin ekranda gittiği yerdir (Y ekseni her zaman X eksenine diktir).

MotionLayout içindeki tüm koordinat sistemleri, hem X hem de Y ekseninde 0.0 ile 1.0 arasındaki değerleri kullanır. Negatif değerlere ve 1.0 değerinden büyük değerlere izin verir. Örneğin, percentX değeri olan -2.0, X ekseninin ters yönüne iki kez gitmelidir.

Bunların hepsi Cebir dersine benziyorsa, aşağıdaki resimlere göz atın!

parentgöreli koordinatlar

a7b7568d46d9dec7.png

parentRelative öğesinin keyPositionType özelliği, ekranla aynı koordinat sistemini kullanır. Tüm MotionLayout öğesinin sol üst tarafında (0, 0) ve sağ altta (1, 1) öğesini tanımlar.

Bu örnekteki ay yayını gibi, MotionLayout boyunca hareket eden bir animasyon oluşturmak istediğinizde parentRelative kullanabilirsiniz.

Bununla birlikte, bir yolu harekete göre değiştirmek, örneğin biraz eğmek istiyorsanız diğer iki koordinat sistemi daha iyi bir tercihtir.

deltagöreli koordinatlar

5680bf553627416c.png

Delta, değişim için kullanılan bir matematik terimi olduğundan deltaRelative, "göreceli değişim" anlamına gelir. deltaRelativeKoordinatlarda(0,0) görünümün başlangıç konumu, (1,1) ise bitiş konumudur. X ve Y eksenleri ekranla hizalanır.

X ekseni ekranda her zaman yatay, Y ekseni ise ekranda her zaman dikeydir. parentRelative ile karşılaştırıldığında en önemli fark, koordinatların ekranda yalnızca görünümün hareket edeceği bölümünü tanımlamasıdır.

deltaRelative, yatay veya dikey hareketi ayrı olarak kontrol etmek için mükemmel bir koordinat sistemidir. Örneğin, sadece dikey (Y) hareketini %50'de tamamlayan ve yatay (X) animasyonuna devam eden bir animasyon oluşturabilirsiniz.

pathgöreli koordinatlar

f3aaadaac8b4a93f.png

MotionLayout bölgesindeki son koordinat sistemi pathRelative. X ekseni, hareket yolunu başından sonuna kadar izlediğinden diğer ikisinden oldukça farklıdır. Dolayısıyla (0,0) başlangıç konumu, (1,0) ise bitiş konumudur.

Bunu neden isteyesiniz? Özellikle de bu koordinat sistemi ekran koordinat sistemiyle aynı hizada olmadığından ilk bakışta oldukça şaşırtıcı.

pathRelative'ın birkaç konuda gerçekten kullanışlı olduğu anlaşılıyor.

  • Animasyonun bir kısmı sırasında görünümün hızlandırılması, yavaşlatılması veya durdurulması. X boyutu her zaman görünümün izlediği yolla tam olarak eşleşeceğinden, söz konusu yoldaki belirli bir noktaya framePosition ulaşmak için bir pathRelative KeyPosition kullanabilirsiniz. Dolayısıyla, percentX="0.1" içeren framePosition="50" konumundaki bir KeyPosition, animasyonun hareketin ilk% 10'luk kısmında seyahat etmek için gereken sürenin% 50'sini almasına neden olur.
  • Yola ince bir yay ekleme. Y boyutu harekete her zaman dik olduğundan, Y'nin değiştirilmesi eğrinin yolunu genel harekete göre değiştirir.
  • deltaRelative çalışmadığında ikinci bir boyut eklemek. deltaRelative, tamamen yatay ve dikey hareketler için yalnızca tek bir yararlı boyut oluşturur. Ancak pathRelative her zaman kullanılabilir X ve Y koordinatları oluşturur.

Sonraki adımda birden fazla KeyPosition kullanarak daha da karmaşık yollar oluşturmayı öğreneceksiniz.

7. Karmaşık yollar oluşturma

Son adımda oluşturduğunuz animasyona bakıldığında yumuşak bir eğri oluşturulur ancak şekil daha çok "aya benzer" olabilir.

Birden çok KeyPosition öğesine sahip bir yolu değiştirme

MotionLayout, herhangi bir hareketi elde etmek için gereken sayıda KeyPosition tanımlayarak bir yolda daha fazla değişiklik yapabilir. Bu animasyon için bir yay oluşturacaksınız. Ancak dilerseniz ayı ekranın ortasında yukarı aşağı zıplatabilirsiniz.

  1. xml/step4.xml adlı kişiyi aç. Bu segmentin aynı görünümlere ve son adımda eklediğiniz KeyFrame değerine sahip olduğunu görüyorsunuz.
  2. Eğrinin üst kısmını yuvarlamak için @id/moon yoluna iki KeyPositions daha ekleyin. Bunlardan biri en üst noktaya ulaşmadan hemen önce, diğeri de arkadan olmalıdır.

500b5ac2db48ef87.png

step4.xml

<!-- TODO: Add two more KeyPositions to the KeyFrameSet here -->
<KeyPosition
       motion:framePosition="25"
       motion:motionTarget="@id/moon"
       motion:keyPositionType="parentRelative"
       motion:percentY="0.6"
/>
<KeyPosition
       motion:framePosition="75"
       motion:motionTarget="@id/moon"
       motion:keyPositionType="parentRelative"
       motion:percentY="0.6"
/>

Bu KeyPositions, animasyonun% 25 ve% 75'inde uygulanır ve @id/moon ürününün, ekranın üst kısmından% 60'lık bir yol boyunca hareket etmesine neden olur. %50'deki mevcut KeyPosition ile birleştirildiğinde bu, ayın takip edeceği yumuşak bir yay oluşturur.

MotionLayout içinde istediğiniz hareket yolunu elde etmek için ihtiyacınız kadar KeyPositions ekleyebilirsiniz. MotionLayout, her bir KeyPosition öğesini belirtilen framePosition saatinde uygulayacak ve KeyPositions cihazının tamamını kapsayan yumuşak bir hareketin nasıl oluşturulacağını çözecek.

Deneyin

  1. Uygulamayı tekrar çalıştırın. Animasyonun nasıl çalıştığını görmek için 4. Adım'a gidin. Ay'ı tıkladığınızda, KeyFrameSet. maddede belirtilen her bir KeyPosition boyunca ilerleyerek yolu başından sonuna kadar izler.

Kendi başınıza keşfedin

Diğer KeyFrame türlerine geçmeden önce, KeyPosition kullanarak ne tür efektler oluşturabileceğinizi görmek için KeyFrameSet öğesine biraz daha KeyPositions eklemeyi deneyin.

Animasyon sırasında ileri ve geri hareket eden karmaşık bir yolun nasıl oluşturulacağını gösteren bir örneği burada bulabilirsiniz.

cd9faaffde3dfef.png

step4.xml

<!-- Complex paths example: Dancing moon -->
<KeyFrameSet>
   <KeyPosition
           motion:framePosition="25"
           motion:motionTarget="@id/moon"
           motion:keyPositionType="parentRelative"
           motion:percentY="0.6"
           motion:percentX="0.1"
   />
   <KeyPosition
           motion:framePosition="50"
           motion:motionTarget="@id/moon"
           motion:keyPositionType="parentRelative"
           motion:percentY="0.5"
           motion:percentX="0.3"
   />
   <KeyPosition
           motion:framePosition="75"
           motion:motionTarget="@id/moon"
           motion:keyPositionType="parentRelative"
           motion:percentY="0.6"
           motion:percentX="0.1"
   />
</KeyFrameSet>

KeyPosition keşfini bitirdiğinizde, bir sonraki adımda diğer KeyFrames türlerine geçeceksiniz.

8. Hareket sırasında özellikleri değiştirme

Dinamik animasyonlar oluşturmak, genellikle animasyon ilerledikçe görünümlerin size, rotation veya alpha değerinin değiştirilmesi anlamına gelir. MotionLayout, KeyAttribute kullanılarak tüm görünümlerde birçok özelliğin animasyonunu destekler.

Bu adımda, Ay'ı ölçeklemek ve döndürmek için KeyAttribute aracını kullanacaksınız. Ay'ın yolculuğu neredeyse bitene kadar metnin görünümünü ertelemek için de bir KeyAttribute kullanacaksınız.

1. Adım: KeyAttribute ile yeniden boyutlandırın ve döndürün

  1. Son adımda oluşturduğunuz animasyonun aynısını içeren xml/step5.xml dosyasını açın. Çeşitlilik sağlamak için bu ekranda arka plan olarak farklı bir alan resmi kullanılır.
  2. Ayın boyut olarak genişlemesini ve dönmesini sağlamak için keyFrame="50" ve keyFrame="100" içine KeyFrameSet iki tane KeyAttribute etiketi ekleyin

bbae524a2898569.png

step5.xml

<!-- TODO: Add KeyAttributes to rotate and resize @id/moon -->

<KeyAttribute
       motion:framePosition="50"
       motion:motionTarget="@id/moon"
       android:scaleY="2.0"
       android:scaleX="2.0"
       android:rotation="-360"
/>
<KeyAttribute
       motion:framePosition="100"
       motion:motionTarget="@id/moon"
       android:rotation="-720"
/>

Bu KeyAttributes, animasyonun% 50 ve% 100'ünde uygulanır. %50'lik ilk KeyAttribute, yayının en üstünde gerçekleşir ve görüntünün iki katına çıkarılmasına ve -360 derece (veya bir tam daire) döndürülmesine neden olur. İkinci KeyAttribute, ikinci dönüşü -720 dereceye (iki tam daire) bitirir ve scaleX ile scaleY değerleri varsayılan olarak 1,0 olduğundan boyutu tekrar normale çeker.

KeyPosition gibi, KeyAttribute da KeyFrame öğesinin ne zaman uygulanacağını ve hangi görünümün değiştirileceğini belirtmek için framePosition ve motionTarget öğelerini kullanır. MotionLayout, değişken animasyonlar oluşturmak için KeyPositions arasında arapolasyon yapar.

KeyAttributes, tüm görünümlere uygulanabilecek özellikleri destekler. Bunlar visibility, alpha veya elevation gibi temel özelliklerin değiştirilmesini destekler. Ayrıca, döndürmeyi burada yaptığınız gibi değiştirebilir, rotateX ve rotateY ile üç boyutta döndürebilir, boyutu scaleX ve scaleY ile ölçeklendirebilir veya görünümün konumunu X, Y veya Z biçiminde çevirebilirsiniz.

2. Adım: Kredilerin gösterilmesini geciktirin

Bu adımın hedeflerinden biri, animasyonu, animasyon neredeyse tamamlanana kadar jenerik metninin görünmeyecek şekilde güncellemektir.

  1. Kredilerin gösterilmesini ertelemek için alpha öğesinin keyPosition="85" tarihine kadar 0 kalmasını sağlayan bir KeyAttribute daha tanımlayın. MotionLayout, 0'dan 100 alfaya sorunsuz bir şekilde geçiş yapmaya devam eder, ancak bunu animasyonun son% 15'inde yapar.

step5.xml

<!-- TODO: Add KeyAttribute to delay the appearance of @id/credits -->

<KeyAttribute
       motion:framePosition="85"
       motion:motionTarget="@id/credits"
       android:alpha="0.0"
/>

Bu KeyAttribute, @id/credits öğesinin alpha değerini animasyonun ilk% 85'i için 0,0'da tutar. Alfa 0'da başladığından, animasyonun ilk% 85'inde görünmez olur.

Bu KeyAttribute işleminin nihai etkisi, jeneriklerin animasyonun sonuna doğru görünmesidir. Bu şekilde, ekranın sağ köşesindeki ay ile koordineli çalışırlar.

Bir görünümdeki animasyonları geciktirirken diğer görünüm bu şekilde hareket eder. Böylece, kullanıcıya dinamik bir deneyim yaşatan etkileyici animasyonlar oluşturabilirsiniz.

Deneyin

  1. Uygulamayı tekrar çalıştırın ve animasyonun nasıl çalıştığını görmek için 5. Adım'a gidin. Ay'ı tıkladığınızda, KeyFrameSet içinde belirtilen her bir KeyAttribute boyunca ilerleyerek yolu baştan sona izlersiniz.

2f4bfdd681c1fa98.gif

Ay'ı iki tam daire şeklinde döndürdüğünüz için arkaya iki kez dönmeniz gerekir. Ayrıca jenerik, animasyon neredeyse bitene kadar görünmelerini geciktirir.

Kendi başınıza keşfetme

Son KeyFrame türüne geçmeden önce KeyAttributes içindeki diğer standart özellikleri değiştirmeyi deneyin. Örneğin, hangi animasyonu oluşturduğunu görmek için rotation öğesini rotationX olarak değiştirmeyi deneyin.

Deneyebileceğiniz standart özelliklerin listesi aşağıda verilmiştir:

  • android:visibility
  • android:alpha
  • android:elevation
  • android:rotation
  • android:rotationX
  • android:rotationY
  • android:scaleX
  • android:scaleY
  • android:translationX
  • android:translationY
  • android:translationZ

9. Özel özellikleri değiştirme

Zengin animasyonlar, görünümün renginin veya diğer özelliklerinin değiştirilmesini içerir. MotionLayout, önceki görevde listelenen standart özelliklerden herhangi birini değiştirmek için KeyAttribute kullanabilir ancak diğer özellikleri belirtmek için CustomAttribute kullanırsınız.

CustomAttribute, belirleyici olan herhangi bir değeri ayarlamak için kullanılabilir. Örneğin, CustomAttribute kullanarak bir Görünümde backgroundColor'ı ayarlayabilirsiniz. MotionLayout, belirleyiciyi bulmak için yansıma özelliğini kullanır, ardından görünümü canlandırmak için tekrar tekrar çağırır.

Bu adımda, aşağıda gösterilen animasyonu oluşturmak amacıyla ayda colorFilter özelliğini ayarlamak için bir CustomAttribute kullanacaksınız.

5fb6792126a09fda.gif

Özel özellikleri tanımlama

  1. Başlamak için son adımda oluşturduğunuz animasyonun aynısını içeren xml/step6.xml öğesini açın.
  2. Ayın rengini değiştirmek için KeyFrameSet için keyFrame="0", keyFrame="50" ve keyFrame="100". noktalarındaki CustomAttribute ile iki KeyAttribute ekleyin.

214699d5fdd956da.png

step6.xml

<!-- TODO: Add Custom attributes here -->
<KeyAttribute
       motion:framePosition="0"
       motion:motionTarget="@id/moon">
   <CustomAttribute
           motion:attributeName="colorFilter"
           motion:customColorValue="#FFFFFF"
   />
</KeyAttribute>
<KeyAttribute
       motion:framePosition="50"
       motion:motionTarget="@id/moon">
   <CustomAttribute
           motion:attributeName="colorFilter"
           motion:customColorValue="#FFB612"
   />
</KeyAttribute>
<KeyAttribute
       motion:framePosition="100"
       motion:motionTarget="@id/moon">
   <CustomAttribute
           motion:attributeName="colorFilter"
           motion:customColorValue="#FFFFFF"
   />
</KeyAttribute>

KeyAttribute içine bir CustomAttribute eklersiniz. CustomAttribute, KeyAttribute ile belirtilen framePosition oranında uygulanacak.

CustomAttribute içinde bir attributeName ve ayarlanacak bir değer belirtmelisiniz.

  • motion:attributeName, bu özel özellik tarafından çağrılacak belirleyicinin adıdır. Bu örnekte, Drawable üzerindeki setColorFilter çağrılır.
  • motion:custom*Value, adda belirtilen türün özel değeridir. Bu örnekte, özel değer belirtilmiş bir renktir.

Özel değerler, aşağıdaki türlerden herhangi birine sahip olabilir:

  • Renk
  • Tamsayı
  • Kayan
  • Dize
  • Boyut
  • Boole

MotionLayout, bu API'yi kullanarak herhangi bir görünümde belirleyici sağlayan her şeyi canlandırabilir.

Deneyin

  1. Uygulamayı tekrar çalıştırın ve animasyonun nasıl çalıştığını görmek için 6. Adım'a gidin. Ay'ı tıkladığınızda, KeyFrameSet içinde belirtilen her bir KeyAttribute boyunca ilerleyerek yolu baştan sona izlersiniz.

5fb6792126a09fda.gif

Daha fazla KeyFrames eklediğinizde MotionLayout, ayın yolunu düz bir çizgiden karmaşık bir eğriye dönüştürerek çift ters çevirme, yeniden boyutlandırma ve animasyonun ortasında bir renk değişikliği ekler.

Gerçek animasyonlarda, genellikle birkaç görünümü aynı anda farklı yollar ve hızlardaki hareketlerini kontrol ederek canlandırırsınız. Her görünüm için farklı bir KeyFrame belirtildiğinde, MotionLayout kullanarak birden çok görünümü canlandıran zengin animasyonların koreografisini oluşturmak mümkündür.

10. Etkinlikleri ve karmaşık yolları sürükleme

Bu adımda, karmaşık yollar ile OnSwipe kullanımını keşfedeceksiniz. Şimdiye kadar, ay animasyonu bir OnClick dinleyicisi tarafından tetiklenmiş ve belirli bir süre boyunca oynatılmıştır.

OnSwipe kullanarak karmaşık yolları olan animasyonları (ör. son birkaç adımda oluşturduğunuz ay animasyonu) kontrol etmek için OnSwipe işlevinin nasıl çalıştığını anlamanız gerekir.

1. Adım: On Kaydırma davranışını keşfedin

  1. xml/step7.xml sayfasını açın ve mevcut OnSwipe beyanını bulun.

step7.xml

<!-- Fix OnSwipe by changing touchAnchorSide 

<OnSwipe
       motion:touchAnchorId="@id/moon"
       motion:touchAnchorSide="bottom"
/>
  1. Uygulamayı cihazınızda çalıştırıp 7. Adım'a gidin. Ayı yay çizgisi boyunca sürükleyerek akıcı bir animasyon elde edip edemeyeceğinize bakın.

Bu animasyonu çalıştırdığınızda pek iyi görünmez. Ay, yayın en üstüne ulaştığında zıplamaya başlar.

ed96e3674854a548.gif

Hatayı anlamak için kullanıcı yayın ekranının hemen alt kısmına dokunduğunda ne olduğunu düşünün. OnSwipe etiketinde motion:touchAnchorSide="bottom" bulunduğundan MotionLayout, animasyon boyunca parmak ile görünümün alt kısmı arasındaki mesafeyi sabit tutmaya çalışır.

Ancak ayın alt kısmı her zaman aynı yönde gitmediğinden önce yukarıya, sonra tekrar aşağıya iner. MotionLayout, kullanıcı yayının üst kısmını geçtiğinde ne yapacağını bilmez. Ay'ın altını izlediğiniz için kullanıcı buraya dokunduğunda bu görüntü neresine yerleştirilmelidir?

56cd575c5c77eddd.png

2. adım: Sağ tarafı kullanın

Bunun gibi hataları önlemek için her zaman animasyonun tamamı boyunca her zaman tek bir yönde ilerleyen bir touchAnchorId ve touchAnchorSide seçmek önemlidir.

Bu animasyonda, ayın hem right tarafı hem de left tarafı ekranda tek bir yönde ilerler.

Ancak hem bottom hem de top yönü tersine çevirir. OnSwipe onu takip etmeye çalıştığında yönü değiştiğinde kafası karışır.

  1. Bu animasyonun, dokunma etkinliklerini takip etmesini sağlamak için touchAnchorSide değerini right olarak değiştirin.

step7.xml

<!-- Fix OnSwipe by changing touchAnchorSide 

<OnSwipe
       motion:touchAnchorId="@id/moon"
       motion:touchAnchorSide="right"
/>

3. Adım: dragDirection'ı kullanın

Ayrıca, yan kanalı normalden farklı bir yöne çekmek için dragDirection ile touchAnchorSide birleştirebilirsiniz. touchAnchorSide yalnızca tek bir yönde ilerlemeye devam eder ancak MotionLayout ürününe hangi yönün izleneceğini söyleyebilirsiniz. Örneğin, touchAnchorSide="bottom" değerini koruyup dragDirection="dragRight" ekleyebilirsiniz. Bu, MotionLayout ürününün görünümün alt konumunu izlemesine neden olur, ancak sağa doğru hareket ederken yalnızca konumunu dikkate alır (dikey hareketi göz ardı eder). Dolayısıyla, alt kısım yukarı ve aşağı inse bile OnSwipe ile doğru bir şekilde animasyon oluşturmaya devam eder.

  1. Ayın hareketini doğru şekilde takip etmek için OnSwipe uygulamasını güncelleyin.

step7.xml

<!-- Using dragDirection to control the direction of drag tracking 

<OnSwipe
       motion:touchAnchorId="@id/moon"
       motion:touchAnchorSide="bottom"
       motion:dragDirection="dragRight"
/>

Deneyin

  1. Uygulamayı tekrar çalıştırın ve ayı tüm yol boyunca sürüklemeyi deneyin. MotionLayout, karmaşık bir yay takip etse de kaydırma etkinliklerine tepki olarak animasyonu ilerletebilir.

5458dff382261427.gif

11. Kodlu hareketli hareket

MotionLayout, CoordinatorLayout ile kullanıldığında zengin animasyonlar oluşturmak için kullanılabilir. Bu adımda, MotionLayout özelliğini kullanarak daraltılabilir bir başlık oluşturacaksınız.

1. Adım: Mevcut kodu inceleyin

  1. Başlamak için layout/activity_step8.xml uygulamasını açın.
  2. layout/activity_step8.xml ürününde, çalışan bir CoordinatorLayout ve AppBarLayout yönteminin zaten oluşturulmuş olduğunu görüyorsunuz.

activity_step8.xml

<androidx.coordinatorlayout.widget.CoordinatorLayout
       ...>
   <com.google.android.material.appbar.AppBarLayout
           android:id="@+id/appbar_layout"
           android:layout_width="match_parent"
           android:layout_height="180dp">
       <androidx.constraintlayout.motion.widget.MotionLayout
               android:id="@+id/motion_layout"
               ... >
           ...
       </androidx.constraintlayout.motion.widget.MotionLayout>
   </com.google.android.material.appbar.AppBarLayout>
  
   <androidx.core.widget.NestedScrollView
           ...
           motion:layout_behavior="@string/appbar_scrolling_view_behavior" >
           ...
   </androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

Bu düzen, NestedScrollView ile AppBarLayout arasında kaydırma bilgilerini paylaşmak için bir CoordinatorLayout kullanır. NestedScrollView yukarı kaydırıldığında AppBarLayout cihazına değişikliği bildirir. Android'de bu şekilde daraltılabilen bir araç çubuğu uygularsınız. Metnin kaydırılması "koordine edilir". başlığıyla daraltılabilir.

@id/motion_layout özelliğinin işaret ettiği hareket sahnesi, son adımdaki hareket sahnesine benziyor. Ancak OnSwipe beyanı, CoordinatorLayout ile çalışmasını sağlamak için kaldırılmıştır.

  1. Uygulamayı çalıştırın ve 8. Adım'a gidin. Metni kaydırdığınızda ayın hareket etmediğini görüyorsunuz.

2. Adım: MotionLayout'u kaydırın

  1. MotionLayout görünümünün NestedScrollView kaydırılır kaydırmaz kaydırılmasını sağlamak için motion:minHeight ve motion:layout_scrollFlags öğelerini MotionLayout öğesine ekleyin.

activity_step8.xml

<!-- Add minHeight and layout_scrollFlags to the MotionLayout -->

<androidx.constraintlayout.motion.widget.MotionLayout
       android:id="@+id/motion_layout"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       motion:layoutDescription="@xml/step8"
       motion:motionDebug="SHOW_PATH"
       android:minHeight="80dp"
       motion:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed"  >
  1. Uygulamayı tekrar çalıştırın ve 8. Adım'a gidin. Yukarı kaydırdıkça MotionLayout daralır. Bununla birlikte, animasyon henüz kaydırma davranışına göre ilerlemez.

3. Adım: Hareketi kodla taşıyın

  1. Step8Activity.kt uygulamasını açın . Kaydırma konumundaki değişiklikleri MotionLayout adlı kullanıcıya bildirmek için coordinateMotion() işlevini düzenleyin.

Step8Activity.kt

// TODO: set progress of MotionLayout based on an AppBarLayout.OnOffsetChangedListener

private fun coordinateMotion() {
    val appBarLayout: AppBarLayout = findViewById(R.id.appbar_layout)
    val motionLayout: MotionLayout = findViewById(R.id.motion_layout)

    val listener = AppBarLayout.OnOffsetChangedListener { unused, verticalOffset ->
        val seekPosition = -verticalOffset / appBarLayout.totalScrollRange.toFloat()
        motionLayout.progress = seekPosition
    }

    appBarLayout.addOnOffsetChangedListener(listener)
}

Bu kod, kullanıcı mevcut kaydırma ofsetiyle her kaydırdığında çağrılacak bir OnOffsetChangedListener kaydeder.

MotionLayout, ilerleme durumunu ayarlayarak geçiş sürecini destekler. verticalOffset ile yüzdelik ilerleme durumu arasında dönüştürme yapmak için toplam kaydırma aralığına bölün.

Deneyin

  1. Uygulamayı tekrar dağıtın ve 8. Adım animasyonunu çalıştırın. MotionLayout öğesinin, animasyonu kaydırma konumuna göre ilerleteceğini görürsünüz.

ee5ce4d9e33a59ca.gif

MotionLayout kullanarak özel dinamik daraltma araç çubuğu animasyonları oluşturabilirsiniz. Bir KeyFrames dizisi kullanarak çok çarpıcı efektler elde edebilirsiniz.

12. Tebrikler

Bu codelab'de MotionLayout ile ilgili temel API ele alınmıştır.

MotionLayout ile ilgili daha fazla örnek görmek için resmi örneği inceleyin. Belgeleri incelemeyi unutmayın.

Daha Fazla Bilgi

MotionLayout, bu codelab'de ele alınmayan başka özellikleri de destekler. Örneğin, tekrarlanan döngüleri olan yolları veya özellikleri kontrol etmenizi sağlayan KeyCycle, ve saat saatine göre animasyon yapmanıza olanak tanıyan KeyTimeCycle, gibi. Her biriyle ilgili örnekler için örneklere göz atın.

Bu kurstaki diğer codelab'lerin bağlantıları için Kotlin codelab'lerinde gelişmiş Android açılış sayfasına göz atın.