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ırayla incelemeniz önerilir ancak bu zorunlu değildir. Kursla ilgili tüm codelab'ler Advanced Android in Kotlin codelabs açılış sayfasında listelenir.

MotionLayout, Android uygulamanıza zengin hareketler eklemenizi sağlayan bir kitaplıktır. ConstraintLayout, temel alınarak geliştirilmiştir ve ConstraintLayout kullanarak oluşturduğunuz her şeyi canlandırmanıza olanak tanır.

Aynı anda birden fazla görünümün konumunu, boyutunu, görünürlüğünü, alfa değerini, rengini, yüksekliğini, dönüşünü ve diğer özelliklerini canlandırmak için MotionLayout kullanabilirsiniz. Bildirimli XML kullanarak, kodda elde edilmesi zor olan ve birden fazla görünüm içeren koordineli animasyonlar oluşturabilirsiniz.

Animasyonlar, uygulama deneyimini iyileştirmenin harika bir yoludur. Animasyonları kullanarak:

  • Değişiklikleri gösterme: Durumlar arasında animasyon oluşturmak, kullanıcının kullanıcı arayüzünüzdeki değişiklikleri doğal bir şekilde takip etmesini sağlar.
  • Dikkat çekin: Önemli kullanıcı arayüzü öğelerine dikkat çekmek için animasyonlar kullanın.
  • Güzel tasarımlar oluşturun: Tasarımdaki etkili hareketler, uygulamaların kusursuz görünmesini sağlar.

Ön koşullar

Bu codelab, Android geliştirme konusunda deneyimli geliştiriciler için tasarlanmıştır. Bu codelab'i tamamlamaya çalışmadan önce şunları yapmanız gerekir:

  • Android Studio'yu kullanarak etkinlik ve temel düzen içeren bir uygulama oluşturmayı ve bunu cihazda veya emülatörde çalıştırmayı öğrenin. ConstraintLayout hakkında bilgi sahibi olun. ConstraintLayout hakkında daha fazla bilgi edinmek için Constraint Layout codelab'ini inceleyin.

Yapacaklarınız

  • ConstraintSets ve MotionLayout ile animasyon tanımlama
  • Sürükleme etkinliklerine göre animasyon oluşturma
  • Animasyonu KeyPosition ile değiştirme
  • KeyAttribute ile özellikleri değiştirme
  • Kodla animasyon çalıştırma
  • Daraltılabilir başlıkları MotionLayout ile canlandırma

Gerekenler

  • Android Studio 4.0 (MotionLayout düzenleyici yalnızca bu Android Studio 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ının tıklamalarına yanıt olarak bir görünümü ekranın üst kısmından alt kısmına taşıyan bir animasyon oluşturacaksınız.

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

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

MotionLayout ile başlayarak bunların her birini sırayla inceleyelim.

1. adım: Mevcut kodu inceleyin

MotionLayout, ConstraintLayout öğesinin bir alt sınıfı olduğundan animasyon eklerken aynı özelliklerin tümünü destekler. MotionLayout özelliğini kullanmak için ConstraintLayout. özelliğini kullanacağınız yere MotionLayout görünümü ekleyin

  1. res/layout bölümünde activity_step1.xml. simgesini açın. Burada, içinde renk tonu uygulanmış tek bir ImageView yıldız bulunan ConstraintLayout simgesi yer alır.

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 üzerinde herhangi bir kısıtlama yoktur. Bu nedenle, uygulamayı şimdi çalıştırırsanız yıldızların kısıtlanmamış şekilde gösterildiğini görürsünüz. Bu da yıldızların bilinmeyen bir konumda yerleştirileceği anlamına gelir. Android Studio, kısıtlamaların olmamasıyla ilgili sizi uyarır.

2. adım: Motion Layout'a dönüştürme

MotionLayout, kullanarak animasyon oluşturmak için ConstraintLayout öğesini MotionLayout öğesine dönüştürmeniz gerekir.

Düzeninizin hareketli sahne kullanması için bu 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 Convert to MotionLayout'u (MotionLayout'a dönüştür) seçin.

4fa936a98a8393b9.png

Bu işlem, ConstraintLayout etiketini MotionLayout etiketiyle değiştirir ve MotionLayout etiketine @xml/activity_step1_scene. öğesini 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'e dönüştürdüğünüz anda tasarım yüzeyinde Motion Editor gösterilir.

66d0e80d5ab4daf8.png

Motion Editor'da üç yeni kullanıcı arayüzü öğesi bulunur:

  1. Genel bakış: Bu, animasyonun farklı bölümlerini seçmenize olanak tanıyan bir modal 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, şu anda 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çilen öğenin özelliklerini gösterir ve düzenlemenize olanak tanır. Bu resimde, start ConstraintSet için özellikler gösterilmektedir.

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

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

MotionScene, başlangıç ve bitiş durumlarını tanımlamak için ConstraintSet etiketini kullanır. ConstraintSet, görünümlere uygulanabilen bir kısıtlama grubudur. Genişlik, yükseklik ve ConstraintLayout kısıtlamaları buna dahildir. Ayrıca alpha gibi bazı özellikler de içerir. Görünümlerin kendisini değil, yalnızca bu görünümlerle ilgili kısıtlamaları içerir.

ConstraintSet içinde belirtilen tüm kısıtlamalar, düzen dosyasında belirtilen kısıtlamaları geçersiz kılar. Hem düzende hem de MotionScene içinde kısıtlamalar tanımlarsanız yalnızca MotionScene içindeki kısıtlamalar uygulanır.

Bu adımda, yıldız görünümünü ekranın üst kısmından başlayıp alt kısmında bitecek şekilde sınırlayacaksınız.

Bu adımı Motion Editor'ı 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, ConstraintSet içinde sınırlanmadığı anlamına gelir. Sağ üstteki kalem simgesini kullanarak Kısıtlama Oluşturun.

f9564c574b86ea8.gif

  1. Genel bakış panelinde start ConstraintSet seçildiğinde red_star simgesinin start Kaynağı gösterdiğini doğrulayın.
  2. Özellikler panelinde, red_star seçiliyken start ConstraintSet, üst kısma bir kısıtlama ekleyin ve mavi + düğmelerini tıklayarak başlayın.

2fce076cd7b04bd.png

  1. Motion Editor'ın bu kısıtlama için oluşturduğu kodu görmek üzere xml/activity_step1_scene.xml simgesini 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/start id değerine sahip 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 gerekir.

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

Bu kısıtlama, red_star görünümünü üst öğesinin en üst başlangıcına kısıtlamak 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 için Motion Editor'ı kullanmak üzere mavi + düğmelerini tıklayarak bottom ve end öğelerine kısıtlama ekleyin.

fd33c779ff83c80a.png

  1. XML'deki kod şu şekilde 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 da @id/red_star üzerinde tek bir Constraint içerir. Bu kez ekranın alt ucuyla sınırlanır.

Bunları @id/start ve @id/end olarak adlandırmanız gerekmez ancak bu şekilde adlandırmanız kolaylık sağlar.

4. adım: Geçiş tanımlayın

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

Bir geçiş, geçiş için bir başlangıç ve bitiş ConstraintSet belirtmelidir. Geçişler, animasyonun nasıl değiştirileceğini başka şekillerde de belirtebilir. Örneğin, animasyonun ne kadar süreyle çalıştırılacağı veya görünümleri sürükleyerek nasıl animasyon oluşturulacağı gibi.

  1. Motion Editor, MotionScene dosyasını oluştururken varsayılan olarak bizim için bir geçiş oluşturdu. Oluşturulan geçişi görmek için activity_step1_scene.xml simgesini 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, animasyon oluşturmak için bu bilgilere ihtiyaç duyar. Her bir özelliğe bakıldığında:

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

MotionLayout, başlangıç ve bitiş kısıtlamaları arasında bir yol belirleyip belirtilen süre boyunca bu yolu animasyon haline getirir.

5. adım: Motion Editor'da animasyonu önizleyin

dff9ecdc1f4a0740.gif

Animasyon: Motion Editor'da geçiş önizlemesinin oynatıldığı video

  1. Motion Editor'ı 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, geçiş seçildiğinde oynatma kontrolleri ve kaydırma çubuğu gösterilir. Animasyonu önizlemek için oynat düğmesini tıklayın veya mevcut konumu sürükleyin.

a0fd2593384dfb36.png

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

Animasyonu başlatmak için bir yöntem gerekir. 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ıç ile 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şleyicisi oluştur'u tıklayın . Bu işlem, geçişi başlatacak bir işleyici ekler.
  2. Pop-up pencereden Click Handler'ı (Tıklama İşleyici) seçin.

ccf92d06335105fe.png

  1. Görüntüleme İçin Tıklama'yı red_star olarak değiştirin.

b0d3f0c970604f01.png

  1. Ekle'yi tıklayın. Tıklama işleyicisi, Motion Editor'daki Geçiş'te küçük bir nokta ile gösterilir.

cec3913e67fb4105.png

  1. Genel bakış panelinde geçiş seçiliyken, özellikler panelinde yeni eklediğiniz OnClick işleyicisine clickAction özelliğini toggle olarak ekleyin.

9af6fc60673d093d.png

  1. Hareket Düzenleyici'nin oluşturduğu kodu görmek için activity_step1_scene.xml simgesini 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 öğesine <OnClick> etiketi kullanarak tıklama etkinliklerine yanıt olarak animasyonu çalıştırmasını söyler. Her bir özelliğe bakıldığında:

  • targetId, tıklamaları izlemek için kullanılan görünümdür.
  • clickAction, tıklama üzerine toggle başlangıç ve bitiş durumu arasında geçiş yapar. clickAction için diğer seçenekleri dokümanlarda görebilirsiniz.
  1. Kodunuzu çalıştırın, 1. Adım'ı ve ardından kırmızı yıldızı tıklayarak animasyonu izleyin.

5. adım: Animasyonları kullanma

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

7ba88af963fdfe10.gif

Tamamlanan hareket sahnesi dosyası, başlangıç ve bitiş ConstraintSet noktalarını gösteren bir Transition tanımlar.

Animasyonun başlangıcında (@id/start), yıldız simgesi ekranın üst kısmının başlangıcına sabitlenir. Animasyonun sonunda (@id/end) yıldız simgesi ekranın alt kısmına sabitlenir.

<?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 göre animasyon oluşturma

Bu adımda, animasyonu çalıştırmak için kullanıcının 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 taşımak için dokunma etkinliklerinin yanı sıra hareketi akıcı hale getirmek için fizik tabanlı fırlatma hareketlerinin izlenmesini destekler.

1. adım: İlk kodu inceleyin

  1. Başlamak için mevcut bir MotionLayout içeren düzen dosyasını activity_step2.xml 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, animasyonun tüm görünümlerini tanımlar. Üç yıldız simgesi, hareket sahnesinde animasyonlu olacağı için düzende kısıtlanmaz.

Krediler, animasyon boyunca aynı yerde kaldığı ve herhangi bir özelliği değiştirmediği için TextView kısıtlamalara tabidir.

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.

Başlangıç ConstraintSet'ini tanımlayın.

  1. Animasyonu tanımlamak için hareketli sahneyi xml/step2.xml açın.
  2. Başlangıç kısıtlaması start için kısıtlamaları ekleyin. Başlangıçta üç yıldız da ekranın alt kısmında ortalanır. Sağ ve soldaki yıldızların alpha değeri 0.0'dir. Bu, yıldızların tamamen şeffaf ve gizli olduğu 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 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 kısımla ilgili kısıtlamalar kullanılarak ekranın alt kısmında ortalanır. @id/left_star ve @id/right_star yıldızlarının her ikisinde de görünmez olmalarını sağlayan ve animasyonun başında uygulanacak ek bir alfa değeri vardır.

start ve end kısıtlama kümeleri, animasyonun başlangıcını ve bitişini tanımlar. motion:layout_constraintStart_toStartOf gibi başlangıç kısıtlamaları, 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. start adı hem hem için kullanıldığından ve her ikisi de kısıtlamalar bağlamında kullanıldığından bu durum ilk başta kafa karıştırıcı olabilir. Farkı daha net bir şekilde ifade etmek için layout_constraintStart içindeki start, görünümün "başlangıç" noktasını ifade eder. Bu nokta, soldan sağa dillerde sol, sağdan sola dillerde ise sağ taraftır. start kısıtlama grubu, animasyonun başlangıcını ifade eder.

Bitiş ConstraintSet'ini tanımlama

  1. Üç yıldızı @id/credits'nin altında birlikte konumlandırmak için zincir kullanacak şekilde son kısıtlamayı tanımlayın. Ayrıca, sol ve sağ yıldızların alpha bitiş değerini 1.0 olarak ayarlar.

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, animasyon sırasında görünümler merkezden dışa ve yukarı doğru yayılır.

Ayrıca, alpha özelliği her iki ConstraintSets'de de @id/right_start ve @id/left_star üzerinde ayarlandığından animasyon ilerledikçe her iki görünüm de yavaş yavaş belirginleşir.

Kullanıcı kaydırmasına göre animasyon oluşturma

MotionLayout, fizik tabanlı bir "hızlı kaydırma" animasyonu oluşturmak için kullanıcıların sürükleme etkinliklerini veya kaydırma işlemlerini izleyebilir. Bu nedenle, kullanıcı kaydırarak görüntülediğinde görünümler devam eder ve bir yüzeyde yuvarlanan fiziksel bir nesne gibi yavaşlar. Bu tür animasyonları Transition içindeki OnSwipe etiketiyle ekleyebilirsiniz.

  1. OnSwipe etiketi eklemeyle ilgili YAPILACAKLAR'ı <OnSwipe motion:touchAnchorId="@id/red_star" /> ile 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çerir. Bunlardan en önemlisi touchAnchorId özelliğidir.

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

MotionLayout sürükleme etkinliklerini dinlediğinde işleyici, touchAnchorId tarafından belirtilen görünümde değil, MotionLayout görünümünde kaydedilir. Kullanıcı ekranda herhangi bir yerde hareket başlattığında MotionLayout, parmağı ile touchAnchorId görünümünün touchAnchorSide arasındaki mesafeyi sabit tutar. Örneğin, MotionLayout, sabitleme tarafının 100 dp uzağına dokunursa animasyon 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. MotionLayout uygulamasının akışkan fizik tabanlı animasyonları nasıl gösterdiğini keşfetmek için animasyonun ortasında parmağınızı "fırlatmayı" veya bırakmayı deneyin.

fefcdd690a0dcaec.gif

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

Bu animasyonda, başlangıçta üç görünüm de ekranın alt kısmındaki üst öğesine göre konumlandırılır. Son olarak, üç görünüm zincir şeklinde @id/credits ile ilişkili olarak konumlandırılır.

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

5. Yolu değiştirme

Bu adımda, animasyon sırasında karmaşık bir yolu takip eden ve hareket sırasında jenerikleri canlandıran bir animasyon oluşturacaksınız. MotionLayout, KeyPosition kullanarak bir görünümün başlangıç ve bitiş arasındaki yolunu 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'ı açın. ImageView ve TextView simgelerinde ay ve "credits" (krediler) metni gösteriliyor.
  2. Hareketli sahne dosyasını (xml/step3.xml) açın. @id/start'den @id/end'e bir Transition tanımlandığını görürsünüz. Animasyon, iki ConstraintSets kullanarak ay resmini ekranın sol alt kısmından sağ alt kısmına taşıyor. Ay hareket ederken alpha="0.0" olan jenerik metni alpha="1.0" olarak belirginleşir.
  3. Uygulamayı şimdi çalıştırın ve 3. Adım'ı seçin. Ayı tıkladığınızda, ayın başlangıçtan sona doğrusal bir yol (veya düz bir çizgi) izlediğini görürsünüz.

2. adım: Yol hata ayıklamayı etkinleştirin

Ayın hareketine yay eklemeden önce MotionLayout'da yol hata ayıklamayı etkinleştirmeniz yararlı olur.

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

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

activity_step3.xml

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

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

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

23bbb604f456f65c.png

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

Örneğin, bu animasyonda ortadaki daire, krediler metninin konumunu gösterir.

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

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

Bu örnekteki ayın yörüngesi gibi karmaşık yollar oluşturmak için MotionLayout, görünümün başlangıç ve bitiş arasındaki yolunu değiştirmek üzere KeyPosition kullanır.

  1. xml/step3.xml uygulamasını 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, Transition öğesinin alt öğesidir ve geçiş sırasında uygulanması gereken tüm KeyFrames'lerin (ör. KeyPosition) kümesidir.

MotionLayout, başlangıç ve bitiş arasındaki ay yolunu hesaplarken KeyFrameSet içinde belirtilen KeyPosition değerine göre yolu değiştirir. Uygulamayı tekrar çalıştırarak bu değişikliğin yolu nasıl değiştirdiğini görebilirsiniz.

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

  • framePosition, 0 ile 100 arasında bir sayıdır. Bu özellik, animasyonun hangi noktasında KeyPosition özelliğinin uygulanacağını tanımlar. 1, animasyonun% 1'i tamamlandığında, 99 ise% 99'u tamamlandığında uygulanacağını gösterir. Bu nedenle, değer 50 ise tam ortada uygularsınız.
  • motionTarget, bu KeyPosition öğesinin yolu değiştirdiği görünümdür.
  • keyPositionType, bu KeyPosition öğesinin yolu nasıl değiştirdiğini gösterir. parentRelative, pathRelative veya deltaRelative olabilir (sonraki adımda açıklanmıştır).
  • percentX | percentY, framePosition konumunda yolun ne kadar değiştirileceğini gösterir (0,0 ile 1,0 arasında değerler; negatif değerlere ve 1'den büyük değerlere izin verilir).

Bunu şu şekilde düşünebilirsiniz: "framePosition koordinatları tarafından belirlenen keyPositionTypekoordinatlarına göre motionTarget yolunu percentX veya percentY kadar hareket ettirerek değiştirin."

Varsayılan olarak MotionLayout, yolu değiştirerek oluşturulan tüm köşeleri yuvarlar. Oluşturduğunuz animasyona baktığınızda ayın, kıvrımda kavisli bir yolu izlediğini görebilirsiniz. Çoğu animasyon için bu değer kullanılır. Aksi takdirde, özelleştirmek için curveFit özelliğini belirtebilirsiniz.

Deneyin

Uygulamayı tekrar çalıştırırsanız bu adımın animasyonunu görürsünüz.

46b179c01801f19e.gif

Ay, Transition içinde belirtilen bir KeyPosition boyunca hareket ettiği için bir yay izler.

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

Bu ifadeyi KeyPosition olarak okuyabilirsiniz: "framePosition 50 (animasyonun yarısında) motionTarget @id/moon öğesinin yolunu, parentRelative (tüm MotionLayout) tarafından belirlenen koordinatlara göre 50% Y (ekranın yarısı) kadar hareket ettirerek değiştirin."

Bu nedenle, animasyonun yarısında ay, ekranda% 50 aşağıda olan bir KeyPosition içinden geçmelidir. Bu KeyPosition, X hareketini hiç değiştirmez. Bu nedenle ay, baştan sona yatay olarak hareket etmeye devam eder. MotionLayout, başlangıç ve bitiş arasında hareket ederken bu KeyPosition'dan geçen sorunsuz bir yol bulur.

Yakından bakarsanız kredi metninin ayın konumuyla sınırlı olduğunu görürsünüz. 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"
/>

Ayın izlediği yolu değiştirseniz bile ayın başlangıç ve bitiş konumları 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ırlıdır.

Jeneriklerin ay ile birlikte hareket etmesini istiyorsanız jeneriklere KeyPosition ekleyebilir veya @id/credits üzerindeki başlangıç kısıtlamalarını değiştirebilirsiniz.

Bir sonraki bölümde, MotionLayout içindeki farklı keyPositionType türlerini inceleyeceğiz.

6. keyPositionType özelliğini anlama

Son adımda, yolu ekranın% 50'si kadar kaydırmak için keyPosition türünde bir parentRelative kullandınız. keyPositionType özniteliği, MotionLayout'un yolu percentX veya percentY değerine göre nasıl değiştireceğini belirler.

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

Üç 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, uzayda bir noktayı belirtmenin bir yolunu sunar. Ayrıca ekrandaki bir konumu tanımlamak için de kullanılırlar.

MotionLayout koordinat sistemleri Kartezyen koordinat sistemidir. Bu, iki dik çizgiyle tanımlanan bir X ve bir Y eksenine sahip oldukları anlamına gelir. Bu iki eksen arasındaki temel fark, X ekseninin ekranda bulunduğu 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ında değerler kullanır. Negatif değerlere ve 1.0 değerinden büyük değerlere izin verilir. Örneğin, percentX değeri -2.0 ise X ekseninin tersi yönünde iki kez hareket etmeniz gerekir.

Bu bilgiler biraz fazla matematiksel geliyorsa aşağıdaki resimlere göz atın.

parentRelative coordinates

a7b7568d46d9dec7.png

parentRelative öğesinin keyPositionType özelliği, ekranla aynı koordinat sistemini kullanır. (0, 0), tüm MotionLayout'nin sol üstünü, (1, 1) ise sağ altını tanımlar.

parentRelative, bu örnekteki ay yayı gibi MotionLayout boyunca hareket eden bir animasyon oluşturmak istediğinizde kullanılabilir.

Ancak bir yolu harekete göre değiştirmek (ör. yolu biraz kıvrımlı hale getirmek) istiyorsanız diğer iki koordinat sistemi daha iyi bir seçimdir.

deltaRelative koordinatları

5680bf553627416c.png

Delta, değişim anlamına gelen bir matematik terimidir. Bu nedenle deltaRelative, "göreceli değişim" demenin bir yoludur. deltaRelative koordinatları(0,0), görünümün başlangıç konumunu, (1,1) ise bitiş konumunu ifade eder. X ve Y eksenleri ekranla hizalanır.

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

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

pathRelative koordinatları

f3aaadaac8b4a93f.png

MotionLayout içindeki son koordinat sistemi pathRelative. X ekseni, hareket yolunu baştan sona takip ettiğinden bu grafik diğer ikisinden oldukça farklıdır. Bu nedenle (0,0) başlangıç konumu, (1,0) ise bitiş konumudur.

Bunu neden isteyebilirsiniz? Bu koordinat sistemi, ekran koordinat sistemiyle bile hizalanmadığı için ilk bakışta oldukça şaşırtıcıdır.

pathRelative'nın birkaç konuda gerçekten faydalı olduğu ortaya çıktı.

  • Animasyonun bir bölümünde görünümü hızlandırma, yavaşlatma veya durdurma. X boyutu, görünümün izlediği yolla her zaman tam olarak eşleştiğinden, bu yoldaki belirli bir noktaya hangi framePosition ile ulaşıldığını değiştirmek için pathRelative KeyPosition kullanabilirsiniz. Bu nedenle, percentX="0.1" ile framePosition="50" konumundaki bir KeyPosition, animasyonun hareketin ilk% 10'unu tamamlaması için gereken sürenin% 50'sini kullanmasına neden olur.
  • Yola ince bir yay ekleme. Y boyutu her zaman harekete dik olduğundan Y'yi değiştirmek, genel harekete göre eğri yolunu değiştirir.
  • deltaRelative İkinci boyut ekleme işlemi çalışmaz. Tamamen yatay ve dikey hareket için deltaRelative yalnızca bir faydalı boyut oluşturur. Ancak pathRelative her zaman kullanılabilir X ve Y koordinatları oluşturur.

Bir 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 baktığımızda, düzgün bir eğri oluşturduğunu ancak şeklin daha "ay benzeri" olabileceğini görüyoruz.

Birden fazla KeyPosition öğesi içeren bir yolu değiştirme

MotionLayout, herhangi bir hareketi elde etmek için gereken sayıda KeyPosition tanımlayarak yolu daha da değiştirebilir. Bu animasyonda bir yay oluşturacaksınız ancak isterseniz ayı ekranın ortasında yukarı ve aşağı zıplatabilirsiniz.

  1. xml/step4.xml adlı kişiyi aç. Son adımda eklediğiniz görüntülemelerin ve KeyFrame sayısının aynı olduğunu görürsünüz.
  2. Eğrinin üst kısmını tamamlamak için @id/moon yoluna iki tane daha KeyPositions ekleyin. Bunlardan biri tepeye ulaşmadan hemen önce, diğeri ise ulaştıktan sonra 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'i tamamlandığında uygulanır ve @id/moon öğesinin ekranın üst kısmından% 60 uzaklıkta bir yolda hareket etmesine neden olur. %50'lik mevcut KeyPosition ile birleştiğinde, ayın izleyeceği düzgün bir yay oluşturur.

MotionLayout bölümünde, istediğiniz hareket yolunu elde etmek için ihtiyacınız olan sayıda KeyPositions ekleyebilirsiniz. MotionLayout, belirtilen framePosition'de her bir KeyPosition'i uygular ve tüm KeyPositions'den geçen akıcı bir hareketin nasıl oluşturulacağını belirler.

Deneyin

  1. Uygulamayı tekrar çalıştırın. Animasyonun işleyiş şeklini görmek için 4. Adım'a gidin. Ayı tıkladığınızda, KeyFrameSet içinde belirtilen her bir KeyPosition öğesinden geçerek baştan sona kadar yolu takip eder.

Kendiniz keşfedin

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

Aşağıda, animasyon sırasında ileri geri hareket eden karmaşık bir yolun nasıl oluşturulacağını gösteren bir örnek verilmiştir.

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 tamamladığınızda 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 özelliklerini değiştirmek anlamına gelir. MotionLayout, KeyAttribute kullanarak herhangi bir görünümde birçok özelliğin canlandırılmasını destekler.

Bu adımda, Ay'ın ölçeğini ayarlamak ve döndürmek için KeyAttribute simgesini kullanacaksınız. Metnin görünümünü, ay yolculuğunu neredeyse tamamlayana kadar geciktirmek için de 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 animasyonu içeren xml/step5.xml dosyasını açın. Bu ekranda, çeşitlilik için arka plan olarak farklı bir uzay resmi kullanılıyor.
  2. Ayın boyutunu büyütmek ve döndürmek için KeyAttribute etiketlerini KeyFrameSet bölümüne keyFrame="50" ve keyFrame="100" konumlarında 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'si ve% 100'ü için uygulanır. %50'deki ilk KeyAttribute, yayın eğrisinin en üstünde gerçekleşir ve görünümün hem iki kat büyümesine hem de -360 derece (veya tam bir daire) dönmesine neden olur. İkinci KeyAttribute, ikinci dönüşü -720 dereceye (iki tam daire) tamamlayacak ve scaleX ile scaleY değerleri varsayılan olarak 1,0 olduğundan boyutu tekrar normal boyutuna küçültecektir.

KeyPosition gibi, KeyAttribute de KeyFrame'nin ne zaman uygulanacağını ve hangi görünümün değiştirileceğini belirtmek için framePosition ve motionTarget'ü kullanır. Akıcı animasyonlar oluşturmak için MotionLayout ile KeyPositions arasında enterpolasyon yapılır.

KeyAttributes Tüm görünümlere uygulanabilen özellikleri destekler. 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, scaleX ve scaleY ile boyutu ölçeklendirebilir veya görünümün konumunu X, Y ya da Z ekseninde çevirebilirsiniz.

2. adım: Jeneriklerin görünümünü geciktirin

Bu adımın amaçlarından biri, animasyonu güncelleyerek animasyon neredeyse tamamlanana kadar jenerik metninin görünmemesini sağlamaktır.

  1. Kredilerin görünümünü geciktirmek için KeyAttribute değerini, alpha değerinin keyPosition="85" değerine kadar 0 kalmasını sağlayacak şekilde tanımlayın. MotionLayout, 0'dan 100 alfa değerine 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, animasyonun ilk% 85'i boyunca @id/credits alpha değerini 0,0'da tutar. Alfa değeri 0'dan başladığı için animasyonun ilk% 85'inde görünmez olur.

Bu KeyAttribute işleminin sonucunda, animasyonun sonuna doğru krediler gösterilir. Bu sayede, ekranın sağ köşesinde yerleşen ay ile uyumlu bir görünüm elde edilir.

Bir görünüm bu şekilde hareket ederken başka bir görünümdeki animasyonları geciktirerek kullanıcıya dinamik hissettiren etkileyici animasyonlar oluşturabilirsiniz.

Deneyin

  1. Uygulamayı tekrar çalıştırın ve animasyonu çalışırken görmek için 5. adıma gidin. Ayı tıkladığınızda, KeyFrameSet içinde belirtilen her KeyAttribute'dan geçerek baştan sona kadar yolu takip eder.

2f4bfdd681c1fa98.gif

Ayı iki tam daire döndürdüğünüz için artık iki kez geriye doğru takla atacak ve animasyon neredeyse tamamlanana kadar jenerik gösterilmeyecek.

Kendiniz keşfedin

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

Aşağıda, deneyebileceğiniz standart özelliklerin listesi 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, bir görünümün rengini veya diğer özelliklerini değiştirmeyi içerir. MotionLayout, önceki görevde listelenen standart özelliklerden herhangi birini değiştirmek için KeyAttribute kullanabilirken diğer özellikleri belirtmek için CustomAttribute kullanırsınız.

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

Bu adımda, aşağıdaki animasyonu oluşturmak için ay üzerindeki colorFilter özelliğini ayarlamak üzere CustomAttribute kullanacaksınız.

5fb6792126a09fda.gif

Özel özellikler tanımlama

  1. Başlamak için son adımda oluşturduğunuz animasyonu içeren xml/step6.xml dosyasını açın.
  2. Ayın renk değiştirmesini sağlamak için KeyAttribute simgesini KeyFrameSet bölümüne keyFrame="0", keyFrame="50" ve keyFrame="100". konumlarında CustomAttribute ile birlikte 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 CustomAttribute eklediğinizde CustomAttribute, KeyAttribute tarafından belirtilen framePosition tarihinde uygulanır.

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

  • motion:attributeName, bu özel özellik tarafından çağrılacak ayarlayıcının adıdır. Bu örnekte, Drawable üzerindeki setColorFilter çağrılır.
  • motion:custom*Value, adında belirtilen türde bir özel değerdir. Bu örnekte özel değer, belirtilen bir renktir.

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

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

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

Deneyin

  1. Uygulamayı tekrar çalıştırın ve animasyonu çalışırken görmek için 6. adıma gidin. Ayı tıkladığınızda, KeyFrameSet içinde belirtilen her KeyAttribute'dan geçerek baştan sona kadar yolu takip eder.

5fb6792126a09fda.gif

Daha fazla KeyFrames eklediğinizde MotionLayout, ayın yolunu düz bir çizgiden karmaşık bir eğriye dönüştürür. Animasyonun ortasında çift geri takla, yeniden boyutlandırma ve renk değişikliği eklenir.

Gerçek animasyonlarda genellikle birden fazla görünümü aynı anda canlandırır, hareketlerini farklı yollar ve hızlarda kontrol edersiniz. Her görünüm için farklı bir KeyFrame belirterek, MotionLayout ile birden fazla görünümü canlandıran zengin animasyonlar oluşturmak mümkündür.

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

Bu adımda, karmaşık yollarla OnSwipe kullanmayı keşfedeceksiniz. Şimdiye kadar ayın animasyonu bir OnClick dinleyicisi tarafından tetikleniyordu ve sabit bir süre boyunca çalışıyordu.

Son birkaç adımda oluşturduğunuz ay animasyonu gibi OnSwipe ile karmaşık yollara sahip animasyonları kontrol etmek için OnSwipe'nın nasıl çalıştığını anlamanız gerekir.

1. adım: OnSwipe davranışını keşfedin

  1. xml/step7.xml simgesini 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ın ve 7. adım'a gidin. Ayı yayın yolu boyunca sürükleyerek akıcı bir animasyon oluşturup oluşturamayacağınızı görün.

Bu animasyonu çalıştırdığınızda çok iyi görünmüyor. Ay, yayın en üst noktasına ulaştıktan sonra etrafta zıplamaya başlar.

ed96e3674854a548.gif

Hatayı anlamak için kullanıcının yayın üst kısmının hemen altına dokunduğunda ne olduğunu düşünün. OnSwipe etiketi motion:touchAnchorSide="bottom" içerdiğinden 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 hareket etmediği için (önce yukarı çıkar, sonra tekrar aşağı iner) MotionLayout, kullanıcı yayın en üst noktasını geçtiğinde ne yapacağını bilemez. Bunu göz önünde bulundurmak için, ayın alt kısmını izlediğinize göre kullanıcı buraya dokunduğunda nereye yerleştirilmelidir?

56cd575c5c77eddd.png

2. adım: Doğru tarafı kullanın

Bu tür hataları önlemek için 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 ters yönde hareket eder. OnSwipe onları izlemeye çalıştığında yönleri 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, bir yan parçanın normalde olduğundan farklı bir yönde ilerlemesini sağlamak için dragDirection ile touchAnchorSide simgesini birleştirebilirsiniz. touchAnchorSide öğesinin yalnızca tek bir yönde ilerlemesi önemlidir ancak touchAnchorSide öğesine hangi yönde izleneceğini söyleyebilirsiniz.MotionLayout Örneğin, touchAnchorSide="bottom" simgesini koruyup dragDirection="dragRight" simgesini ekleyebilirsiniz. Bu durumda MotionLayout, görünümün alt kısmının konumunu izler ancak yalnızca sağa hareket ederken konumunu dikkate alır (dikey hareketi yoksayar). Bu nedenle, alt kısım yukarı ve aşağı hareket etse de OnSwipe ile doğru şekilde animasyon oluşturulur.

  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. Karmaşık bir yay izlese de MotionLayout, kaydırma etkinliklerine yanıt olarak animasyonu ilerletebilir.

5458dff382261427.gif

11. Kodu kullanarak hareket çalıştırma

MotionLayout, CoordinatorLayout ile birlikte kullanıldığında zengin animasyonlar oluşturmak için kullanılabilir. Bu adımda, MotionLayout 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 içinde, çalışan bir CoordinatorLayout ve AppBarLayout'nin zaten oluşturulduğunu görürsünüz.

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 CoordinatorLayout kullanır. Bu nedenle, NestedScrollView yukarı kaydığında AppBarLayout'ye değişiklik hakkında bilgi verir. Android'de bu tür daraltılabilir araç çubuğu bu şekilde uygulanır. Metnin kaydırılması, daraltılabilir üstbilgiyle "koordine edilir".

@id/motion_layout ile gösterilen hareket sahnesi, son adımdaki hareket sahnesine benzer. Ancak OnSwipe ile çalışabilmesi için OnSwipe bildirimi kaldırıldı.CoordinatorLayout

  1. Uygulamayı çalıştırın ve 8. adıma gidin. Metni kaydırdığınızda ayın hareket etmediğini görürsünüz.

2. adım: MotionLayout'un kaydırılmasını sağlama

  1. NestedScrollView kaydırılır kaydırılmaz MotionLayout görünümünün de kaydırılması için MotionLayout'ya motion:minHeight ve motion:layout_scrollFlags 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ıma gidin. Yukarı kaydırdığınızda MotionLayout simgesinin daraldığını görürsünüz. Ancak animasyon henüz kaydırma davranışına göre ilerlemiyor.

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

  1. Step8Activity.kt uygulamasını açın . Kaydırma konumundaki değişiklikleri MotionLayout'a 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ının geçerli kaydırma uzaklığıyla her kaydırma işleminde çağrılacak bir OnOffsetChangedListener kaydeder.

MotionLayout, ilerleme özelliğini ayarlayarak geçişi destekler. verticalOffset ile ilerleme yüzdesi arasında dönüşüm 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 simgesinin, kaydırma konumuna göre animasyonu ilerlettiğini görürsünüz.

ee5ce4d9e33a59ca.gif

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

12. Tebrikler

Bu kod laboratuvarında MotionLayout'nın temel API'si ele alınmıştır.

MotionLayout'nın uygulamadaki diğer örneklerini görmek için resmi örneğe göz atın. Ayrıca belgelere göz atmayı unutmayın.

Daha Fazla Bilgi

MotionLayout, bu kod laboratuvarında ele alınmayan daha da fazla özelliği destekler. Örneğin, KeyCycle, ile yolları veya özellikleri tekrarlayan döngülerle kontrol edebilir, KeyTimeCycle, ile de saat zamanına göre animasyon oluşturabilirsiniz. Her birinin örnekleri için numunelere göz atın.

Bu kurstaki diğer codelab'lerin bağlantıları için Kotlin'de İleri Düzey Android codelab'leri açılış sayfasına bakın.